/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 23664 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26