/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 29548 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

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

  ViewVC Help
Powered by ViewVC 1.1.26