/[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

Contents of /trunk/src/devices/dev_fb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 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 /*
2 * Copyright (C) 2003-2006 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 * $Id: dev_fb.c,v 1.121 2006/07/08 12:30:02 debug Exp $
29 *
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 * HPC (mips, arm, ..) framebuffer
36 * Playstation 2 (24-bit color)
37 * Generic (any resolution, several bit depths possible, useful for
38 * testmachines)
39 *
40 *
41 * TODO: This should actually be independent of X11, but that
42 * 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 #define FB_TICK_SHIFT 19
67
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 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 /*
117 * 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 *
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 */
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 if (new_xsize < 10 || new_ysize < 10) {
138 fatal("dev_fb_resize(): size too small.\n");
139 exit(1);
140 }
141
142 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 if (new_xsize > d->xsize || new_ysize > d->ysize) {
172 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 d->xsize = d->visible_xsize = new_xsize;
179 d->ysize = d->visible_ysize = new_ysize;
180
181 d->x11_xsize = d->xsize / d->vfb_scaledown;
182 d->x11_ysize = d->ysize / d->vfb_scaledown;
183
184 memory_device_update_data(d->memory, d, d->framebuffer);
185
186 set_title(d);
187
188 #ifdef WITH_X11
189 if (d->fb_window != NULL) {
190 x11_fb_resize(d->fb_window, new_xsize, new_ysize);
191 x11_set_standard_properties(d->fb_window, d->title);
192 }
193 #endif
194 }
195
196
197 /*
198 * 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 for (x=0; x<linelen && x<sizeof(buf);
276 x += 3) {
277 buf[x] = fill_r;
278 buf[x+1] = fill_g;
279 buf[x+2] = fill_b;
280 }
281 else {
282 fatal("[ fb: TODO: fill for non-24-bit"
283 " modes ]\n");
284 }
285
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 #define REDRAW redraw_fallback
321 #include "fb_include.c"
322 #undef REDRAW
323
324 #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
340 #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
358 #define FB_SCALEDOWN
359
360 #define REDRAW redraw_fallback_sd
361 #include "fb_include.c"
362 #undef REDRAW
363
364 #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
380 #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
398 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
408 #endif /* WITH_X11 */
409
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 uint64_t high, low = (uint64_t)(int64_t) -1;
428 int x, y;
429
430 memory_device_dyntrans_access(cpu, cpu->mem,
431 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 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 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
506 d->update_x2 < (d->fb_window->OLD_cursor_x +
507 d->fb_window->OLD_cursor_xsize)) ||
508 (d->update_x1 < d->fb_window->OLD_cursor_x &&
509 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 }
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 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
535 }
536 }
537 #endif
538
539 if (d->update_x2 != -1) {
540 #ifdef WITH_X11
541 int y;
542 #endif
543 int addr, addr2, q = d->vfb_scaledown;
544
545 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
554 /* Without these, we might miss the rightmost/bottom pixel: */
555 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 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
568 #ifdef WITH_X11
569 for (y=d->update_y1; y<=d->update_y2; y+=q) {
570 d->redraw_func(d, addr, addr2 - addr);
571 addr += d->bytes_per_line * q;
572 addr2 += d->bytes_per_line * q;
573 }
574
575 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 (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 x11_redraw_cursor(cpu->machine,
595 d->fb_window->fb_number);
596 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 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 need_to_flush_x11 = 1;
604 }
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 DEVICE_ACCESS(fb)
619 {
620 struct vfb_data *d = extra;
621 size_t i;
622
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 if (relative_addr >= d->framebuffer_size)
640 return 0;
641
642 /* 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 if (i == len-1)
651 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 else {
710 for (i=0; i<len; i++)
711 d->framebuffer[relative_addr + i] = data[i];
712 }
713 } else {
714 if (len > 8)
715 memcpy(data, d->framebuffer + relative_addr, len);
716 else {
717 for (i=0; i<len; i++)
718 data[i] = d->framebuffer[relative_addr + i];
719 }
720 }
721
722 return 1;
723 }
724
725
726 /*
727 * dev_fb_init():
728 *
729 * 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 * If type is VFB_HPC, then color encoding differs from the generic case.
743 *
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 */
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 int xsize, int ysize, int bit_depth, char *name)
750 {
751 struct vfb_data *d;
752 size_t size, nlen;
753 int flags;
754 int reverse_start = 0;
755 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 if (vfb_type & VFB_REVERSE_START) {
765 vfb_type &= ~VFB_REVERSE_START;
766 reverse_start = 1;
767 }
768
769 d->memory = mem;
770 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 } else if (bit_depth == -15) {
782 d->psp_15bit = 1;
783 bit_depth = d->bit_depth = 16;
784 }
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 memset(d->framebuffer, reverse_start? 255 : 0, size);
833
834 d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
835 d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
836
837 /* 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
848 d->name = strdup(name);
849 set_title(d);
850
851 #ifdef WITH_X11
852 if (machine->use_x11) {
853 int i = 0;
854 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
855 d->title, machine->x11_scaledown, machine);
856 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 #endif
868 d->fb_window = NULL;
869
870 nlen = strlen(name) + 10;
871 name2 = malloc(nlen);
872 if (name2 == NULL) {
873 fprintf(stderr, "out of memory in dev_fb_init()\n");
874 exit(1);
875 }
876 snprintf(name2, nlen, "fb [%s]", name);
877
878 flags = DM_DEFAULT;
879 if ((baseaddr & 0xfff) == 0)
880 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
881
882 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
883
884 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
885 d, flags, d->framebuffer);
886
887 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT, 0.0);
888 return d;
889 }
890

  ViewVC Help
Powered by ViewVC 1.1.26