/[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 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 27326 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 dpavlin 4 /*
2     * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3     *
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     * $Id: dev_fb.c,v 1.90 2005/03/29 09:46:06 debug Exp $
29     *
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     * HPCmips framebuffer
36     * Playstation 2 (24-bit color)
37     * generic (any resolution, several bit depths possible)
38     *
39     *
40     * TODO: There is still a bug when redrawing the cursor. The underlying
41     * image is moved 1 pixel (?), or something like that.
42     *
43     * TODO: This should actually be independant of X11, but that
44     * might be too hard to do right now.
45     *
46     * TODO: playstation 2 pixels are stored in another format, actually
47     */
48    
49     #include <stdio.h>
50     #include <stdlib.h>
51     #include <string.h>
52    
53     #include "console.h"
54     #include "cpu.h"
55     #include "devices.h"
56     #include "machine.h"
57     #include "memory.h"
58     #include "misc.h"
59     #include "x11.h"
60    
61     #ifdef WITH_X11
62     #include <X11/Xlib.h>
63     #include <X11/Xos.h>
64     #include <X11/Xutil.h>
65     #endif
66    
67    
68     #define FB_TICK_SHIFT 18
69    
70     #define LOGO_XSIZE 256
71     #define LOGO_YSIZE 256
72     #define LOGO_BOTTOM_MARGIN 60
73     /* This must be a 256*256 pixels P4 ppm: */
74     #include "fb_logo.c"
75     unsigned char *fb_logo = fb_logo_ppm + 11;
76    
77    
78     /* #define FB_DEBUG */
79    
80     /*
81     * set_grayscale_palette():
82     *
83     * Fill d->rgb_palette with grayscale values. ncolors should
84     * be something like 2, 4, 16, or 256.
85     */
86     void set_grayscale_palette(struct vfb_data *d, int ncolors)
87     {
88     int i, gray;
89    
90     for (i=0; i<256; i++) {
91     gray = 255*i/(ncolors-1);
92     d->rgb_palette[i*3 + 0] = gray;
93     d->rgb_palette[i*3 + 1] = gray;
94     d->rgb_palette[i*3 + 2] = gray;
95     }
96     }
97    
98    
99     /*
100     * set_blackwhite_palette():
101     *
102     * Set color 0 = black, all others to white.
103     */
104     void set_blackwhite_palette(struct vfb_data *d, int ncolors)
105     {
106     int i, gray;
107    
108     for (i=0; i<256; i++) {
109     gray = i==0? 0 : 255;
110     d->rgb_palette[i*3 + 0] = gray;
111     d->rgb_palette[i*3 + 1] = gray;
112     d->rgb_palette[i*3 + 2] = gray;
113     }
114     }
115    
116    
117     /*
118     * dev_fb_setcursor():
119     */
120     void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
121     int cursor_xsize, int cursor_ysize)
122     {
123     if (cursor_x < 0)
124     cursor_x = 0;
125     if (cursor_y < 0)
126     cursor_y = 0;
127     if (cursor_x + cursor_xsize >= d->xsize)
128     cursor_x = d->xsize - cursor_xsize;
129     if (cursor_y + cursor_ysize >= d->ysize)
130     cursor_y = d->ysize - cursor_ysize;
131    
132     #ifdef WITH_X11
133     if (d->fb_window != NULL) {
134     d->fb_window->cursor_x = cursor_x;
135     d->fb_window->cursor_y = cursor_y;
136     d->fb_window->cursor_on = on;
137     d->fb_window->cursor_xsize = cursor_xsize;
138     d->fb_window->cursor_ysize = cursor_ysize;
139     }
140     #endif
141    
142     if (d->fb_window != NULL)
143     console_set_framebuffer_mouse(cursor_x, cursor_y,
144     d->fb_window->fb_number);
145    
146     /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
147     cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
148     }
149    
150    
151     /*
152     * framebuffer_blockcopyfill():
153     *
154     * This function should be used by devices that are capable of doing
155     * block copy/fill.
156     *
157     * If fillflag is non-zero, then fill_[rgb] should contain the color
158     * with which to fill.
159     *
160     * If fillflag is zero, copy mode is used, and from_[xy] should contain
161     * the offset on the framebuffer where we should copy from.
162     *
163     * NOTE: Overlapping copies are undefined!
164     */
165     void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
166     int fill_g, int fill_b, int x1, int y1, int x2, int y2,
167     int from_x, int from_y)
168     {
169     int y;
170     long from_ofs, dest_ofs, linelen;
171    
172     if (fillflag)
173     debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
174     "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
175     else
176     debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
177     "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
178    
179     /* Clip x: */
180     if (x1 < 0) x1 = 0;
181     if (x1 >= d->xsize) x1 = d->xsize-1;
182     if (x2 < 0) x2 = 0;
183     if (x2 >= d->xsize) x2 = d->xsize-1;
184    
185     dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
186     linelen = (x2-x1 + 1) * (d->bit_depth/8);
187     /* NOTE: linelen is nr of bytes, not pixels */
188    
189     if (fillflag) {
190     for (y=y1; y<=y2; y++) {
191     if (y>=0 && y<d->ysize) {
192     int x;
193     char buf[8192 * 3];
194     if (d->bit_depth == 24)
195     for (x=0; x<linelen; x+=3) {
196     buf[x] = fill_r;
197     buf[x+1] = fill_g;
198     buf[x+2] = fill_b;
199     }
200     else
201     printf("TODO: fill for non-24-bit"
202     " modes\n");
203    
204     memmove(d->framebuffer + dest_ofs, buf,
205     linelen);
206     }
207    
208     dest_ofs += d->bytes_per_line;
209     }
210     } else {
211     from_ofs = d->bytes_per_line * from_y +
212     (d->bit_depth/8) * from_x;
213    
214     for (y=y1; y<=y2; y++) {
215     if (y>=0 && y<d->ysize)
216     memmove(d->framebuffer + dest_ofs,
217     d->framebuffer + from_ofs, linelen);
218    
219     from_ofs += d->bytes_per_line;
220     dest_ofs += d->bytes_per_line;
221     }
222     }
223    
224     if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
225     if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
226     if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
227     if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
228    
229     if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
230     if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
231     if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
232     if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
233     }
234    
235    
236     #ifdef WITH_X11
237     #define macro_put_pixel() { \
238     /* Combine the color into an X11 long and display it: */ \
239     /* TODO: construct color in a more portable way: */ \
240     switch (d->fb_window->x11_screen_depth) { \
241     case 24: \
242     if (d->fb_window->fb_ximage->byte_order) \
243     color = (b << 16) + (g << 8) + r; \
244     else \
245     color = (r << 16) + (g << 8) + b; \
246     break; \
247     case 16: \
248     r >>= 3; g >>= 2; b >>= 3; \
249     if (d->fb_window->fb_ximage->byte_order) { \
250     /* Big endian 16-bit X server: */ \
251     static int first = 1; \
252     if (first) { \
253     fprintf(stderr, "\n*** Please report to the author whether 16-bit X11 colors are rendered correctly or not!\n\n"); \
254     first = 0; \
255     } \
256     color = (b << 11) + (g << 5) + r; \
257     } else { \
258     /* Little endian (eg PC) X servers: */ \
259     color = (r << 11) + (g << 5) + b; \
260     } \
261     break; \
262     case 15: \
263     r >>= 3; g >>= 3; b >>= 3; \
264     if (d->fb_window->fb_ximage->byte_order) { \
265     /* Big endian 15-bit X server: */ \
266     static int first = 1; \
267     if (first) { \
268     fprintf(stderr, "\n*** Please report to the author whether 15-bit X11 colors are rendered correctly or not!\n\n"); \
269     first = 0; \
270     } \
271     color = (b << 10) + (g << 5) + r; \
272     } else { \
273     /* Little endian (eg PC) X servers: */ \
274     color = (r << 10) + (g << 5) + b; \
275     } \
276     break; \
277     default: \
278     color = d->fb_window->x11_graycolor[15 * (r + g + b) / (255 * 3)].pixel; \
279     } \
280     if (x>=0 && x<d->x11_xsize && y>=0 && y<d->x11_ysize) \
281     XPutPixel(d->fb_window->fb_ximage, x, y, color); \
282     }
283     #else
284     /* If not WITH_X11: */
285     #define macro_put_pixel() { }
286     #endif
287    
288    
289     /*
290     * update_framebuffer():
291     *
292     * The framebuffer memory has been updated. This function tries to make
293     * sure that the XImage is also updated (1 or more pixels).
294     */
295     void update_framebuffer(struct vfb_data *d, int addr, int len)
296     {
297     int x, y, pixel, npixels;
298     long color_r, color_g, color_b;
299     #ifdef WITH_X11
300     long color;
301     #endif
302     int scaledown = d->vfb_scaledown;
303     int scaledownXscaledown = 1;
304    
305     if (scaledown == 1) {
306     /* Which framebuffer pixel does addr correspond to? */
307     pixel = addr * 8 / d->bit_depth;
308     y = pixel / d->xsize;
309     x = pixel % d->xsize;
310    
311     /* How many framebuffer pixels? */
312     npixels = len * 8 / d->bit_depth;
313     if (npixels == 0)
314     npixels = 1;
315    
316     if (d->bit_depth < 8) {
317     for (pixel=0; pixel<npixels; pixel++) {
318     int fb_addr, c, r, g, b;
319     color_r = color_g = color_b = 0;
320    
321     fb_addr = (y * d->xsize + x) * d->bit_depth;
322     /* fb_addr is now which _bit_ in
323     the framebuffer */
324    
325     c = d->framebuffer[fb_addr >> 3];
326     fb_addr &= 7;
327    
328     /* HPCmips is reverse: */
329     if (d->vfb_type == VFB_HPCMIPS)
330     fb_addr = 8 - d->bit_depth - fb_addr;
331    
332     c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
333     /* c <<= (8 - d->bit_depth); */
334    
335     r = d->rgb_palette[c*3 + 0];
336     g = d->rgb_palette[c*3 + 1];
337     b = d->rgb_palette[c*3 + 2];
338    
339     macro_put_pixel();
340     x++;
341     }
342     } else if (d->bit_depth == 8) {
343     for (pixel=0; pixel<npixels; pixel++) {
344     int fb_addr, c, r, g, b;
345     color_r = color_g = color_b = 0;
346    
347     fb_addr = y * d->xsize + x;
348     /* fb_addr is now which byte in framebuffer */
349     c = d->framebuffer[fb_addr];
350     r = d->rgb_palette[c*3 + 0];
351     g = d->rgb_palette[c*3 + 1];
352     b = d->rgb_palette[c*3 + 2];
353    
354     macro_put_pixel();
355     x++;
356     }
357     } else { /* d->bit_depth > 8 */
358     for (pixel=0; pixel<npixels; pixel++) {
359     int fb_addr, r, g, b;
360     color_r = color_g = color_b = 0;
361    
362     fb_addr = (y * d->xsize + x) * d->bit_depth;
363     /* fb_addr is now which byte in framebuffer */
364    
365     /* > 8 bits color. */
366     fb_addr >>= 3;
367     switch (d->bit_depth) {
368     case 24:
369     r = d->framebuffer[fb_addr];
370     g = d->framebuffer[fb_addr + 1];
371     b = d->framebuffer[fb_addr + 2];
372     break;
373     /* TODO: copy to the scaledown code below */
374     case 16:
375     if (d->vfb_type == VFB_HPCMIPS) {
376     b = d->framebuffer[fb_addr] +
377     (d->framebuffer[fb_addr+1] << 8);
378    
379     if (d->color32k) {
380     r = b >> 11;
381     g = b >> 5;
382     r = r & 31;
383     g = (g & 31) * 2;
384     b = b & 31;
385     } else {
386     r = (b >> 11) & 0x1f;
387     g = (b >> 5) & 0x3f;
388     b = b & 0x1f;
389     }
390     } else {
391     r = d->framebuffer[fb_addr] >> 3;
392     g = (d->framebuffer[fb_addr] << 5) +
393     (d->framebuffer[fb_addr + 1] >> 5);
394     b = d->framebuffer[fb_addr + 1] & 0x1f;
395     }
396    
397     r *= 8;
398     g *= 4;
399     b *= 8;
400     break;
401     default:
402     r = g = b = random() & 255;
403     }
404    
405     macro_put_pixel();
406     x++;
407     }
408     }
409    
410     return;
411     }
412    
413     /* scaledown != 1: */
414    
415     scaledown = d->vfb_scaledown;
416     scaledownXscaledown = scaledown * scaledown;
417    
418     /* Which framebuffer pixel does addr correspond to? */
419     pixel = addr * 8 / d->bit_depth;
420     y = pixel / d->xsize;
421     x = pixel % d->xsize;
422    
423     /* How many framebuffer pixels? */
424     npixels = len * 8 / d->bit_depth;
425    
426     /* Which x11 pixel? */
427     x /= scaledown;
428     y /= scaledown;
429    
430     /* How many x11 pixels: */
431     npixels /= scaledown;
432     if (npixels == 0)
433     npixels = 1;
434    
435     if (d->bit_depth < 8) {
436     for (pixel=0; pixel<npixels; pixel++) {
437     int subx, suby, r, g, b;
438     color_r = color_g = color_b = 0;
439     for (suby=0; suby<scaledown; suby++)
440     for (subx=0; subx<scaledown; subx++) {
441     int fb_x, fb_y, fb_addr, c;
442    
443     fb_x = x * scaledown + subx;
444     fb_y = y * scaledown + suby;
445     fb_addr = fb_y * d->xsize + fb_x;
446     fb_addr = fb_addr * d->bit_depth;
447     /* fb_addr is now which _bit_ in
448     the framebuffer */
449    
450     c = d->framebuffer[fb_addr >> 3];
451     fb_addr &= 7;
452    
453     /* HPCmips is reverse: */
454     if (d->vfb_type == VFB_HPCMIPS)
455     fb_addr = 8 - d->bit_depth - fb_addr;
456    
457     c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
458     /* c <<= (8 - d->bit_depth); */
459    
460     r = d->rgb_palette[c*3 + 0];
461     g = d->rgb_palette[c*3 + 1];
462     b = d->rgb_palette[c*3 + 2];
463    
464     color_r += r;
465     color_g += g;
466     color_b += b;
467     }
468    
469     r = color_r / scaledownXscaledown;
470     g = color_g / scaledownXscaledown;
471     b = color_b / scaledownXscaledown;
472     macro_put_pixel();
473     x++;
474     }
475     } else if (d->bit_depth == 8) {
476     for (pixel=0; pixel<npixels; pixel++) {
477     int subx, suby, r, g, b;
478     color_r = color_g = color_b = 0;
479     for (suby=0; suby<scaledown; suby++)
480     for (subx=0; subx<scaledown; subx++) {
481     int fb_x, fb_y, fb_addr, c;
482    
483     fb_x = x * scaledown + subx;
484     fb_y = y * scaledown + suby;
485     fb_addr = fb_y * d->xsize + fb_x;
486     /* fb_addr is which _byte_ in framebuffer */
487     c = d->framebuffer[fb_addr] * 3;
488     r = d->rgb_palette[c + 0];
489     g = d->rgb_palette[c + 1];
490     b = d->rgb_palette[c + 2];
491     color_r += r;
492     color_g += g;
493     color_b += b;
494     }
495    
496     r = color_r / scaledownXscaledown;
497     g = color_g / scaledownXscaledown;
498     b = color_b / scaledownXscaledown;
499     macro_put_pixel();
500     x++;
501     }
502     } else {
503     /* Generic > 8 bit bit-depth: */
504     for (pixel=0; pixel<npixels; pixel++) {
505     int subx, suby, r, g, b;
506     color_r = color_g = color_b = 0;
507     for (suby=0; suby<scaledown; suby++)
508     for (subx=0; subx<scaledown; subx++) {
509     int fb_x, fb_y, fb_addr;
510    
511     fb_x = x * scaledown + subx;
512     fb_y = y * scaledown + suby;
513     fb_addr = fb_y * d->xsize + fb_x;
514     fb_addr = (fb_addr * d->bit_depth) >> 3;
515     /* fb_addr is which _byte_ in framebuffer */
516    
517     /* > 8 bits color. */
518     switch (d->bit_depth) {
519     case 24:
520     r = d->framebuffer[fb_addr];
521     g = d->framebuffer[fb_addr + 1];
522     b = d->framebuffer[fb_addr + 2];
523     break;
524     default:
525     r = g = b = random() & 255;
526     }
527     color_r += r;
528     color_g += g;
529     color_b += b;
530     }
531     r = color_r / scaledownXscaledown;
532     g = color_g / scaledownXscaledown;
533     b = color_b / scaledownXscaledown;
534     macro_put_pixel();
535     x++;
536     }
537     }
538     }
539    
540    
541     /*
542     * dev_fb_tick():
543     *
544     */
545     void dev_fb_tick(struct cpu *cpu, void *extra)
546     {
547     struct vfb_data *d = extra;
548     #ifdef WITH_X11
549     int need_to_flush_x11 = 0;
550     int need_to_redraw_cursor = 0;
551     #endif
552    
553     if (!cpu->machine->use_x11)
554     return;
555    
556     #ifdef BINTRANS
557     do {
558     uint64_t low = -1, high;
559     int x, y;
560    
561     memory_device_bintrans_access(cpu, cpu->mem,
562     extra, &low, &high);
563     if ((int64_t)low == -1)
564     break;
565    
566     /* printf("low=%016llx high=%016llx\n",
567     (long long)low, (long long)high); */
568    
569     x = (low % d->bytes_per_line) * 8 / d->bit_depth;
570     y = low / d->bytes_per_line;
571     if (x < d->update_x1 || d->update_x1 == -1)
572     d->update_x1 = x;
573     if (x > d->update_x2 || d->update_x2 == -1)
574     d->update_x2 = x;
575     if (y < d->update_y1 || d->update_y1 == -1)
576     d->update_y1 = y;
577     if (y > d->update_y2 || d->update_y2 == -1)
578     d->update_y2 = y;
579    
580     x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
581     y = (low+7) / d->bytes_per_line;
582     if (x < d->update_x1 || d->update_x1 == -1)
583     d->update_x1 = x;
584     if (x > d->update_x2 || d->update_x2 == -1)
585     d->update_x2 = x;
586     if (y < d->update_y1 || d->update_y1 == -1)
587     d->update_y1 = y;
588     if (y > d->update_y2 || d->update_y2 == -1)
589     d->update_y2 = y;
590    
591     x = (high % d->bytes_per_line) * 8 / d->bit_depth;
592     y = high / d->bytes_per_line;
593     if (x < d->update_x1 || d->update_x1 == -1)
594     d->update_x1 = x;
595     if (x > d->update_x2 || d->update_x2 == -1)
596     d->update_x2 = x;
597     if (y < d->update_y1 || d->update_y1 == -1)
598     d->update_y1 = y;
599     if (y > d->update_y2 || d->update_y2 == -1)
600     d->update_y2 = y;
601    
602     x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
603     y = (high+7) / d->bytes_per_line;
604     if (x < d->update_x1 || d->update_x1 == -1)
605     d->update_x1 = x;
606     if (x > d->update_x2 || d->update_x2 == -1)
607     d->update_x2 = x;
608     if (y < d->update_y1 || d->update_y1 == -1)
609     d->update_y1 = y;
610     if (y > d->update_y2 || d->update_y2 == -1)
611     d->update_y2 = y;
612    
613     /*
614     * An update covering more than one line will automatically
615     * force an update of all the affected lines:
616     */
617     if (d->update_y1 != d->update_y2) {
618     d->update_x1 = 0;
619     d->update_x2 = d->xsize-1;
620     }
621     } while (0);
622     #endif
623    
624     #ifdef WITH_X11
625     /* Do we need to redraw the cursor? */
626     if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
627     d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
628     d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
629     d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
630     d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
631     need_to_redraw_cursor = 1;
632    
633     if (d->update_x2 != -1) {
634     if ( (d->update_x1 >= d->fb_window->OLD_cursor_x &&
635     d->update_x1 < (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ||
636     (d->update_x2 >= d->fb_window->OLD_cursor_x &&
637     d->update_x2 < (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ||
638     (d->update_x1 < d->fb_window->OLD_cursor_x &&
639     d->update_x2 >= (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ) {
640     if ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
641     d->update_y1 < (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) ||
642     (d->update_y2 >= d->fb_window->OLD_cursor_y &&
643     d->update_y2 < (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) ||
644     (d->update_y1 < d->fb_window->OLD_cursor_y &&
645     d->update_y2 >= (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) )
646     need_to_redraw_cursor = 1;
647     }
648     }
649    
650     if (need_to_redraw_cursor) {
651     /* Remove old cursor, if any: */
652     if (d->fb_window->OLD_cursor_on) {
653     XPutImage(d->fb_window->x11_display,
654     d->fb_window->x11_fb_window,
655     d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
656     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
657     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
658     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
659     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
660     d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
661     d->fb_window->OLD_cursor_ysize/d->vfb_scaledown + 1);
662     }
663     }
664     #endif
665    
666     if (d->update_x2 != -1) {
667     int y, addr, addr2, q = d->vfb_scaledown;
668    
669     if (d->update_x1 >= d->visible_xsize) d->update_x1 = d->visible_xsize - 1;
670     if (d->update_x2 >= d->visible_xsize) d->update_x2 = d->visible_xsize - 1;
671     if (d->update_y1 >= d->visible_ysize) d->update_y1 = d->visible_ysize - 1;
672     if (d->update_y2 >= d->visible_ysize) d->update_y2 = d->visible_ysize - 1;
673    
674     /* Without these, we might miss the right most / bottom pixel: */
675     d->update_x2 += (q - 1);
676     d->update_y2 += (q - 1);
677    
678     d->update_x1 = d->update_x1 / q * q;
679     d->update_x2 = d->update_x2 / q * q;
680     d->update_y1 = d->update_y1 / q * q;
681     d->update_y2 = d->update_y2 / q * q;
682    
683     addr = d->update_y1 * d->bytes_per_line + d->update_x1 * d->bit_depth / 8;
684     addr2 = d->update_y1 * d->bytes_per_line + d->update_x2 * d->bit_depth / 8;
685    
686     for (y=d->update_y1; y<=d->update_y2; y+=q) {
687     update_framebuffer(d, addr, addr2 - addr);
688     addr += d->bytes_per_line * q;
689     addr2 += d->bytes_per_line * q;
690     }
691    
692     #ifdef WITH_X11
693     XPutImage(d->fb_window->x11_display, d->fb_window->x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
694     d->update_x1/d->vfb_scaledown, d->update_y1/d->vfb_scaledown,
695     d->update_x1/d->vfb_scaledown, d->update_y1/d->vfb_scaledown,
696     (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
697     (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
698    
699     need_to_flush_x11 = 1;
700     #endif
701    
702     d->update_x1 = d->update_y1 = 99999;
703     d->update_x2 = d->update_y2 = -1;
704     }
705    
706     #ifdef WITH_X11
707     if (need_to_redraw_cursor) {
708     /* Paint new cursor: */
709     if (d->fb_window->cursor_on) {
710     x11_redraw_cursor(cpu->machine, d->fb_window->fb_number);
711     d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
712     d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
713     d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
714     d->fb_window->OLD_cursor_xsize = d->fb_window->cursor_xsize;
715     d->fb_window->OLD_cursor_ysize = d->fb_window->cursor_ysize;
716     }
717     }
718     #endif
719    
720     #ifdef WITH_X11
721     if (need_to_flush_x11)
722     XFlush(d->fb_window->x11_display);
723     #endif
724     }
725    
726    
727     /*
728     * dev_fb_access():
729     */
730     int dev_fb_access(struct cpu *cpu, struct memory *mem,
731     uint64_t relative_addr, unsigned char *data, size_t len,
732     int writeflag, void *extra)
733     {
734     struct vfb_data *d = extra;
735     int i;
736    
737     #ifdef FB_DEBUG
738     if (writeflag == MEM_WRITE) { if (data[0]) {
739     fatal("[ dev_fb: write to addr=%08lx, data = ",
740     (long)relative_addr);
741     for (i=0; i<len; i++)
742     fatal("%02x ", data[i]);
743     fatal("]\n");
744     } else {
745     fatal("[ dev_fb: read from addr=%08lx, data = ",
746     (long)relative_addr);
747     for (i=0; i<len; i++)
748     fatal("%02x ", d->framebuffer[relative_addr + i]);
749     fatal("]\n");
750     }
751     #endif
752    
753     /* See if a write actually modifies the framebuffer contents: */
754     if (writeflag == MEM_WRITE) {
755     for (i=0; i<len; i++) {
756     if (data[i] != d->framebuffer[relative_addr + i])
757     break;
758    
759     /* If all bytes are equal to what is already stored
760     in the framebuffer, then simply return: */
761     if (i==len-1)
762     return 1;
763     }
764     }
765    
766     /*
767     * If the framebuffer is modified, then we should keep a track
768     * of which area(s) we modify, so that the display isn't updated
769     * unnecessarily.
770     */
771     if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
772     int x, y, x2,y2;
773    
774     x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
775     y = relative_addr / d->bytes_per_line;
776     x2 = ((relative_addr + len) % d->bytes_per_line)
777     * 8 / d->bit_depth;
778     y2 = (relative_addr + len) / d->bytes_per_line;
779    
780     if (x < d->update_x1 || d->update_x1 == -1)
781     d->update_x1 = x;
782     if (x > d->update_x2 || d->update_x2 == -1)
783     d->update_x2 = x;
784    
785     if (y < d->update_y1 || d->update_y1 == -1)
786     d->update_y1 = y;
787     if (y > d->update_y2 || d->update_y2 == -1)
788     d->update_y2 = y;
789    
790     if (x2 < d->update_x1 || d->update_x1 == -1)
791     d->update_x1 = x2;
792     if (x2 > d->update_x2 || d->update_x2 == -1)
793     d->update_x2 = x2;
794    
795     if (y2 < d->update_y1 || d->update_y1 == -1)
796     d->update_y1 = y2;
797     if (y2 > d->update_y2 || d->update_y2 == -1)
798     d->update_y2 = y2;
799    
800     /*
801     * An update covering more than one line will automatically
802     * force an update of all the affected lines:
803     */
804     if (y != y2) {
805     d->update_x1 = 0;
806     d->update_x2 = d->xsize-1;
807     }
808     }
809    
810     /*
811     * Read from/write to the framebuffer:
812     * (TODO: take the color_plane_mask into account)
813     *
814     * Calling memcpy() is probably overkill, as it usually is just one
815     * or a few bytes that are read/written at a time.
816     */
817     if (writeflag == MEM_WRITE) {
818     if (len > 8)
819     memcpy(d->framebuffer + relative_addr, data, len);
820     else
821     for (i=0; i<len; i++)
822     d->framebuffer[relative_addr + i] = data[i];
823     } else {
824     if (len > 8)
825     memcpy(data, d->framebuffer + relative_addr, len);
826     else
827     for (i=0; i<len; i++)
828     data[i] = d->framebuffer[relative_addr + i];
829     }
830    
831     return 1;
832     }
833    
834    
835     /*
836     * dev_fb_init():
837     *
838     * xsize and ysize are ignored if vfb_type is VFB_DEC_VFB01 or 02.
839     */
840     struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
841     uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
842     int xsize, int ysize, int bit_depth, char *name, int logo)
843     {
844     struct vfb_data *d;
845     size_t size;
846     int x, y;
847     char title[400];
848     char *name2;
849     int flags;
850    
851     d = malloc(sizeof(struct vfb_data));
852     if (d == NULL) {
853     fprintf(stderr, "out of memory\n");
854     exit(1);
855     }
856     memset(d, 0, sizeof(struct vfb_data));
857    
858     d->vfb_type = vfb_type;
859    
860     /* Defaults: */
861     d->xsize = xsize; d->visible_xsize = visible_xsize;
862     d->ysize = ysize; d->visible_ysize = visible_ysize;
863    
864     d->bit_depth = bit_depth;
865    
866     if (bit_depth == 15) {
867     d->color32k = 1;
868     bit_depth = d->bit_depth = 16;
869     }
870    
871     /* Specific types: */
872     switch (vfb_type) {
873     case VFB_DEC_VFB01:
874     /* DECstation VFB01 (monochrome) */
875     d->xsize = 2048; d->visible_xsize = 1024;
876     d->ysize = 1024; d->visible_ysize = 864;
877     d->bit_depth = 1;
878     break;
879     case VFB_DEC_VFB02:
880     /* DECstation VFB02 (color) */
881     d->xsize = 1024; d->visible_xsize = 1024;
882     d->ysize = 1024; d->visible_ysize = 864;
883     d->bit_depth = 8;
884     break;
885     case VFB_DEC_MAXINE:
886     /* DECstation Maxine (1024x768x8) */
887     d->xsize = 1024; d->visible_xsize = d->xsize;
888     d->ysize = 768; d->visible_ysize = d->ysize;
889     d->bit_depth = 8;
890     break;
891     case VFB_PLAYSTATION2:
892     /* Playstation 2 */
893     d->xsize = xsize; d->visible_xsize = d->xsize;
894     d->ysize = ysize; d->visible_ysize = d->ysize;
895     d->bit_depth = 24;
896     break;
897     default:
898     ;
899     }
900    
901     if (d->bit_depth == 2 || d->bit_depth == 4)
902     set_grayscale_palette(d, 1 << d->bit_depth);
903     else if (d->bit_depth == 8 || d->bit_depth == 1)
904     set_blackwhite_palette(d, 1 << d->bit_depth);
905    
906     d->vfb_scaledown = machine->x11_scaledown;
907    
908     d->bytes_per_line = d->xsize * d->bit_depth / 8;
909     size = d->ysize * d->bytes_per_line;
910    
911     d->framebuffer = malloc(size);
912     if (d->framebuffer == NULL) {
913     fprintf(stderr, "out of memory\n");
914     exit(1);
915     }
916    
917     /* Clear the framebuffer (all black pixels): */
918     d->framebuffer_size = size;
919     memset(d->framebuffer, 0, size);
920    
921     d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
922     d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
923    
924     d->update_x1 = d->update_y1 = 99999;
925     d->update_x2 = d->update_y2 = -1;
926    
927    
928     /* A nice bootup logo: */
929     if (logo) {
930     int logo_bottom_margin = LOGO_BOTTOM_MARGIN;
931    
932     d->update_x1 = 0;
933     d->update_x2 = LOGO_XSIZE-1;
934     d->update_y1 = d->visible_ysize-LOGO_YSIZE-logo_bottom_margin;
935     d->update_y2 = d->visible_ysize-logo_bottom_margin;
936     for (y=0; y<LOGO_YSIZE; y++)
937     for (x=0; x<LOGO_XSIZE; x++) {
938     int s, a = ((y + d->visible_ysize - LOGO_YSIZE
939     - logo_bottom_margin)*d->xsize + x)
940     * d->bit_depth / 8;
941     int b = fb_logo[(y*LOGO_XSIZE+x) / 8] &
942     (128 >> (x&7));
943     for (s=0; s<d->bit_depth / 8; s++)
944     d->framebuffer[a+s] = b? 0 : 255;
945     }
946     }
947    
948     snprintf(title, sizeof(title), "GXemul: %ix%ix%i %s framebuffer",
949     d->visible_xsize, d->visible_ysize, d->bit_depth, name);
950     title[sizeof(title)-1] = '\0';
951    
952     #ifdef WITH_X11
953     if (machine->use_x11)
954     d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
955     title, machine->x11_scaledown, machine);
956     else
957     #endif
958     d->fb_window = NULL;
959    
960     name2 = malloc(strlen(name) + 10);
961     if (name2 == NULL) {
962     fprintf(stderr, "out of memory in dev_fb_init()\n");
963     exit(1);
964     }
965     sprintf(name2, "fb [%s]", name);
966    
967     flags = MEM_DEFAULT;
968     if ((baseaddr & 0xfff) == 0)
969     flags = MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK;
970    
971     memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
972     d, flags, d->framebuffer);
973    
974     machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT);
975     return d;
976     }
977    

  ViewVC Help
Powered by ViewVC 1.1.26