/[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 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (13 years ago) by dpavlin
File MIME type: text/plain
File size: 29543 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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 20 * $Id: dev_fb.c,v 1.110 2005/11/13 00:14:08 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 20 #define FB_TICK_SHIFT 18
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 dpavlin 20 flags = DM_DEFAULT;
1060 dpavlin 4 if ((baseaddr & 0xfff) == 0)
1061 dpavlin 20 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
1062 dpavlin 4
1063 dpavlin 20 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
1064 dpavlin 6
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