/[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 6 - (hide annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 29268 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26