/[gxemul]/trunk/src/devices/dev_fb.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/devices/dev_fb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24281 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


1 dpavlin 4 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 4 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 30 * $Id: dev_fb.c,v 1.123 2006/07/24 08:08:39 debug Exp $
29 dpavlin 4 *
30     * Generic framebuffer device.
31     *
32     * DECstation VFB01 monochrome framebuffer, 1024x864
33     * DECstation VFB02 8-bit color framebuffer, 1024x864
34     * DECstation Maxine, 1024x768 8-bit color
35 dpavlin 18 * HPC (mips, arm, ..) framebuffer
36 dpavlin 4 * Playstation 2 (24-bit color)
37 dpavlin 28 * Generic (any resolution, several bit depths possible, useful for
38     * testmachines)
39 dpavlin 4 *
40     *
41 dpavlin 22 * TODO: This should actually be independent of X11, but that
42 dpavlin 4 * might be too hard to do right now.
43     *
44     * TODO: playstation 2 pixels are stored in another format, actually
45     */
46    
47     #include <stdio.h>
48     #include <stdlib.h>
49     #include <string.h>
50    
51     #include "console.h"
52     #include "cpu.h"
53     #include "devices.h"
54     #include "machine.h"
55     #include "memory.h"
56     #include "misc.h"
57     #include "x11.h"
58    
59     #ifdef WITH_X11
60     #include <X11/Xlib.h>
61     #include <X11/Xos.h>
62     #include <X11/Xutil.h>
63     #endif
64    
65    
66 dpavlin 28 #define FB_TICK_SHIFT 19
67 dpavlin 4
68    
69     /* #define FB_DEBUG */
70    
71     /*
72     * set_grayscale_palette():
73     *
74     * Fill d->rgb_palette with grayscale values. ncolors should
75     * be something like 2, 4, 16, or 256.
76     */
77     void set_grayscale_palette(struct vfb_data *d, int ncolors)
78     {
79     int i, gray;
80    
81     for (i=0; i<256; i++) {
82     gray = 255*i/(ncolors-1);
83     d->rgb_palette[i*3 + 0] = gray;
84     d->rgb_palette[i*3 + 1] = gray;
85     d->rgb_palette[i*3 + 2] = gray;
86     }
87     }
88    
89    
90     /*
91     * set_blackwhite_palette():
92     *
93     * Set color 0 = black, all others to white.
94     */
95     void set_blackwhite_palette(struct vfb_data *d, int ncolors)
96     {
97     int i, gray;
98    
99     for (i=0; i<256; i++) {
100     gray = i==0? 0 : 255;
101     d->rgb_palette[i*3 + 0] = gray;
102     d->rgb_palette[i*3 + 1] = gray;
103     d->rgb_palette[i*3 + 2] = gray;
104     }
105     }
106    
107    
108 dpavlin 28 static void set_title(struct vfb_data *d)
109     {
110     snprintf(d->title, sizeof(d->title),"GXemul: %ix%ix%i %s framebuffer",
111     d->visible_xsize, d->visible_ysize, d->bit_depth, d->name);
112     d->title[sizeof(d->title)-1] = '\0';
113     }
114    
115    
116 dpavlin 4 /*
117 dpavlin 6 * dev_fb_resize():
118     *
119     * Resize a framebuffer window. (This functionality is probably a bit buggy,
120     * because I didn't think of including it from the start.)
121 dpavlin 28 *
122     * SUPER-IMPORTANT: Anyone who resizes a framebuffer by calling this function
123     * must also clear all dyntrans address translations manually, in all cpus
124     * which might have access to the framebuffer!
125 dpavlin 6 */
126     void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
127     {
128     unsigned char *new_framebuffer;
129     int y, new_bytes_per_line;
130     size_t size;
131    
132     if (d == NULL) {
133     fatal("dev_fb_resize(): d == NULL\n");
134     return;
135     }
136    
137 dpavlin 28 if (new_xsize < 10 || new_ysize < 10) {
138     fatal("dev_fb_resize(): size too small.\n");
139     exit(1);
140     }
141    
142 dpavlin 6 new_bytes_per_line = new_xsize * d->bit_depth / 8;
143     size = new_ysize * new_bytes_per_line;
144    
145     new_framebuffer = malloc(size);
146     if (new_framebuffer == NULL) {
147     fprintf(stderr, "dev_fb_resize(): out of memory\n");
148     exit(1);
149     }
150    
151     /* Copy the old framebuffer to the new: */
152     if (d->framebuffer != NULL) {
153     for (y=0; y<new_ysize; y++) {
154     size_t fromofs = d->bytes_per_line * y;
155     size_t toofs = new_bytes_per_line * y;
156     size_t len_to_copy = d->bytes_per_line <
157     new_bytes_per_line? d->bytes_per_line
158     : new_bytes_per_line;
159     memset(new_framebuffer + toofs, 0, new_bytes_per_line);
160     if (y < d->x11_ysize)
161     memmove(new_framebuffer + toofs,
162     d->framebuffer + fromofs, len_to_copy);
163     }
164    
165     free(d->framebuffer);
166     }
167    
168     d->framebuffer = new_framebuffer;
169     d->framebuffer_size = size;
170    
171 dpavlin 22 if (new_xsize > d->xsize || new_ysize > d->ysize) {
172 dpavlin 6 d->update_x1 = d->update_y1 = 0;
173     d->update_x2 = new_xsize - 1;
174     d->update_y2 = new_ysize - 1;
175     }
176    
177     d->bytes_per_line = new_bytes_per_line;
178 dpavlin 22 d->xsize = d->visible_xsize = new_xsize;
179     d->ysize = d->visible_ysize = new_ysize;
180 dpavlin 6
181 dpavlin 22 d->x11_xsize = d->xsize / d->vfb_scaledown;
182     d->x11_ysize = d->ysize / d->vfb_scaledown;
183    
184 dpavlin 28 memory_device_update_data(d->memory, d, d->framebuffer);
185    
186     set_title(d);
187    
188 dpavlin 6 #ifdef WITH_X11
189 dpavlin 28 if (d->fb_window != NULL) {
190 dpavlin 6 x11_fb_resize(d->fb_window, new_xsize, new_ysize);
191 dpavlin 28 x11_set_standard_properties(d->fb_window, d->title);
192     }
193 dpavlin 6 #endif
194     }
195    
196    
197     /*
198 dpavlin 4 * dev_fb_setcursor():
199     */
200     void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
201     int cursor_xsize, int cursor_ysize)
202     {
203     if (cursor_x < 0)
204     cursor_x = 0;
205     if (cursor_y < 0)
206     cursor_y = 0;
207     if (cursor_x + cursor_xsize >= d->xsize)
208     cursor_x = d->xsize - cursor_xsize;
209     if (cursor_y + cursor_ysize >= d->ysize)
210     cursor_y = d->ysize - cursor_ysize;
211    
212     #ifdef WITH_X11
213     if (d->fb_window != NULL) {
214     d->fb_window->cursor_x = cursor_x;
215     d->fb_window->cursor_y = cursor_y;
216     d->fb_window->cursor_on = on;
217     d->fb_window->cursor_xsize = cursor_xsize;
218     d->fb_window->cursor_ysize = cursor_ysize;
219     }
220     #endif
221    
222     if (d->fb_window != NULL)
223     console_set_framebuffer_mouse(cursor_x, cursor_y,
224     d->fb_window->fb_number);
225    
226     /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
227     cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
228     }
229    
230    
231     /*
232     * framebuffer_blockcopyfill():
233     *
234     * This function should be used by devices that are capable of doing
235     * block copy/fill.
236     *
237     * If fillflag is non-zero, then fill_[rgb] should contain the color
238 dpavlin 30 * with which to fill. (In 8-bit mode, only fill_r is used.)
239 dpavlin 4 *
240     * If fillflag is zero, copy mode is used, and from_[xy] should contain
241     * the offset on the framebuffer where we should copy from.
242     *
243     * NOTE: Overlapping copies are undefined!
244     */
245     void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
246     int fill_g, int fill_b, int x1, int y1, int x2, int y2,
247     int from_x, int from_y)
248     {
249 dpavlin 30 int x, y;
250 dpavlin 4 long from_ofs, dest_ofs, linelen;
251    
252     if (fillflag)
253     debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
254     "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
255     else
256     debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
257     "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
258    
259     /* Clip x: */
260     if (x1 < 0) x1 = 0;
261     if (x1 >= d->xsize) x1 = d->xsize-1;
262     if (x2 < 0) x2 = 0;
263     if (x2 >= d->xsize) x2 = d->xsize-1;
264    
265     dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
266     linelen = (x2-x1 + 1) * (d->bit_depth/8);
267     /* NOTE: linelen is nr of bytes, not pixels */
268    
269     if (fillflag) {
270     for (y=y1; y<=y2; y++) {
271     if (y>=0 && y<d->ysize) {
272 dpavlin 30 unsigned char *buf =
273     d->framebuffer + dest_ofs;
274    
275     if (d->bit_depth == 24) {
276 dpavlin 22 for (x=0; x<linelen && x<sizeof(buf);
277     x += 3) {
278 dpavlin 4 buf[x] = fill_r;
279     buf[x+1] = fill_g;
280     buf[x+2] = fill_b;
281     }
282 dpavlin 30 } else if (d->bit_depth == 8) {
283     memset(buf, fill_r, linelen);
284     } else {
285     fatal("Unimplemented bit-depth (%i)"
286     " for fb fill\n", d->bit_depth);
287     exit(1);
288 dpavlin 22 }
289 dpavlin 4 }
290    
291     dest_ofs += d->bytes_per_line;
292     }
293     } else {
294     from_ofs = d->bytes_per_line * from_y +
295     (d->bit_depth/8) * from_x;
296     for (y=y1; y<=y2; y++) {
297 dpavlin 30 if (y >= 0 && y < d->ysize) {
298     if (from_y >= 0 && from_y < d->ysize)
299     memmove(d->framebuffer + dest_ofs,
300     d->framebuffer + from_ofs, linelen);
301     else
302     memset(d->framebuffer + dest_ofs,
303     0, linelen);
304     }
305     from_y ++;
306 dpavlin 4 from_ofs += d->bytes_per_line;
307     dest_ofs += d->bytes_per_line;
308     }
309     }
310    
311     if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
312     if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
313     if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
314     if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
315    
316     if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
317     if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
318     if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
319     if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
320     }
321    
322    
323     #ifdef WITH_X11
324    
325 dpavlin 22 #define REDRAW redraw_fallback
326     #include "fb_include.c"
327     #undef REDRAW
328 dpavlin 4
329 dpavlin 22 #define FB_24
330     #define REDRAW redraw_24
331     #include "fb_include.c"
332     #undef REDRAW
333     #undef FB_24
334     #define FB_16
335     #define REDRAW redraw_16
336     #include "fb_include.c"
337     #undef FB_16
338     #undef REDRAW
339     #define FB_15
340     #define REDRAW redraw_15
341     #include "fb_include.c"
342     #undef REDRAW
343     #undef FB_15
344 dpavlin 4
345 dpavlin 22 #define FB_BO
346     #define FB_24
347     #define REDRAW redraw_24_bo
348     #include "fb_include.c"
349     #undef REDRAW
350     #undef FB_24
351     #define FB_16
352     #define REDRAW redraw_16_bo
353     #include "fb_include.c"
354     #undef FB_16
355     #undef REDRAW
356     #define FB_15
357     #define REDRAW redraw_15_bo
358     #include "fb_include.c"
359     #undef REDRAW
360     #undef FB_15
361     #undef FB_BO
362 dpavlin 4
363 dpavlin 22 #define FB_SCALEDOWN
364 dpavlin 4
365 dpavlin 22 #define REDRAW redraw_fallback_sd
366     #include "fb_include.c"
367     #undef REDRAW
368 dpavlin 4
369 dpavlin 22 #define FB_24
370     #define REDRAW redraw_24_sd
371     #include "fb_include.c"
372     #undef REDRAW
373     #undef FB_24
374     #define FB_16
375     #define REDRAW redraw_16_sd
376     #include "fb_include.c"
377     #undef FB_16
378     #undef REDRAW
379     #define FB_15
380     #define REDRAW redraw_15_sd
381     #include "fb_include.c"
382     #undef REDRAW
383     #undef FB_15
384 dpavlin 4
385 dpavlin 22 #define FB_BO
386     #define FB_24
387     #define REDRAW redraw_24_bo_sd
388     #include "fb_include.c"
389     #undef REDRAW
390     #undef FB_24
391     #define FB_16
392     #define REDRAW redraw_16_bo_sd
393     #include "fb_include.c"
394     #undef FB_16
395     #undef REDRAW
396     #define FB_15
397     #define REDRAW redraw_15_bo_sd
398     #include "fb_include.c"
399     #undef REDRAW
400     #undef FB_15
401     #undef FB_BO
402 dpavlin 4
403 dpavlin 22 void (*redraw[2 * 4 * 2])(struct vfb_data *, int, int) = {
404     redraw_fallback, redraw_fallback,
405     redraw_15, redraw_15_bo,
406     redraw_16, redraw_16_bo,
407     redraw_24, redraw_24_bo,
408     redraw_fallback_sd, redraw_fallback_sd,
409     redraw_15_sd, redraw_15_bo_sd,
410     redraw_16_sd, redraw_16_bo_sd,
411     redraw_24_sd, redraw_24_bo_sd };
412 dpavlin 4
413 dpavlin 22 #endif /* WITH_X11 */
414 dpavlin 4
415    
416     /*
417     * dev_fb_tick():
418     *
419     */
420     void dev_fb_tick(struct cpu *cpu, void *extra)
421     {
422     struct vfb_data *d = extra;
423     #ifdef WITH_X11
424     int need_to_flush_x11 = 0;
425     int need_to_redraw_cursor = 0;
426     #endif
427    
428     if (!cpu->machine->use_x11)
429     return;
430    
431     do {
432 dpavlin 12 uint64_t high, low = (uint64_t)(int64_t) -1;
433 dpavlin 4 int x, y;
434    
435 dpavlin 12 memory_device_dyntrans_access(cpu, cpu->mem,
436 dpavlin 4 extra, &low, &high);
437     if ((int64_t)low == -1)
438     break;
439    
440     /* printf("low=%016llx high=%016llx\n",
441     (long long)low, (long long)high); */
442    
443     x = (low % d->bytes_per_line) * 8 / d->bit_depth;
444     y = low / d->bytes_per_line;
445     if (x < d->update_x1 || d->update_x1 == -1)
446     d->update_x1 = x;
447     if (x > d->update_x2 || d->update_x2 == -1)
448     d->update_x2 = x;
449     if (y < d->update_y1 || d->update_y1 == -1)
450     d->update_y1 = y;
451     if (y > d->update_y2 || d->update_y2 == -1)
452     d->update_y2 = y;
453    
454     x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
455     y = (low+7) / d->bytes_per_line;
456     if (x < d->update_x1 || d->update_x1 == -1)
457     d->update_x1 = x;
458     if (x > d->update_x2 || d->update_x2 == -1)
459     d->update_x2 = x;
460     if (y < d->update_y1 || d->update_y1 == -1)
461     d->update_y1 = y;
462     if (y > d->update_y2 || d->update_y2 == -1)
463     d->update_y2 = y;
464    
465     x = (high % d->bytes_per_line) * 8 / d->bit_depth;
466     y = high / d->bytes_per_line;
467     if (x < d->update_x1 || d->update_x1 == -1)
468     d->update_x1 = x;
469     if (x > d->update_x2 || d->update_x2 == -1)
470     d->update_x2 = x;
471     if (y < d->update_y1 || d->update_y1 == -1)
472     d->update_y1 = y;
473     if (y > d->update_y2 || d->update_y2 == -1)
474     d->update_y2 = y;
475    
476     x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
477     y = (high+7) / d->bytes_per_line;
478     if (x < d->update_x1 || d->update_x1 == -1)
479     d->update_x1 = x;
480     if (x > d->update_x2 || d->update_x2 == -1)
481     d->update_x2 = x;
482     if (y < d->update_y1 || d->update_y1 == -1)
483     d->update_y1 = y;
484     if (y > d->update_y2 || d->update_y2 == -1)
485     d->update_y2 = y;
486    
487     /*
488     * An update covering more than one line will automatically
489     * force an update of all the affected lines:
490     */
491     if (d->update_y1 != d->update_y2) {
492     d->update_x1 = 0;
493     d->update_x2 = d->xsize-1;
494     }
495     } while (0);
496    
497     #ifdef WITH_X11
498     /* Do we need to redraw the cursor? */
499     if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
500     d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
501     d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
502     d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
503     d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
504     need_to_redraw_cursor = 1;
505    
506     if (d->update_x2 != -1) {
507 dpavlin 14 if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
508     d->update_x1 < (d->fb_window->OLD_cursor_x +
509     d->fb_window->OLD_cursor_xsize)) ||
510 dpavlin 4 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
511 dpavlin 14 d->update_x2 < (d->fb_window->OLD_cursor_x +
512     d->fb_window->OLD_cursor_xsize)) ||
513 dpavlin 4 (d->update_x1 < d->fb_window->OLD_cursor_x &&
514 dpavlin 14 d->update_x2 >= (d->fb_window->OLD_cursor_x +
515     d->fb_window->OLD_cursor_xsize)) ) &&
516     ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
517     d->update_y1 < (d->fb_window->OLD_cursor_y +
518     d->fb_window->OLD_cursor_ysize)) ||
519     (d->update_y2 >= d->fb_window->OLD_cursor_y &&
520     d->update_y2 < (d->fb_window->OLD_cursor_y +
521     d->fb_window->OLD_cursor_ysize)) ||
522     (d->update_y1 < d->fb_window->OLD_cursor_y &&
523     d->update_y2 >= (d->fb_window->OLD_cursor_y +
524     d->fb_window->OLD_cursor_ysize)) ) )
525     need_to_redraw_cursor = 1;
526 dpavlin 4 }
527    
528     if (need_to_redraw_cursor) {
529     /* Remove old cursor, if any: */
530     if (d->fb_window->OLD_cursor_on) {
531     XPutImage(d->fb_window->x11_display,
532     d->fb_window->x11_fb_window,
533     d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
534     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
535     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
536     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
537     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
538     d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
539 dpavlin 14 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
540 dpavlin 4 }
541     }
542     #endif
543    
544     if (d->update_x2 != -1) {
545 dpavlin 24 #ifdef WITH_X11
546     int y;
547     #endif
548     int addr, addr2, q = d->vfb_scaledown;
549 dpavlin 4
550 dpavlin 14 if (d->update_x1 >= d->visible_xsize)
551     d->update_x1 = d->visible_xsize - 1;
552     if (d->update_x2 >= d->visible_xsize)
553     d->update_x2 = d->visible_xsize - 1;
554     if (d->update_y1 >= d->visible_ysize)
555     d->update_y1 = d->visible_ysize - 1;
556     if (d->update_y2 >= d->visible_ysize)
557     d->update_y2 = d->visible_ysize - 1;
558 dpavlin 4
559 dpavlin 14 /* Without these, we might miss the rightmost/bottom pixel: */
560 dpavlin 4 d->update_x2 += (q - 1);
561     d->update_y2 += (q - 1);
562    
563     d->update_x1 = d->update_x1 / q * q;
564     d->update_x2 = d->update_x2 / q * q;
565     d->update_y1 = d->update_y1 / q * q;
566     d->update_y2 = d->update_y2 / q * q;
567    
568 dpavlin 14 addr = d->update_y1 * d->bytes_per_line +
569     d->update_x1 * d->bit_depth / 8;
570     addr2 = d->update_y1 * d->bytes_per_line +
571     d->update_x2 * d->bit_depth / 8;
572 dpavlin 4
573 dpavlin 22 #ifdef WITH_X11
574 dpavlin 4 for (y=d->update_y1; y<=d->update_y2; y+=q) {
575 dpavlin 22 d->redraw_func(d, addr, addr2 - addr);
576 dpavlin 4 addr += d->bytes_per_line * q;
577     addr2 += d->bytes_per_line * q;
578     }
579    
580 dpavlin 14 XPutImage(d->fb_window->x11_display, d->fb_window->
581     x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
582     fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
583     d->vfb_scaledown, d->update_x1/d->vfb_scaledown,
584     d->update_y1/d->vfb_scaledown,
585 dpavlin 4 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
586     (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
587    
588     need_to_flush_x11 = 1;
589     #endif
590    
591     d->update_x1 = d->update_y1 = 99999;
592     d->update_x2 = d->update_y2 = -1;
593     }
594    
595     #ifdef WITH_X11
596     if (need_to_redraw_cursor) {
597     /* Paint new cursor: */
598     if (d->fb_window->cursor_on) {
599 dpavlin 14 x11_redraw_cursor(cpu->machine,
600     d->fb_window->fb_number);
601 dpavlin 4 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
602     d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
603     d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
604 dpavlin 14 d->fb_window->OLD_cursor_xsize = d->fb_window->
605     cursor_xsize;
606     d->fb_window->OLD_cursor_ysize = d->fb_window->
607     cursor_ysize;
608 dpavlin 22 need_to_flush_x11 = 1;
609 dpavlin 4 }
610     }
611     #endif
612    
613     #ifdef WITH_X11
614     if (need_to_flush_x11)
615     XFlush(d->fb_window->x11_display);
616     #endif
617     }
618    
619    
620     /*
621     * dev_fb_access():
622     */
623 dpavlin 22 DEVICE_ACCESS(fb)
624 dpavlin 4 {
625     struct vfb_data *d = extra;
626 dpavlin 22 size_t i;
627 dpavlin 4
628     #ifdef FB_DEBUG
629     if (writeflag == MEM_WRITE) { if (data[0]) {
630     fatal("[ dev_fb: write to addr=%08lx, data = ",
631     (long)relative_addr);
632     for (i=0; i<len; i++)
633     fatal("%02x ", data[i]);
634     fatal("]\n");
635     } else {
636     fatal("[ dev_fb: read from addr=%08lx, data = ",
637     (long)relative_addr);
638     for (i=0; i<len; i++)
639     fatal("%02x ", d->framebuffer[relative_addr + i]);
640     fatal("]\n");
641     }
642     #endif
643    
644 dpavlin 6 if (relative_addr >= d->framebuffer_size)
645     return 0;
646    
647 dpavlin 4 /* See if a write actually modifies the framebuffer contents: */
648     if (writeflag == MEM_WRITE) {
649     for (i=0; i<len; i++) {
650     if (data[i] != d->framebuffer[relative_addr + i])
651     break;
652    
653     /* If all bytes are equal to what is already stored
654     in the framebuffer, then simply return: */
655 dpavlin 22 if (i == len-1)
656 dpavlin 4 return 1;
657     }
658     }
659    
660     /*
661     * If the framebuffer is modified, then we should keep a track
662     * of which area(s) we modify, so that the display isn't updated
663     * unnecessarily.
664     */
665     if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
666     int x, y, x2,y2;
667    
668     x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
669     y = relative_addr / d->bytes_per_line;
670     x2 = ((relative_addr + len) % d->bytes_per_line)
671     * 8 / d->bit_depth;
672     y2 = (relative_addr + len) / d->bytes_per_line;
673    
674     if (x < d->update_x1 || d->update_x1 == -1)
675     d->update_x1 = x;
676     if (x > d->update_x2 || d->update_x2 == -1)
677     d->update_x2 = x;
678    
679     if (y < d->update_y1 || d->update_y1 == -1)
680     d->update_y1 = y;
681     if (y > d->update_y2 || d->update_y2 == -1)
682     d->update_y2 = y;
683    
684     if (x2 < d->update_x1 || d->update_x1 == -1)
685     d->update_x1 = x2;
686     if (x2 > d->update_x2 || d->update_x2 == -1)
687     d->update_x2 = x2;
688    
689     if (y2 < d->update_y1 || d->update_y1 == -1)
690     d->update_y1 = y2;
691     if (y2 > d->update_y2 || d->update_y2 == -1)
692     d->update_y2 = y2;
693    
694     /*
695     * An update covering more than one line will automatically
696     * force an update of all the affected lines:
697     */
698     if (y != y2) {
699     d->update_x1 = 0;
700     d->update_x2 = d->xsize-1;
701     }
702     }
703    
704     /*
705     * Read from/write to the framebuffer:
706     * (TODO: take the color_plane_mask into account)
707     *
708     * Calling memcpy() is probably overkill, as it usually is just one
709     * or a few bytes that are read/written at a time.
710     */
711     if (writeflag == MEM_WRITE) {
712     if (len > 8)
713     memcpy(d->framebuffer + relative_addr, data, len);
714 dpavlin 22 else {
715 dpavlin 4 for (i=0; i<len; i++)
716     d->framebuffer[relative_addr + i] = data[i];
717 dpavlin 22 }
718 dpavlin 4 } else {
719     if (len > 8)
720     memcpy(data, d->framebuffer + relative_addr, len);
721 dpavlin 22 else {
722 dpavlin 4 for (i=0; i<len; i++)
723     data[i] = d->framebuffer[relative_addr + i];
724 dpavlin 22 }
725 dpavlin 4 }
726    
727     return 1;
728     }
729    
730    
731     /*
732     * dev_fb_init():
733     *
734 dpavlin 10 * This function is big and ugly, but the point is to initialize a framebuffer
735     * device. :-)
736     *
737     * visible_xsize and visible_ysize are the sizes of the visible display area.
738     * xsize and ysize tell how much memory is actually allocated (for example
739     * visible_xsize could be 640, but xsize could be 1024, for better alignment).
740     *
741     * vfb_type is useful for selecting special features.
742     *
743     * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
744     *
745     * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
746     *
747 dpavlin 18 * If type is VFB_HPC, then color encoding differs from the generic case.
748 dpavlin 10 *
749     * If bit_depth = -15 (note the minus sign), then a special hack is used for
750     * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
751 dpavlin 4 */
752     struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
753     uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
754 dpavlin 12 int xsize, int ysize, int bit_depth, char *name)
755 dpavlin 4 {
756     struct vfb_data *d;
757 dpavlin 10 size_t size, nlen;
758 dpavlin 12 int flags;
759 dpavlin 22 int reverse_start = 0;
760 dpavlin 4 char *name2;
761    
762     d = malloc(sizeof(struct vfb_data));
763     if (d == NULL) {
764     fprintf(stderr, "out of memory\n");
765     exit(1);
766     }
767     memset(d, 0, sizeof(struct vfb_data));
768    
769 dpavlin 22 if (vfb_type & VFB_REVERSE_START) {
770     vfb_type &= ~VFB_REVERSE_START;
771     reverse_start = 1;
772     }
773    
774 dpavlin 28 d->memory = mem;
775 dpavlin 4 d->vfb_type = vfb_type;
776    
777     /* Defaults: */
778     d->xsize = xsize; d->visible_xsize = visible_xsize;
779     d->ysize = ysize; d->visible_ysize = visible_ysize;
780    
781     d->bit_depth = bit_depth;
782    
783     if (bit_depth == 15) {
784     d->color32k = 1;
785     bit_depth = d->bit_depth = 16;
786 dpavlin 10 } else if (bit_depth == -15) {
787     d->psp_15bit = 1;
788     bit_depth = d->bit_depth = 16;
789 dpavlin 4 }
790    
791     /* Specific types: */
792     switch (vfb_type) {
793     case VFB_DEC_VFB01:
794     /* DECstation VFB01 (monochrome) */
795     d->xsize = 2048; d->visible_xsize = 1024;
796     d->ysize = 1024; d->visible_ysize = 864;
797     d->bit_depth = 1;
798     break;
799     case VFB_DEC_VFB02:
800     /* DECstation VFB02 (color) */
801     d->xsize = 1024; d->visible_xsize = 1024;
802     d->ysize = 1024; d->visible_ysize = 864;
803     d->bit_depth = 8;
804     break;
805     case VFB_DEC_MAXINE:
806     /* DECstation Maxine (1024x768x8) */
807     d->xsize = 1024; d->visible_xsize = d->xsize;
808     d->ysize = 768; d->visible_ysize = d->ysize;
809     d->bit_depth = 8;
810     break;
811     case VFB_PLAYSTATION2:
812     /* Playstation 2 */
813     d->xsize = xsize; d->visible_xsize = d->xsize;
814     d->ysize = ysize; d->visible_ysize = d->ysize;
815     d->bit_depth = 24;
816     break;
817     }
818    
819     if (d->bit_depth == 2 || d->bit_depth == 4)
820     set_grayscale_palette(d, 1 << d->bit_depth);
821     else if (d->bit_depth == 8 || d->bit_depth == 1)
822     set_blackwhite_palette(d, 1 << d->bit_depth);
823    
824     d->vfb_scaledown = machine->x11_scaledown;
825    
826     d->bytes_per_line = d->xsize * d->bit_depth / 8;
827     size = d->ysize * d->bytes_per_line;
828    
829     d->framebuffer = malloc(size);
830     if (d->framebuffer == NULL) {
831     fprintf(stderr, "out of memory\n");
832     exit(1);
833     }
834    
835     /* Clear the framebuffer (all black pixels): */
836     d->framebuffer_size = size;
837 dpavlin 22 memset(d->framebuffer, reverse_start? 255 : 0, size);
838 dpavlin 4
839     d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
840     d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
841    
842 dpavlin 22 /* Only "update" from the start if we need to fill with white. */
843     /* (The Ximage will be black from the start anyway.) */
844     if (reverse_start) {
845     d->update_x1 = d->update_y1 = 0;
846     d->update_x2 = d->xsize - 1;
847     d->update_y2 = d->ysize - 1;
848     } else {
849     d->update_x1 = d->update_y1 = 99999;
850     d->update_x2 = d->update_y2 = -1;
851     }
852 dpavlin 4
853 dpavlin 28 d->name = strdup(name);
854     set_title(d);
855 dpavlin 4
856     #ifdef WITH_X11
857 dpavlin 22 if (machine->use_x11) {
858     int i = 0;
859 dpavlin 4 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
860 dpavlin 28 d->title, machine->x11_scaledown, machine);
861 dpavlin 22 switch (d->fb_window->x11_screen_depth) {
862     case 15: i = 2; break;
863     case 16: i = 4; break;
864     case 24: i = 6; break;
865     }
866     if (d->fb_window->fb_ximage->byte_order)
867     i ++;
868     if (d->vfb_scaledown > 1)
869     i += 8;
870     d->redraw_func = redraw[i];
871     } else
872 dpavlin 4 #endif
873     d->fb_window = NULL;
874    
875 dpavlin 10 nlen = strlen(name) + 10;
876     name2 = malloc(nlen);
877 dpavlin 4 if (name2 == NULL) {
878     fprintf(stderr, "out of memory in dev_fb_init()\n");
879     exit(1);
880     }
881 dpavlin 10 snprintf(name2, nlen, "fb [%s]", name);
882 dpavlin 4
883 dpavlin 20 flags = DM_DEFAULT;
884 dpavlin 4 if ((baseaddr & 0xfff) == 0)
885 dpavlin 20 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
886 dpavlin 4
887 dpavlin 20 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
888 dpavlin 6
889 dpavlin 4 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
890     d, flags, d->framebuffer);
891    
892 dpavlin 24 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT, 0.0);
893 dpavlin 4 return d;
894     }
895    

  ViewVC Help
Powered by ViewVC 1.1.26