/[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 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 24036 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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 28 * $Id: dev_fb.c,v 1.121 2006/07/08 12:30: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 dpavlin 18 * HPC (mips, arm, ..) framebuffer
36 dpavlin 4 * Playstation 2 (24-bit color)
37 dpavlin 28 * Generic (any resolution, several bit depths possible, useful for
38     * testmachines)
39 dpavlin 4 *
40     *
41 dpavlin 22 * TODO: This should actually be independent of X11, but that
42 dpavlin 4 * might be too hard to do right now.
43     *
44     * TODO: playstation 2 pixels are stored in another format, actually
45     */
46    
47     #include <stdio.h>
48     #include <stdlib.h>
49     #include <string.h>
50    
51     #include "console.h"
52     #include "cpu.h"
53     #include "devices.h"
54     #include "machine.h"
55     #include "memory.h"
56     #include "misc.h"
57     #include "x11.h"
58    
59     #ifdef WITH_X11
60     #include <X11/Xlib.h>
61     #include <X11/Xos.h>
62     #include <X11/Xutil.h>
63     #endif
64    
65    
66 dpavlin 28 #define FB_TICK_SHIFT 19
67 dpavlin 4
68    
69     /* #define FB_DEBUG */
70    
71     /*
72     * set_grayscale_palette():
73     *
74     * Fill d->rgb_palette with grayscale values. ncolors should
75     * be something like 2, 4, 16, or 256.
76     */
77     void set_grayscale_palette(struct vfb_data *d, int ncolors)
78     {
79     int i, gray;
80    
81     for (i=0; i<256; i++) {
82     gray = 255*i/(ncolors-1);
83     d->rgb_palette[i*3 + 0] = gray;
84     d->rgb_palette[i*3 + 1] = gray;
85     d->rgb_palette[i*3 + 2] = gray;
86     }
87     }
88    
89    
90     /*
91     * set_blackwhite_palette():
92     *
93     * Set color 0 = black, all others to white.
94     */
95     void set_blackwhite_palette(struct vfb_data *d, int ncolors)
96     {
97     int i, gray;
98    
99     for (i=0; i<256; i++) {
100     gray = i==0? 0 : 255;
101     d->rgb_palette[i*3 + 0] = gray;
102     d->rgb_palette[i*3 + 1] = gray;
103     d->rgb_palette[i*3 + 2] = gray;
104     }
105     }
106    
107    
108 dpavlin 28 static void set_title(struct vfb_data *d)
109     {
110     snprintf(d->title, sizeof(d->title),"GXemul: %ix%ix%i %s framebuffer",
111     d->visible_xsize, d->visible_ysize, d->bit_depth, d->name);
112     d->title[sizeof(d->title)-1] = '\0';
113     }
114    
115    
116 dpavlin 4 /*
117 dpavlin 6 * dev_fb_resize():
118     *
119     * Resize a framebuffer window. (This functionality is probably a bit buggy,
120     * because I didn't think of including it from the start.)
121 dpavlin 28 *
122     * SUPER-IMPORTANT: Anyone who resizes a framebuffer by calling this function
123     * must also clear all dyntrans address translations manually, in all cpus
124     * which might have access to the framebuffer!
125 dpavlin 6 */
126     void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
127     {
128     unsigned char *new_framebuffer;
129     int y, new_bytes_per_line;
130     size_t size;
131    
132     if (d == NULL) {
133     fatal("dev_fb_resize(): d == NULL\n");
134     return;
135     }
136    
137 dpavlin 28 if (new_xsize < 10 || new_ysize < 10) {
138     fatal("dev_fb_resize(): size too small.\n");
139     exit(1);
140     }
141    
142 dpavlin 6 new_bytes_per_line = new_xsize * d->bit_depth / 8;
143     size = new_ysize * new_bytes_per_line;
144    
145     new_framebuffer = malloc(size);
146     if (new_framebuffer == NULL) {
147     fprintf(stderr, "dev_fb_resize(): out of memory\n");
148     exit(1);
149     }
150    
151     /* Copy the old framebuffer to the new: */
152     if (d->framebuffer != NULL) {
153     for (y=0; y<new_ysize; y++) {
154     size_t fromofs = d->bytes_per_line * y;
155     size_t toofs = new_bytes_per_line * y;
156     size_t len_to_copy = d->bytes_per_line <
157     new_bytes_per_line? d->bytes_per_line
158     : new_bytes_per_line;
159     memset(new_framebuffer + toofs, 0, new_bytes_per_line);
160     if (y < d->x11_ysize)
161     memmove(new_framebuffer + toofs,
162     d->framebuffer + fromofs, len_to_copy);
163     }
164    
165     free(d->framebuffer);
166     }
167    
168     d->framebuffer = new_framebuffer;
169     d->framebuffer_size = size;
170    
171 dpavlin 22 if (new_xsize > d->xsize || new_ysize > d->ysize) {
172 dpavlin 6 d->update_x1 = d->update_y1 = 0;
173     d->update_x2 = new_xsize - 1;
174     d->update_y2 = new_ysize - 1;
175     }
176    
177     d->bytes_per_line = new_bytes_per_line;
178 dpavlin 22 d->xsize = d->visible_xsize = new_xsize;
179     d->ysize = d->visible_ysize = new_ysize;
180 dpavlin 6
181 dpavlin 22 d->x11_xsize = d->xsize / d->vfb_scaledown;
182     d->x11_ysize = d->ysize / d->vfb_scaledown;
183    
184 dpavlin 28 memory_device_update_data(d->memory, d, d->framebuffer);
185    
186     set_title(d);
187    
188 dpavlin 6 #ifdef WITH_X11
189 dpavlin 28 if (d->fb_window != NULL) {
190 dpavlin 6 x11_fb_resize(d->fb_window, new_xsize, new_ysize);
191 dpavlin 28 x11_set_standard_properties(d->fb_window, d->title);
192     }
193 dpavlin 6 #endif
194     }
195    
196    
197     /*
198 dpavlin 4 * dev_fb_setcursor():
199     */
200     void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
201     int cursor_xsize, int cursor_ysize)
202     {
203     if (cursor_x < 0)
204     cursor_x = 0;
205     if (cursor_y < 0)
206     cursor_y = 0;
207     if (cursor_x + cursor_xsize >= d->xsize)
208     cursor_x = d->xsize - cursor_xsize;
209     if (cursor_y + cursor_ysize >= d->ysize)
210     cursor_y = d->ysize - cursor_ysize;
211    
212     #ifdef WITH_X11
213     if (d->fb_window != NULL) {
214     d->fb_window->cursor_x = cursor_x;
215     d->fb_window->cursor_y = cursor_y;
216     d->fb_window->cursor_on = on;
217     d->fb_window->cursor_xsize = cursor_xsize;
218     d->fb_window->cursor_ysize = cursor_ysize;
219     }
220     #endif
221    
222     if (d->fb_window != NULL)
223     console_set_framebuffer_mouse(cursor_x, cursor_y,
224     d->fb_window->fb_number);
225    
226     /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
227     cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
228     }
229    
230    
231     /*
232     * framebuffer_blockcopyfill():
233     *
234     * This function should be used by devices that are capable of doing
235     * block copy/fill.
236     *
237     * If fillflag is non-zero, then fill_[rgb] should contain the color
238     * with which to fill.
239     *
240     * If fillflag is zero, copy mode is used, and from_[xy] should contain
241     * the offset on the framebuffer where we should copy from.
242     *
243     * NOTE: Overlapping copies are undefined!
244     */
245     void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
246     int fill_g, int fill_b, int x1, int y1, int x2, int y2,
247     int from_x, int from_y)
248     {
249     int y;
250     long from_ofs, dest_ofs, linelen;
251    
252     if (fillflag)
253     debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
254     "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
255     else
256     debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
257     "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
258    
259     /* Clip x: */
260     if (x1 < 0) x1 = 0;
261     if (x1 >= d->xsize) x1 = d->xsize-1;
262     if (x2 < 0) x2 = 0;
263     if (x2 >= d->xsize) x2 = d->xsize-1;
264    
265     dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
266     linelen = (x2-x1 + 1) * (d->bit_depth/8);
267     /* NOTE: linelen is nr of bytes, not pixels */
268    
269     if (fillflag) {
270     for (y=y1; y<=y2; y++) {
271     if (y>=0 && y<d->ysize) {
272     int x;
273     char buf[8192 * 3];
274     if (d->bit_depth == 24)
275 dpavlin 22 for (x=0; x<linelen && x<sizeof(buf);
276     x += 3) {
277 dpavlin 4 buf[x] = fill_r;
278     buf[x+1] = fill_g;
279     buf[x+2] = fill_b;
280     }
281 dpavlin 22 else {
282     fatal("[ fb: TODO: fill for non-24-bit"
283     " modes ]\n");
284     }
285 dpavlin 4
286     memmove(d->framebuffer + dest_ofs, buf,
287     linelen);
288     }
289    
290     dest_ofs += d->bytes_per_line;
291     }
292     } else {
293     from_ofs = d->bytes_per_line * from_y +
294     (d->bit_depth/8) * from_x;
295    
296     for (y=y1; y<=y2; y++) {
297     if (y>=0 && y<d->ysize)
298     memmove(d->framebuffer + dest_ofs,
299     d->framebuffer + from_ofs, linelen);
300    
301     from_ofs += d->bytes_per_line;
302     dest_ofs += d->bytes_per_line;
303     }
304     }
305    
306     if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
307     if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
308     if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
309     if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
310    
311     if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
312     if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
313     if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
314     if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
315     }
316    
317    
318     #ifdef WITH_X11
319    
320 dpavlin 22 #define REDRAW redraw_fallback
321     #include "fb_include.c"
322     #undef REDRAW
323 dpavlin 4
324 dpavlin 22 #define FB_24
325     #define REDRAW redraw_24
326     #include "fb_include.c"
327     #undef REDRAW
328     #undef FB_24
329     #define FB_16
330     #define REDRAW redraw_16
331     #include "fb_include.c"
332     #undef FB_16
333     #undef REDRAW
334     #define FB_15
335     #define REDRAW redraw_15
336     #include "fb_include.c"
337     #undef REDRAW
338     #undef FB_15
339 dpavlin 4
340 dpavlin 22 #define FB_BO
341     #define FB_24
342     #define REDRAW redraw_24_bo
343     #include "fb_include.c"
344     #undef REDRAW
345     #undef FB_24
346     #define FB_16
347     #define REDRAW redraw_16_bo
348     #include "fb_include.c"
349     #undef FB_16
350     #undef REDRAW
351     #define FB_15
352     #define REDRAW redraw_15_bo
353     #include "fb_include.c"
354     #undef REDRAW
355     #undef FB_15
356     #undef FB_BO
357 dpavlin 4
358 dpavlin 22 #define FB_SCALEDOWN
359 dpavlin 4
360 dpavlin 22 #define REDRAW redraw_fallback_sd
361     #include "fb_include.c"
362     #undef REDRAW
363 dpavlin 4
364 dpavlin 22 #define FB_24
365     #define REDRAW redraw_24_sd
366     #include "fb_include.c"
367     #undef REDRAW
368     #undef FB_24
369     #define FB_16
370     #define REDRAW redraw_16_sd
371     #include "fb_include.c"
372     #undef FB_16
373     #undef REDRAW
374     #define FB_15
375     #define REDRAW redraw_15_sd
376     #include "fb_include.c"
377     #undef REDRAW
378     #undef FB_15
379 dpavlin 4
380 dpavlin 22 #define FB_BO
381     #define FB_24
382     #define REDRAW redraw_24_bo_sd
383     #include "fb_include.c"
384     #undef REDRAW
385     #undef FB_24
386     #define FB_16
387     #define REDRAW redraw_16_bo_sd
388     #include "fb_include.c"
389     #undef FB_16
390     #undef REDRAW
391     #define FB_15
392     #define REDRAW redraw_15_bo_sd
393     #include "fb_include.c"
394     #undef REDRAW
395     #undef FB_15
396     #undef FB_BO
397 dpavlin 4
398 dpavlin 22 void (*redraw[2 * 4 * 2])(struct vfb_data *, int, int) = {
399     redraw_fallback, redraw_fallback,
400     redraw_15, redraw_15_bo,
401     redraw_16, redraw_16_bo,
402     redraw_24, redraw_24_bo,
403     redraw_fallback_sd, redraw_fallback_sd,
404     redraw_15_sd, redraw_15_bo_sd,
405     redraw_16_sd, redraw_16_bo_sd,
406     redraw_24_sd, redraw_24_bo_sd };
407 dpavlin 4
408 dpavlin 22 #endif /* WITH_X11 */
409 dpavlin 4
410    
411     /*
412     * dev_fb_tick():
413     *
414     */
415     void dev_fb_tick(struct cpu *cpu, void *extra)
416     {
417     struct vfb_data *d = extra;
418     #ifdef WITH_X11
419     int need_to_flush_x11 = 0;
420     int need_to_redraw_cursor = 0;
421     #endif
422    
423     if (!cpu->machine->use_x11)
424     return;
425    
426     do {
427 dpavlin 12 uint64_t high, low = (uint64_t)(int64_t) -1;
428 dpavlin 4 int x, y;
429    
430 dpavlin 12 memory_device_dyntrans_access(cpu, cpu->mem,
431 dpavlin 4 extra, &low, &high);
432     if ((int64_t)low == -1)
433     break;
434    
435     /* printf("low=%016llx high=%016llx\n",
436     (long long)low, (long long)high); */
437    
438     x = (low % d->bytes_per_line) * 8 / d->bit_depth;
439     y = low / d->bytes_per_line;
440     if (x < d->update_x1 || d->update_x1 == -1)
441     d->update_x1 = x;
442     if (x > d->update_x2 || d->update_x2 == -1)
443     d->update_x2 = x;
444     if (y < d->update_y1 || d->update_y1 == -1)
445     d->update_y1 = y;
446     if (y > d->update_y2 || d->update_y2 == -1)
447     d->update_y2 = y;
448    
449     x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
450     y = (low+7) / d->bytes_per_line;
451     if (x < d->update_x1 || d->update_x1 == -1)
452     d->update_x1 = x;
453     if (x > d->update_x2 || d->update_x2 == -1)
454     d->update_x2 = x;
455     if (y < d->update_y1 || d->update_y1 == -1)
456     d->update_y1 = y;
457     if (y > d->update_y2 || d->update_y2 == -1)
458     d->update_y2 = y;
459    
460     x = (high % d->bytes_per_line) * 8 / d->bit_depth;
461     y = high / d->bytes_per_line;
462     if (x < d->update_x1 || d->update_x1 == -1)
463     d->update_x1 = x;
464     if (x > d->update_x2 || d->update_x2 == -1)
465     d->update_x2 = x;
466     if (y < d->update_y1 || d->update_y1 == -1)
467     d->update_y1 = y;
468     if (y > d->update_y2 || d->update_y2 == -1)
469     d->update_y2 = y;
470    
471     x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
472     y = (high+7) / d->bytes_per_line;
473     if (x < d->update_x1 || d->update_x1 == -1)
474     d->update_x1 = x;
475     if (x > d->update_x2 || d->update_x2 == -1)
476     d->update_x2 = x;
477     if (y < d->update_y1 || d->update_y1 == -1)
478     d->update_y1 = y;
479     if (y > d->update_y2 || d->update_y2 == -1)
480     d->update_y2 = y;
481    
482     /*
483     * An update covering more than one line will automatically
484     * force an update of all the affected lines:
485     */
486     if (d->update_y1 != d->update_y2) {
487     d->update_x1 = 0;
488     d->update_x2 = d->xsize-1;
489     }
490     } while (0);
491    
492     #ifdef WITH_X11
493     /* Do we need to redraw the cursor? */
494     if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
495     d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
496     d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
497     d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
498     d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
499     need_to_redraw_cursor = 1;
500    
501     if (d->update_x2 != -1) {
502 dpavlin 14 if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
503     d->update_x1 < (d->fb_window->OLD_cursor_x +
504     d->fb_window->OLD_cursor_xsize)) ||
505 dpavlin 4 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
506 dpavlin 14 d->update_x2 < (d->fb_window->OLD_cursor_x +
507     d->fb_window->OLD_cursor_xsize)) ||
508 dpavlin 4 (d->update_x1 < d->fb_window->OLD_cursor_x &&
509 dpavlin 14 d->update_x2 >= (d->fb_window->OLD_cursor_x +
510     d->fb_window->OLD_cursor_xsize)) ) &&
511     ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
512     d->update_y1 < (d->fb_window->OLD_cursor_y +
513     d->fb_window->OLD_cursor_ysize)) ||
514     (d->update_y2 >= d->fb_window->OLD_cursor_y &&
515     d->update_y2 < (d->fb_window->OLD_cursor_y +
516     d->fb_window->OLD_cursor_ysize)) ||
517     (d->update_y1 < d->fb_window->OLD_cursor_y &&
518     d->update_y2 >= (d->fb_window->OLD_cursor_y +
519     d->fb_window->OLD_cursor_ysize)) ) )
520     need_to_redraw_cursor = 1;
521 dpavlin 4 }
522    
523     if (need_to_redraw_cursor) {
524     /* Remove old cursor, if any: */
525     if (d->fb_window->OLD_cursor_on) {
526     XPutImage(d->fb_window->x11_display,
527     d->fb_window->x11_fb_window,
528     d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
529     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
530     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
531     d->fb_window->OLD_cursor_x/d->vfb_scaledown,
532     d->fb_window->OLD_cursor_y/d->vfb_scaledown,
533     d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
534 dpavlin 14 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
535 dpavlin 4 }
536     }
537     #endif
538    
539     if (d->update_x2 != -1) {
540 dpavlin 24 #ifdef WITH_X11
541     int y;
542     #endif
543     int addr, addr2, q = d->vfb_scaledown;
544 dpavlin 4
545 dpavlin 14 if (d->update_x1 >= d->visible_xsize)
546     d->update_x1 = d->visible_xsize - 1;
547     if (d->update_x2 >= d->visible_xsize)
548     d->update_x2 = d->visible_xsize - 1;
549     if (d->update_y1 >= d->visible_ysize)
550     d->update_y1 = d->visible_ysize - 1;
551     if (d->update_y2 >= d->visible_ysize)
552     d->update_y2 = d->visible_ysize - 1;
553 dpavlin 4
554 dpavlin 14 /* Without these, we might miss the rightmost/bottom pixel: */
555 dpavlin 4 d->update_x2 += (q - 1);
556     d->update_y2 += (q - 1);
557    
558     d->update_x1 = d->update_x1 / q * q;
559     d->update_x2 = d->update_x2 / q * q;
560     d->update_y1 = d->update_y1 / q * q;
561     d->update_y2 = d->update_y2 / q * q;
562    
563 dpavlin 14 addr = d->update_y1 * d->bytes_per_line +
564     d->update_x1 * d->bit_depth / 8;
565     addr2 = d->update_y1 * d->bytes_per_line +
566     d->update_x2 * d->bit_depth / 8;
567 dpavlin 4
568 dpavlin 22 #ifdef WITH_X11
569 dpavlin 4 for (y=d->update_y1; y<=d->update_y2; y+=q) {
570 dpavlin 22 d->redraw_func(d, addr, addr2 - addr);
571 dpavlin 4 addr += d->bytes_per_line * q;
572     addr2 += d->bytes_per_line * q;
573     }
574    
575 dpavlin 14 XPutImage(d->fb_window->x11_display, d->fb_window->
576     x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
577     fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
578     d->vfb_scaledown, d->update_x1/d->vfb_scaledown,
579     d->update_y1/d->vfb_scaledown,
580 dpavlin 4 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
581     (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
582    
583     need_to_flush_x11 = 1;
584     #endif
585    
586     d->update_x1 = d->update_y1 = 99999;
587     d->update_x2 = d->update_y2 = -1;
588     }
589    
590     #ifdef WITH_X11
591     if (need_to_redraw_cursor) {
592     /* Paint new cursor: */
593     if (d->fb_window->cursor_on) {
594 dpavlin 14 x11_redraw_cursor(cpu->machine,
595     d->fb_window->fb_number);
596 dpavlin 4 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
597     d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
598     d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
599 dpavlin 14 d->fb_window->OLD_cursor_xsize = d->fb_window->
600     cursor_xsize;
601     d->fb_window->OLD_cursor_ysize = d->fb_window->
602     cursor_ysize;
603 dpavlin 22 need_to_flush_x11 = 1;
604 dpavlin 4 }
605     }
606     #endif
607    
608     #ifdef WITH_X11
609     if (need_to_flush_x11)
610     XFlush(d->fb_window->x11_display);
611     #endif
612     }
613    
614    
615     /*
616     * dev_fb_access():
617     */
618 dpavlin 22 DEVICE_ACCESS(fb)
619 dpavlin 4 {
620     struct vfb_data *d = extra;
621 dpavlin 22 size_t i;
622 dpavlin 4
623     #ifdef FB_DEBUG
624     if (writeflag == MEM_WRITE) { if (data[0]) {
625     fatal("[ dev_fb: write to addr=%08lx, data = ",
626     (long)relative_addr);
627     for (i=0; i<len; i++)
628     fatal("%02x ", data[i]);
629     fatal("]\n");
630     } else {
631     fatal("[ dev_fb: read from addr=%08lx, data = ",
632     (long)relative_addr);
633     for (i=0; i<len; i++)
634     fatal("%02x ", d->framebuffer[relative_addr + i]);
635     fatal("]\n");
636     }
637     #endif
638    
639 dpavlin 6 if (relative_addr >= d->framebuffer_size)
640     return 0;
641    
642 dpavlin 4 /* See if a write actually modifies the framebuffer contents: */
643     if (writeflag == MEM_WRITE) {
644     for (i=0; i<len; i++) {
645     if (data[i] != d->framebuffer[relative_addr + i])
646     break;
647    
648     /* If all bytes are equal to what is already stored
649     in the framebuffer, then simply return: */
650 dpavlin 22 if (i == len-1)
651 dpavlin 4 return 1;
652     }
653     }
654    
655     /*
656     * If the framebuffer is modified, then we should keep a track
657     * of which area(s) we modify, so that the display isn't updated
658     * unnecessarily.
659     */
660     if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
661     int x, y, x2,y2;
662    
663     x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
664     y = relative_addr / d->bytes_per_line;
665     x2 = ((relative_addr + len) % d->bytes_per_line)
666     * 8 / d->bit_depth;
667     y2 = (relative_addr + len) / d->bytes_per_line;
668    
669     if (x < d->update_x1 || d->update_x1 == -1)
670     d->update_x1 = x;
671     if (x > d->update_x2 || d->update_x2 == -1)
672     d->update_x2 = x;
673    
674     if (y < d->update_y1 || d->update_y1 == -1)
675     d->update_y1 = y;
676     if (y > d->update_y2 || d->update_y2 == -1)
677     d->update_y2 = y;
678    
679     if (x2 < d->update_x1 || d->update_x1 == -1)
680     d->update_x1 = x2;
681     if (x2 > d->update_x2 || d->update_x2 == -1)
682     d->update_x2 = x2;
683    
684     if (y2 < d->update_y1 || d->update_y1 == -1)
685     d->update_y1 = y2;
686     if (y2 > d->update_y2 || d->update_y2 == -1)
687     d->update_y2 = y2;
688    
689     /*
690     * An update covering more than one line will automatically
691     * force an update of all the affected lines:
692     */
693     if (y != y2) {
694     d->update_x1 = 0;
695     d->update_x2 = d->xsize-1;
696     }
697     }
698    
699     /*
700     * Read from/write to the framebuffer:
701     * (TODO: take the color_plane_mask into account)
702     *
703     * Calling memcpy() is probably overkill, as it usually is just one
704     * or a few bytes that are read/written at a time.
705     */
706     if (writeflag == MEM_WRITE) {
707     if (len > 8)
708     memcpy(d->framebuffer + relative_addr, data, len);
709 dpavlin 22 else {
710 dpavlin 4 for (i=0; i<len; i++)
711     d->framebuffer[relative_addr + i] = data[i];
712 dpavlin 22 }
713 dpavlin 4 } else {
714     if (len > 8)
715     memcpy(data, d->framebuffer + relative_addr, len);
716 dpavlin 22 else {
717 dpavlin 4 for (i=0; i<len; i++)
718     data[i] = d->framebuffer[relative_addr + i];
719 dpavlin 22 }
720 dpavlin 4 }
721    
722     return 1;
723     }
724    
725    
726     /*
727     * dev_fb_init():
728     *
729 dpavlin 10 * This function is big and ugly, but the point is to initialize a framebuffer
730     * device. :-)
731     *
732     * visible_xsize and visible_ysize are the sizes of the visible display area.
733     * xsize and ysize tell how much memory is actually allocated (for example
734     * visible_xsize could be 640, but xsize could be 1024, for better alignment).
735     *
736     * vfb_type is useful for selecting special features.
737     *
738     * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
739     *
740     * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
741     *
742 dpavlin 18 * If type is VFB_HPC, then color encoding differs from the generic case.
743 dpavlin 10 *
744     * If bit_depth = -15 (note the minus sign), then a special hack is used for
745     * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
746 dpavlin 4 */
747     struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
748     uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
749 dpavlin 12 int xsize, int ysize, int bit_depth, char *name)
750 dpavlin 4 {
751     struct vfb_data *d;
752 dpavlin 10 size_t size, nlen;
753 dpavlin 12 int flags;
754 dpavlin 22 int reverse_start = 0;
755 dpavlin 4 char *name2;
756    
757     d = malloc(sizeof(struct vfb_data));
758     if (d == NULL) {
759     fprintf(stderr, "out of memory\n");
760     exit(1);
761     }
762     memset(d, 0, sizeof(struct vfb_data));
763    
764 dpavlin 22 if (vfb_type & VFB_REVERSE_START) {
765     vfb_type &= ~VFB_REVERSE_START;
766     reverse_start = 1;
767     }
768    
769 dpavlin 28 d->memory = mem;
770 dpavlin 4 d->vfb_type = vfb_type;
771    
772     /* Defaults: */
773     d->xsize = xsize; d->visible_xsize = visible_xsize;
774     d->ysize = ysize; d->visible_ysize = visible_ysize;
775    
776     d->bit_depth = bit_depth;
777    
778     if (bit_depth == 15) {
779     d->color32k = 1;
780     bit_depth = d->bit_depth = 16;
781 dpavlin 10 } else if (bit_depth == -15) {
782     d->psp_15bit = 1;
783     bit_depth = d->bit_depth = 16;
784 dpavlin 4 }
785    
786     /* Specific types: */
787     switch (vfb_type) {
788     case VFB_DEC_VFB01:
789     /* DECstation VFB01 (monochrome) */
790     d->xsize = 2048; d->visible_xsize = 1024;
791     d->ysize = 1024; d->visible_ysize = 864;
792     d->bit_depth = 1;
793     break;
794     case VFB_DEC_VFB02:
795     /* DECstation VFB02 (color) */
796     d->xsize = 1024; d->visible_xsize = 1024;
797     d->ysize = 1024; d->visible_ysize = 864;
798     d->bit_depth = 8;
799     break;
800     case VFB_DEC_MAXINE:
801     /* DECstation Maxine (1024x768x8) */
802     d->xsize = 1024; d->visible_xsize = d->xsize;
803     d->ysize = 768; d->visible_ysize = d->ysize;
804     d->bit_depth = 8;
805     break;
806     case VFB_PLAYSTATION2:
807     /* Playstation 2 */
808     d->xsize = xsize; d->visible_xsize = d->xsize;
809     d->ysize = ysize; d->visible_ysize = d->ysize;
810     d->bit_depth = 24;
811     break;
812     }
813    
814     if (d->bit_depth == 2 || d->bit_depth == 4)
815     set_grayscale_palette(d, 1 << d->bit_depth);
816     else if (d->bit_depth == 8 || d->bit_depth == 1)
817     set_blackwhite_palette(d, 1 << d->bit_depth);
818    
819     d->vfb_scaledown = machine->x11_scaledown;
820    
821     d->bytes_per_line = d->xsize * d->bit_depth / 8;
822     size = d->ysize * d->bytes_per_line;
823    
824     d->framebuffer = malloc(size);
825     if (d->framebuffer == NULL) {
826     fprintf(stderr, "out of memory\n");
827     exit(1);
828     }
829    
830     /* Clear the framebuffer (all black pixels): */
831     d->framebuffer_size = size;
832 dpavlin 22 memset(d->framebuffer, reverse_start? 255 : 0, size);
833 dpavlin 4
834     d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
835     d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
836    
837 dpavlin 22 /* Only "update" from the start if we need to fill with white. */
838     /* (The Ximage will be black from the start anyway.) */
839     if (reverse_start) {
840     d->update_x1 = d->update_y1 = 0;
841     d->update_x2 = d->xsize - 1;
842     d->update_y2 = d->ysize - 1;
843     } else {
844     d->update_x1 = d->update_y1 = 99999;
845     d->update_x2 = d->update_y2 = -1;
846     }
847 dpavlin 4
848 dpavlin 28 d->name = strdup(name);
849     set_title(d);
850 dpavlin 4
851     #ifdef WITH_X11
852 dpavlin 22 if (machine->use_x11) {
853     int i = 0;
854 dpavlin 4 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
855 dpavlin 28 d->title, machine->x11_scaledown, machine);
856 dpavlin 22 switch (d->fb_window->x11_screen_depth) {
857     case 15: i = 2; break;
858     case 16: i = 4; break;
859     case 24: i = 6; break;
860     }
861     if (d->fb_window->fb_ximage->byte_order)
862     i ++;
863     if (d->vfb_scaledown > 1)
864     i += 8;
865     d->redraw_func = redraw[i];
866     } else
867 dpavlin 4 #endif
868     d->fb_window = NULL;
869    
870 dpavlin 10 nlen = strlen(name) + 10;
871     name2 = malloc(nlen);
872 dpavlin 4 if (name2 == NULL) {
873     fprintf(stderr, "out of memory in dev_fb_init()\n");
874     exit(1);
875     }
876 dpavlin 10 snprintf(name2, nlen, "fb [%s]", name);
877 dpavlin 4
878 dpavlin 20 flags = DM_DEFAULT;
879 dpavlin 4 if ((baseaddr & 0xfff) == 0)
880 dpavlin 20 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
881 dpavlin 4
882 dpavlin 20 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
883 dpavlin 6
884 dpavlin 4 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
885     d, flags, d->framebuffer);
886    
887 dpavlin 24 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT, 0.0);
888 dpavlin 4 return d;
889     }
890    

  ViewVC Help
Powered by ViewVC 1.1.26