/[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 30 - (show annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 24281 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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.123 2006/07/24 08:08:39 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. (In 8-bit mode, only fill_r is used.)
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 x, 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 unsigned char *buf =
273 d->framebuffer + dest_ofs;
274
275 if (d->bit_depth == 24) {
276 for (x=0; x<linelen && x<sizeof(buf);
277 x += 3) {
278 buf[x] = fill_r;
279 buf[x+1] = fill_g;
280 buf[x+2] = fill_b;
281 }
282 } else if (d->bit_depth == 8) {
283 memset(buf, fill_r, linelen);
284 } else {
285 fatal("Unimplemented bit-depth (%i)"
286 " for fb fill\n", d->bit_depth);
287 exit(1);
288 }
289 }
290
291 dest_ofs += d->bytes_per_line;
292 }
293 } else {
294 from_ofs = d->bytes_per_line * from_y +
295 (d->bit_depth/8) * from_x;
296 for (y=y1; y<=y2; y++) {
297 if (y >= 0 && y < d->ysize) {
298 if (from_y >= 0 && from_y < d->ysize)
299 memmove(d->framebuffer + dest_ofs,
300 d->framebuffer + from_ofs, linelen);
301 else
302 memset(d->framebuffer + dest_ofs,
303 0, linelen);
304 }
305 from_y ++;
306 from_ofs += d->bytes_per_line;
307 dest_ofs += d->bytes_per_line;
308 }
309 }
310
311 if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
312 if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
313 if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
314 if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
315
316 if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
317 if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
318 if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
319 if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
320 }
321
322
323 #ifdef WITH_X11
324
325 #define REDRAW redraw_fallback
326 #include "fb_include.c"
327 #undef REDRAW
328
329 #define FB_24
330 #define REDRAW redraw_24
331 #include "fb_include.c"
332 #undef REDRAW
333 #undef FB_24
334 #define FB_16
335 #define REDRAW redraw_16
336 #include "fb_include.c"
337 #undef FB_16
338 #undef REDRAW
339 #define FB_15
340 #define REDRAW redraw_15
341 #include "fb_include.c"
342 #undef REDRAW
343 #undef FB_15
344
345 #define FB_BO
346 #define FB_24
347 #define REDRAW redraw_24_bo
348 #include "fb_include.c"
349 #undef REDRAW
350 #undef FB_24
351 #define FB_16
352 #define REDRAW redraw_16_bo
353 #include "fb_include.c"
354 #undef FB_16
355 #undef REDRAW
356 #define FB_15
357 #define REDRAW redraw_15_bo
358 #include "fb_include.c"
359 #undef REDRAW
360 #undef FB_15
361 #undef FB_BO
362
363 #define FB_SCALEDOWN
364
365 #define REDRAW redraw_fallback_sd
366 #include "fb_include.c"
367 #undef REDRAW
368
369 #define FB_24
370 #define REDRAW redraw_24_sd
371 #include "fb_include.c"
372 #undef REDRAW
373 #undef FB_24
374 #define FB_16
375 #define REDRAW redraw_16_sd
376 #include "fb_include.c"
377 #undef FB_16
378 #undef REDRAW
379 #define FB_15
380 #define REDRAW redraw_15_sd
381 #include "fb_include.c"
382 #undef REDRAW
383 #undef FB_15
384
385 #define FB_BO
386 #define FB_24
387 #define REDRAW redraw_24_bo_sd
388 #include "fb_include.c"
389 #undef REDRAW
390 #undef FB_24
391 #define FB_16
392 #define REDRAW redraw_16_bo_sd
393 #include "fb_include.c"
394 #undef FB_16
395 #undef REDRAW
396 #define FB_15
397 #define REDRAW redraw_15_bo_sd
398 #include "fb_include.c"
399 #undef REDRAW
400 #undef FB_15
401 #undef FB_BO
402
403 void (*redraw[2 * 4 * 2])(struct vfb_data *, int, int) = {
404 redraw_fallback, redraw_fallback,
405 redraw_15, redraw_15_bo,
406 redraw_16, redraw_16_bo,
407 redraw_24, redraw_24_bo,
408 redraw_fallback_sd, redraw_fallback_sd,
409 redraw_15_sd, redraw_15_bo_sd,
410 redraw_16_sd, redraw_16_bo_sd,
411 redraw_24_sd, redraw_24_bo_sd };
412
413 #endif /* WITH_X11 */
414
415
416 /*
417 * dev_fb_tick():
418 *
419 */
420 void dev_fb_tick(struct cpu *cpu, void *extra)
421 {
422 struct vfb_data *d = extra;
423 #ifdef WITH_X11
424 int need_to_flush_x11 = 0;
425 int need_to_redraw_cursor = 0;
426 #endif
427
428 if (!cpu->machine->use_x11)
429 return;
430
431 do {
432 uint64_t high, low = (uint64_t)(int64_t) -1;
433 int x, y;
434
435 memory_device_dyntrans_access(cpu, cpu->mem,
436 extra, &low, &high);
437 if ((int64_t)low == -1)
438 break;
439
440 /* printf("low=%016llx high=%016llx\n",
441 (long long)low, (long long)high); */
442
443 x = (low % d->bytes_per_line) * 8 / d->bit_depth;
444 y = low / d->bytes_per_line;
445 if (x < d->update_x1 || d->update_x1 == -1)
446 d->update_x1 = x;
447 if (x > d->update_x2 || d->update_x2 == -1)
448 d->update_x2 = x;
449 if (y < d->update_y1 || d->update_y1 == -1)
450 d->update_y1 = y;
451 if (y > d->update_y2 || d->update_y2 == -1)
452 d->update_y2 = y;
453
454 x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
455 y = (low+7) / d->bytes_per_line;
456 if (x < d->update_x1 || d->update_x1 == -1)
457 d->update_x1 = x;
458 if (x > d->update_x2 || d->update_x2 == -1)
459 d->update_x2 = x;
460 if (y < d->update_y1 || d->update_y1 == -1)
461 d->update_y1 = y;
462 if (y > d->update_y2 || d->update_y2 == -1)
463 d->update_y2 = y;
464
465 x = (high % d->bytes_per_line) * 8 / d->bit_depth;
466 y = high / d->bytes_per_line;
467 if (x < d->update_x1 || d->update_x1 == -1)
468 d->update_x1 = x;
469 if (x > d->update_x2 || d->update_x2 == -1)
470 d->update_x2 = x;
471 if (y < d->update_y1 || d->update_y1 == -1)
472 d->update_y1 = y;
473 if (y > d->update_y2 || d->update_y2 == -1)
474 d->update_y2 = y;
475
476 x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
477 y = (high+7) / d->bytes_per_line;
478 if (x < d->update_x1 || d->update_x1 == -1)
479 d->update_x1 = x;
480 if (x > d->update_x2 || d->update_x2 == -1)
481 d->update_x2 = x;
482 if (y < d->update_y1 || d->update_y1 == -1)
483 d->update_y1 = y;
484 if (y > d->update_y2 || d->update_y2 == -1)
485 d->update_y2 = y;
486
487 /*
488 * An update covering more than one line will automatically
489 * force an update of all the affected lines:
490 */
491 if (d->update_y1 != d->update_y2) {
492 d->update_x1 = 0;
493 d->update_x2 = d->xsize-1;
494 }
495 } while (0);
496
497 #ifdef WITH_X11
498 /* Do we need to redraw the cursor? */
499 if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
500 d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
501 d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
502 d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
503 d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
504 need_to_redraw_cursor = 1;
505
506 if (d->update_x2 != -1) {
507 if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
508 d->update_x1 < (d->fb_window->OLD_cursor_x +
509 d->fb_window->OLD_cursor_xsize)) ||
510 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
511 d->update_x2 < (d->fb_window->OLD_cursor_x +
512 d->fb_window->OLD_cursor_xsize)) ||
513 (d->update_x1 < d->fb_window->OLD_cursor_x &&
514 d->update_x2 >= (d->fb_window->OLD_cursor_x +
515 d->fb_window->OLD_cursor_xsize)) ) &&
516 ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
517 d->update_y1 < (d->fb_window->OLD_cursor_y +
518 d->fb_window->OLD_cursor_ysize)) ||
519 (d->update_y2 >= d->fb_window->OLD_cursor_y &&
520 d->update_y2 < (d->fb_window->OLD_cursor_y +
521 d->fb_window->OLD_cursor_ysize)) ||
522 (d->update_y1 < d->fb_window->OLD_cursor_y &&
523 d->update_y2 >= (d->fb_window->OLD_cursor_y +
524 d->fb_window->OLD_cursor_ysize)) ) )
525 need_to_redraw_cursor = 1;
526 }
527
528 if (need_to_redraw_cursor) {
529 /* Remove old cursor, if any: */
530 if (d->fb_window->OLD_cursor_on) {
531 XPutImage(d->fb_window->x11_display,
532 d->fb_window->x11_fb_window,
533 d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
534 d->fb_window->OLD_cursor_x/d->vfb_scaledown,
535 d->fb_window->OLD_cursor_y/d->vfb_scaledown,
536 d->fb_window->OLD_cursor_x/d->vfb_scaledown,
537 d->fb_window->OLD_cursor_y/d->vfb_scaledown,
538 d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
539 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
540 }
541 }
542 #endif
543
544 if (d->update_x2 != -1) {
545 #ifdef WITH_X11
546 int y;
547 #endif
548 int addr, addr2, q = d->vfb_scaledown;
549
550 if (d->update_x1 >= d->visible_xsize)
551 d->update_x1 = d->visible_xsize - 1;
552 if (d->update_x2 >= d->visible_xsize)
553 d->update_x2 = d->visible_xsize - 1;
554 if (d->update_y1 >= d->visible_ysize)
555 d->update_y1 = d->visible_ysize - 1;
556 if (d->update_y2 >= d->visible_ysize)
557 d->update_y2 = d->visible_ysize - 1;
558
559 /* Without these, we might miss the rightmost/bottom pixel: */
560 d->update_x2 += (q - 1);
561 d->update_y2 += (q - 1);
562
563 d->update_x1 = d->update_x1 / q * q;
564 d->update_x2 = d->update_x2 / q * q;
565 d->update_y1 = d->update_y1 / q * q;
566 d->update_y2 = d->update_y2 / q * q;
567
568 addr = d->update_y1 * d->bytes_per_line +
569 d->update_x1 * d->bit_depth / 8;
570 addr2 = d->update_y1 * d->bytes_per_line +
571 d->update_x2 * d->bit_depth / 8;
572
573 #ifdef WITH_X11
574 for (y=d->update_y1; y<=d->update_y2; y+=q) {
575 d->redraw_func(d, addr, addr2 - addr);
576 addr += d->bytes_per_line * q;
577 addr2 += d->bytes_per_line * q;
578 }
579
580 XPutImage(d->fb_window->x11_display, d->fb_window->
581 x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
582 fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
583 d->vfb_scaledown, d->update_x1/d->vfb_scaledown,
584 d->update_y1/d->vfb_scaledown,
585 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
586 (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
587
588 need_to_flush_x11 = 1;
589 #endif
590
591 d->update_x1 = d->update_y1 = 99999;
592 d->update_x2 = d->update_y2 = -1;
593 }
594
595 #ifdef WITH_X11
596 if (need_to_redraw_cursor) {
597 /* Paint new cursor: */
598 if (d->fb_window->cursor_on) {
599 x11_redraw_cursor(cpu->machine,
600 d->fb_window->fb_number);
601 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
602 d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
603 d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
604 d->fb_window->OLD_cursor_xsize = d->fb_window->
605 cursor_xsize;
606 d->fb_window->OLD_cursor_ysize = d->fb_window->
607 cursor_ysize;
608 need_to_flush_x11 = 1;
609 }
610 }
611 #endif
612
613 #ifdef WITH_X11
614 if (need_to_flush_x11)
615 XFlush(d->fb_window->x11_display);
616 #endif
617 }
618
619
620 /*
621 * dev_fb_access():
622 */
623 DEVICE_ACCESS(fb)
624 {
625 struct vfb_data *d = extra;
626 size_t i;
627
628 #ifdef FB_DEBUG
629 if (writeflag == MEM_WRITE) { if (data[0]) {
630 fatal("[ dev_fb: write to addr=%08lx, data = ",
631 (long)relative_addr);
632 for (i=0; i<len; i++)
633 fatal("%02x ", data[i]);
634 fatal("]\n");
635 } else {
636 fatal("[ dev_fb: read from addr=%08lx, data = ",
637 (long)relative_addr);
638 for (i=0; i<len; i++)
639 fatal("%02x ", d->framebuffer[relative_addr + i]);
640 fatal("]\n");
641 }
642 #endif
643
644 if (relative_addr >= d->framebuffer_size)
645 return 0;
646
647 /* See if a write actually modifies the framebuffer contents: */
648 if (writeflag == MEM_WRITE) {
649 for (i=0; i<len; i++) {
650 if (data[i] != d->framebuffer[relative_addr + i])
651 break;
652
653 /* If all bytes are equal to what is already stored
654 in the framebuffer, then simply return: */
655 if (i == len-1)
656 return 1;
657 }
658 }
659
660 /*
661 * If the framebuffer is modified, then we should keep a track
662 * of which area(s) we modify, so that the display isn't updated
663 * unnecessarily.
664 */
665 if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
666 int x, y, x2,y2;
667
668 x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
669 y = relative_addr / d->bytes_per_line;
670 x2 = ((relative_addr + len) % d->bytes_per_line)
671 * 8 / d->bit_depth;
672 y2 = (relative_addr + len) / d->bytes_per_line;
673
674 if (x < d->update_x1 || d->update_x1 == -1)
675 d->update_x1 = x;
676 if (x > d->update_x2 || d->update_x2 == -1)
677 d->update_x2 = x;
678
679 if (y < d->update_y1 || d->update_y1 == -1)
680 d->update_y1 = y;
681 if (y > d->update_y2 || d->update_y2 == -1)
682 d->update_y2 = y;
683
684 if (x2 < d->update_x1 || d->update_x1 == -1)
685 d->update_x1 = x2;
686 if (x2 > d->update_x2 || d->update_x2 == -1)
687 d->update_x2 = x2;
688
689 if (y2 < d->update_y1 || d->update_y1 == -1)
690 d->update_y1 = y2;
691 if (y2 > d->update_y2 || d->update_y2 == -1)
692 d->update_y2 = y2;
693
694 /*
695 * An update covering more than one line will automatically
696 * force an update of all the affected lines:
697 */
698 if (y != y2) {
699 d->update_x1 = 0;
700 d->update_x2 = d->xsize-1;
701 }
702 }
703
704 /*
705 * Read from/write to the framebuffer:
706 * (TODO: take the color_plane_mask into account)
707 *
708 * Calling memcpy() is probably overkill, as it usually is just one
709 * or a few bytes that are read/written at a time.
710 */
711 if (writeflag == MEM_WRITE) {
712 if (len > 8)
713 memcpy(d->framebuffer + relative_addr, data, len);
714 else {
715 for (i=0; i<len; i++)
716 d->framebuffer[relative_addr + i] = data[i];
717 }
718 } else {
719 if (len > 8)
720 memcpy(data, d->framebuffer + relative_addr, len);
721 else {
722 for (i=0; i<len; i++)
723 data[i] = d->framebuffer[relative_addr + i];
724 }
725 }
726
727 return 1;
728 }
729
730
731 /*
732 * dev_fb_init():
733 *
734 * This function is big and ugly, but the point is to initialize a framebuffer
735 * device. :-)
736 *
737 * visible_xsize and visible_ysize are the sizes of the visible display area.
738 * xsize and ysize tell how much memory is actually allocated (for example
739 * visible_xsize could be 640, but xsize could be 1024, for better alignment).
740 *
741 * vfb_type is useful for selecting special features.
742 *
743 * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
744 *
745 * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
746 *
747 * If type is VFB_HPC, then color encoding differs from the generic case.
748 *
749 * If bit_depth = -15 (note the minus sign), then a special hack is used for
750 * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
751 */
752 struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
753 uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
754 int xsize, int ysize, int bit_depth, char *name)
755 {
756 struct vfb_data *d;
757 size_t size, nlen;
758 int flags;
759 int reverse_start = 0;
760 char *name2;
761
762 d = malloc(sizeof(struct vfb_data));
763 if (d == NULL) {
764 fprintf(stderr, "out of memory\n");
765 exit(1);
766 }
767 memset(d, 0, sizeof(struct vfb_data));
768
769 if (vfb_type & VFB_REVERSE_START) {
770 vfb_type &= ~VFB_REVERSE_START;
771 reverse_start = 1;
772 }
773
774 d->memory = mem;
775 d->vfb_type = vfb_type;
776
777 /* Defaults: */
778 d->xsize = xsize; d->visible_xsize = visible_xsize;
779 d->ysize = ysize; d->visible_ysize = visible_ysize;
780
781 d->bit_depth = bit_depth;
782
783 if (bit_depth == 15) {
784 d->color32k = 1;
785 bit_depth = d->bit_depth = 16;
786 } else if (bit_depth == -15) {
787 d->psp_15bit = 1;
788 bit_depth = d->bit_depth = 16;
789 }
790
791 /* Specific types: */
792 switch (vfb_type) {
793 case VFB_DEC_VFB01:
794 /* DECstation VFB01 (monochrome) */
795 d->xsize = 2048; d->visible_xsize = 1024;
796 d->ysize = 1024; d->visible_ysize = 864;
797 d->bit_depth = 1;
798 break;
799 case VFB_DEC_VFB02:
800 /* DECstation VFB02 (color) */
801 d->xsize = 1024; d->visible_xsize = 1024;
802 d->ysize = 1024; d->visible_ysize = 864;
803 d->bit_depth = 8;
804 break;
805 case VFB_DEC_MAXINE:
806 /* DECstation Maxine (1024x768x8) */
807 d->xsize = 1024; d->visible_xsize = d->xsize;
808 d->ysize = 768; d->visible_ysize = d->ysize;
809 d->bit_depth = 8;
810 break;
811 case VFB_PLAYSTATION2:
812 /* Playstation 2 */
813 d->xsize = xsize; d->visible_xsize = d->xsize;
814 d->ysize = ysize; d->visible_ysize = d->ysize;
815 d->bit_depth = 24;
816 break;
817 }
818
819 if (d->bit_depth == 2 || d->bit_depth == 4)
820 set_grayscale_palette(d, 1 << d->bit_depth);
821 else if (d->bit_depth == 8 || d->bit_depth == 1)
822 set_blackwhite_palette(d, 1 << d->bit_depth);
823
824 d->vfb_scaledown = machine->x11_scaledown;
825
826 d->bytes_per_line = d->xsize * d->bit_depth / 8;
827 size = d->ysize * d->bytes_per_line;
828
829 d->framebuffer = malloc(size);
830 if (d->framebuffer == NULL) {
831 fprintf(stderr, "out of memory\n");
832 exit(1);
833 }
834
835 /* Clear the framebuffer (all black pixels): */
836 d->framebuffer_size = size;
837 memset(d->framebuffer, reverse_start? 255 : 0, size);
838
839 d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
840 d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
841
842 /* Only "update" from the start if we need to fill with white. */
843 /* (The Ximage will be black from the start anyway.) */
844 if (reverse_start) {
845 d->update_x1 = d->update_y1 = 0;
846 d->update_x2 = d->xsize - 1;
847 d->update_y2 = d->ysize - 1;
848 } else {
849 d->update_x1 = d->update_y1 = 99999;
850 d->update_x2 = d->update_y2 = -1;
851 }
852
853 d->name = strdup(name);
854 set_title(d);
855
856 #ifdef WITH_X11
857 if (machine->use_x11) {
858 int i = 0;
859 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
860 d->title, machine->x11_scaledown, machine);
861 switch (d->fb_window->x11_screen_depth) {
862 case 15: i = 2; break;
863 case 16: i = 4; break;
864 case 24: i = 6; break;
865 }
866 if (d->fb_window->fb_ximage->byte_order)
867 i ++;
868 if (d->vfb_scaledown > 1)
869 i += 8;
870 d->redraw_func = redraw[i];
871 } else
872 #endif
873 d->fb_window = NULL;
874
875 nlen = strlen(name) + 10;
876 name2 = malloc(nlen);
877 if (name2 == NULL) {
878 fprintf(stderr, "out of memory in dev_fb_init()\n");
879 exit(1);
880 }
881 snprintf(name2, nlen, "fb [%s]", name);
882
883 flags = DM_DEFAULT;
884 if ((baseaddr & 0xfff) == 0)
885 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
886
887 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
888
889 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
890 d, flags, d->framebuffer);
891
892 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT, 0.0);
893 return d;
894 }
895

  ViewVC Help
Powered by ViewVC 1.1.26