/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 27326 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_fb.c,v 1.90 2005/03/29 09:46:06 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 * HPCmips framebuffer
36 * Playstation 2 (24-bit color)
37 * generic (any resolution, several bit depths possible)
38 *
39 *
40 * TODO: There is still a bug when redrawing the cursor. The underlying
41 * image is moved 1 pixel (?), or something like that.
42 *
43 * TODO: This should actually be independant of X11, but that
44 * might be too hard to do right now.
45 *
46 * TODO: playstation 2 pixels are stored in another format, actually
47 */
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include "console.h"
54 #include "cpu.h"
55 #include "devices.h"
56 #include "machine.h"
57 #include "memory.h"
58 #include "misc.h"
59 #include "x11.h"
60
61 #ifdef WITH_X11
62 #include <X11/Xlib.h>
63 #include <X11/Xos.h>
64 #include <X11/Xutil.h>
65 #endif
66
67
68 #define FB_TICK_SHIFT 18
69
70 #define LOGO_XSIZE 256
71 #define LOGO_YSIZE 256
72 #define LOGO_BOTTOM_MARGIN 60
73 /* This must be a 256*256 pixels P4 ppm: */
74 #include "fb_logo.c"
75 unsigned char *fb_logo = fb_logo_ppm + 11;
76
77
78 /* #define FB_DEBUG */
79
80 /*
81 * set_grayscale_palette():
82 *
83 * Fill d->rgb_palette with grayscale values. ncolors should
84 * be something like 2, 4, 16, or 256.
85 */
86 void set_grayscale_palette(struct vfb_data *d, int ncolors)
87 {
88 int i, gray;
89
90 for (i=0; i<256; i++) {
91 gray = 255*i/(ncolors-1);
92 d->rgb_palette[i*3 + 0] = gray;
93 d->rgb_palette[i*3 + 1] = gray;
94 d->rgb_palette[i*3 + 2] = gray;
95 }
96 }
97
98
99 /*
100 * set_blackwhite_palette():
101 *
102 * Set color 0 = black, all others to white.
103 */
104 void set_blackwhite_palette(struct vfb_data *d, int ncolors)
105 {
106 int i, gray;
107
108 for (i=0; i<256; i++) {
109 gray = i==0? 0 : 255;
110 d->rgb_palette[i*3 + 0] = gray;
111 d->rgb_palette[i*3 + 1] = gray;
112 d->rgb_palette[i*3 + 2] = gray;
113 }
114 }
115
116
117 /*
118 * dev_fb_setcursor():
119 */
120 void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
121 int cursor_xsize, int cursor_ysize)
122 {
123 if (cursor_x < 0)
124 cursor_x = 0;
125 if (cursor_y < 0)
126 cursor_y = 0;
127 if (cursor_x + cursor_xsize >= d->xsize)
128 cursor_x = d->xsize - cursor_xsize;
129 if (cursor_y + cursor_ysize >= d->ysize)
130 cursor_y = d->ysize - cursor_ysize;
131
132 #ifdef WITH_X11
133 if (d->fb_window != NULL) {
134 d->fb_window->cursor_x = cursor_x;
135 d->fb_window->cursor_y = cursor_y;
136 d->fb_window->cursor_on = on;
137 d->fb_window->cursor_xsize = cursor_xsize;
138 d->fb_window->cursor_ysize = cursor_ysize;
139 }
140 #endif
141
142 if (d->fb_window != NULL)
143 console_set_framebuffer_mouse(cursor_x, cursor_y,
144 d->fb_window->fb_number);
145
146 /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
147 cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
148 }
149
150
151 /*
152 * framebuffer_blockcopyfill():
153 *
154 * This function should be used by devices that are capable of doing
155 * block copy/fill.
156 *
157 * If fillflag is non-zero, then fill_[rgb] should contain the color
158 * with which to fill.
159 *
160 * If fillflag is zero, copy mode is used, and from_[xy] should contain
161 * the offset on the framebuffer where we should copy from.
162 *
163 * NOTE: Overlapping copies are undefined!
164 */
165 void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
166 int fill_g, int fill_b, int x1, int y1, int x2, int y2,
167 int from_x, int from_y)
168 {
169 int y;
170 long from_ofs, dest_ofs, linelen;
171
172 if (fillflag)
173 debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
174 "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
175 else
176 debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
177 "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
178
179 /* Clip x: */
180 if (x1 < 0) x1 = 0;
181 if (x1 >= d->xsize) x1 = d->xsize-1;
182 if (x2 < 0) x2 = 0;
183 if (x2 >= d->xsize) x2 = d->xsize-1;
184
185 dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
186 linelen = (x2-x1 + 1) * (d->bit_depth/8);
187 /* NOTE: linelen is nr of bytes, not pixels */
188
189 if (fillflag) {
190 for (y=y1; y<=y2; y++) {
191 if (y>=0 && y<d->ysize) {
192 int x;
193 char buf[8192 * 3];
194 if (d->bit_depth == 24)
195 for (x=0; x<linelen; x+=3) {
196 buf[x] = fill_r;
197 buf[x+1] = fill_g;
198 buf[x+2] = fill_b;
199 }
200 else
201 printf("TODO: fill for non-24-bit"
202 " modes\n");
203
204 memmove(d->framebuffer + dest_ofs, buf,
205 linelen);
206 }
207
208 dest_ofs += d->bytes_per_line;
209 }
210 } else {
211 from_ofs = d->bytes_per_line * from_y +
212 (d->bit_depth/8) * from_x;
213
214 for (y=y1; y<=y2; y++) {
215 if (y>=0 && y<d->ysize)
216 memmove(d->framebuffer + dest_ofs,
217 d->framebuffer + from_ofs, linelen);
218
219 from_ofs += d->bytes_per_line;
220 dest_ofs += d->bytes_per_line;
221 }
222 }
223
224 if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
225 if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
226 if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
227 if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
228
229 if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
230 if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
231 if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
232 if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
233 }
234
235
236 #ifdef WITH_X11
237 #define macro_put_pixel() { \
238 /* Combine the color into an X11 long and display it: */ \
239 /* TODO: construct color in a more portable way: */ \
240 switch (d->fb_window->x11_screen_depth) { \
241 case 24: \
242 if (d->fb_window->fb_ximage->byte_order) \
243 color = (b << 16) + (g << 8) + r; \
244 else \
245 color = (r << 16) + (g << 8) + b; \
246 break; \
247 case 16: \
248 r >>= 3; g >>= 2; b >>= 3; \
249 if (d->fb_window->fb_ximage->byte_order) { \
250 /* Big endian 16-bit X server: */ \
251 static int first = 1; \
252 if (first) { \
253 fprintf(stderr, "\n*** Please report to the author whether 16-bit X11 colors are rendered correctly or not!\n\n"); \
254 first = 0; \
255 } \
256 color = (b << 11) + (g << 5) + r; \
257 } else { \
258 /* Little endian (eg PC) X servers: */ \
259 color = (r << 11) + (g << 5) + b; \
260 } \
261 break; \
262 case 15: \
263 r >>= 3; g >>= 3; b >>= 3; \
264 if (d->fb_window->fb_ximage->byte_order) { \
265 /* Big endian 15-bit X server: */ \
266 static int first = 1; \
267 if (first) { \
268 fprintf(stderr, "\n*** Please report to the author whether 15-bit X11 colors are rendered correctly or not!\n\n"); \
269 first = 0; \
270 } \
271 color = (b << 10) + (g << 5) + r; \
272 } else { \
273 /* Little endian (eg PC) X servers: */ \
274 color = (r << 10) + (g << 5) + b; \
275 } \
276 break; \
277 default: \
278 color = d->fb_window->x11_graycolor[15 * (r + g + b) / (255 * 3)].pixel; \
279 } \
280 if (x>=0 && x<d->x11_xsize && y>=0 && y<d->x11_ysize) \
281 XPutPixel(d->fb_window->fb_ximage, x, y, color); \
282 }
283 #else
284 /* If not WITH_X11: */
285 #define macro_put_pixel() { }
286 #endif
287
288
289 /*
290 * update_framebuffer():
291 *
292 * The framebuffer memory has been updated. This function tries to make
293 * sure that the XImage is also updated (1 or more pixels).
294 */
295 void update_framebuffer(struct vfb_data *d, int addr, int len)
296 {
297 int x, y, pixel, npixels;
298 long color_r, color_g, color_b;
299 #ifdef WITH_X11
300 long color;
301 #endif
302 int scaledown = d->vfb_scaledown;
303 int scaledownXscaledown = 1;
304
305 if (scaledown == 1) {
306 /* Which framebuffer pixel does addr correspond to? */
307 pixel = addr * 8 / d->bit_depth;
308 y = pixel / d->xsize;
309 x = pixel % d->xsize;
310
311 /* How many framebuffer pixels? */
312 npixels = len * 8 / d->bit_depth;
313 if (npixels == 0)
314 npixels = 1;
315
316 if (d->bit_depth < 8) {
317 for (pixel=0; pixel<npixels; pixel++) {
318 int fb_addr, c, r, g, b;
319 color_r = color_g = color_b = 0;
320
321 fb_addr = (y * d->xsize + x) * d->bit_depth;
322 /* fb_addr is now which _bit_ in
323 the framebuffer */
324
325 c = d->framebuffer[fb_addr >> 3];
326 fb_addr &= 7;
327
328 /* HPCmips is reverse: */
329 if (d->vfb_type == VFB_HPCMIPS)
330 fb_addr = 8 - d->bit_depth - fb_addr;
331
332 c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
333 /* c <<= (8 - d->bit_depth); */
334
335 r = d->rgb_palette[c*3 + 0];
336 g = d->rgb_palette[c*3 + 1];
337 b = d->rgb_palette[c*3 + 2];
338
339 macro_put_pixel();
340 x++;
341 }
342 } else if (d->bit_depth == 8) {
343 for (pixel=0; pixel<npixels; pixel++) {
344 int fb_addr, c, r, g, b;
345 color_r = color_g = color_b = 0;
346
347 fb_addr = y * d->xsize + x;
348 /* fb_addr is now which byte in framebuffer */
349 c = d->framebuffer[fb_addr];
350 r = d->rgb_palette[c*3 + 0];
351 g = d->rgb_palette[c*3 + 1];
352 b = d->rgb_palette[c*3 + 2];
353
354 macro_put_pixel();
355 x++;
356 }
357 } else { /* d->bit_depth > 8 */
358 for (pixel=0; pixel<npixels; pixel++) {
359 int fb_addr, r, g, b;
360 color_r = color_g = color_b = 0;
361
362 fb_addr = (y * d->xsize + x) * d->bit_depth;
363 /* fb_addr is now which byte in framebuffer */
364
365 /* > 8 bits color. */
366 fb_addr >>= 3;
367 switch (d->bit_depth) {
368 case 24:
369 r = d->framebuffer[fb_addr];
370 g = d->framebuffer[fb_addr + 1];
371 b = d->framebuffer[fb_addr + 2];
372 break;
373 /* TODO: copy to the scaledown code below */
374 case 16:
375 if (d->vfb_type == VFB_HPCMIPS) {
376 b = d->framebuffer[fb_addr] +
377 (d->framebuffer[fb_addr+1] << 8);
378
379 if (d->color32k) {
380 r = b >> 11;
381 g = b >> 5;
382 r = r & 31;
383 g = (g & 31) * 2;
384 b = b & 31;
385 } else {
386 r = (b >> 11) & 0x1f;
387 g = (b >> 5) & 0x3f;
388 b = b & 0x1f;
389 }
390 } else {
391 r = d->framebuffer[fb_addr] >> 3;
392 g = (d->framebuffer[fb_addr] << 5) +
393 (d->framebuffer[fb_addr + 1] >> 5);
394 b = d->framebuffer[fb_addr + 1] & 0x1f;
395 }
396
397 r *= 8;
398 g *= 4;
399 b *= 8;
400 break;
401 default:
402 r = g = b = random() & 255;
403 }
404
405 macro_put_pixel();
406 x++;
407 }
408 }
409
410 return;
411 }
412
413 /* scaledown != 1: */
414
415 scaledown = d->vfb_scaledown;
416 scaledownXscaledown = scaledown * scaledown;
417
418 /* Which framebuffer pixel does addr correspond to? */
419 pixel = addr * 8 / d->bit_depth;
420 y = pixel / d->xsize;
421 x = pixel % d->xsize;
422
423 /* How many framebuffer pixels? */
424 npixels = len * 8 / d->bit_depth;
425
426 /* Which x11 pixel? */
427 x /= scaledown;
428 y /= scaledown;
429
430 /* How many x11 pixels: */
431 npixels /= scaledown;
432 if (npixels == 0)
433 npixels = 1;
434
435 if (d->bit_depth < 8) {
436 for (pixel=0; pixel<npixels; pixel++) {
437 int subx, suby, r, g, b;
438 color_r = color_g = color_b = 0;
439 for (suby=0; suby<scaledown; suby++)
440 for (subx=0; subx<scaledown; subx++) {
441 int fb_x, fb_y, fb_addr, c;
442
443 fb_x = x * scaledown + subx;
444 fb_y = y * scaledown + suby;
445 fb_addr = fb_y * d->xsize + fb_x;
446 fb_addr = fb_addr * d->bit_depth;
447 /* fb_addr is now which _bit_ in
448 the framebuffer */
449
450 c = d->framebuffer[fb_addr >> 3];
451 fb_addr &= 7;
452
453 /* HPCmips is reverse: */
454 if (d->vfb_type == VFB_HPCMIPS)
455 fb_addr = 8 - d->bit_depth - fb_addr;
456
457 c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
458 /* c <<= (8 - d->bit_depth); */
459
460 r = d->rgb_palette[c*3 + 0];
461 g = d->rgb_palette[c*3 + 1];
462 b = d->rgb_palette[c*3 + 2];
463
464 color_r += r;
465 color_g += g;
466 color_b += b;
467 }
468
469 r = color_r / scaledownXscaledown;
470 g = color_g / scaledownXscaledown;
471 b = color_b / scaledownXscaledown;
472 macro_put_pixel();
473 x++;
474 }
475 } else if (d->bit_depth == 8) {
476 for (pixel=0; pixel<npixels; pixel++) {
477 int subx, suby, r, g, b;
478 color_r = color_g = color_b = 0;
479 for (suby=0; suby<scaledown; suby++)
480 for (subx=0; subx<scaledown; subx++) {
481 int fb_x, fb_y, fb_addr, c;
482
483 fb_x = x * scaledown + subx;
484 fb_y = y * scaledown + suby;
485 fb_addr = fb_y * d->xsize + fb_x;
486 /* fb_addr is which _byte_ in framebuffer */
487 c = d->framebuffer[fb_addr] * 3;
488 r = d->rgb_palette[c + 0];
489 g = d->rgb_palette[c + 1];
490 b = d->rgb_palette[c + 2];
491 color_r += r;
492 color_g += g;
493 color_b += b;
494 }
495
496 r = color_r / scaledownXscaledown;
497 g = color_g / scaledownXscaledown;
498 b = color_b / scaledownXscaledown;
499 macro_put_pixel();
500 x++;
501 }
502 } else {
503 /* Generic > 8 bit bit-depth: */
504 for (pixel=0; pixel<npixels; pixel++) {
505 int subx, suby, r, g, b;
506 color_r = color_g = color_b = 0;
507 for (suby=0; suby<scaledown; suby++)
508 for (subx=0; subx<scaledown; subx++) {
509 int fb_x, fb_y, fb_addr;
510
511 fb_x = x * scaledown + subx;
512 fb_y = y * scaledown + suby;
513 fb_addr = fb_y * d->xsize + fb_x;
514 fb_addr = (fb_addr * d->bit_depth) >> 3;
515 /* fb_addr is which _byte_ in framebuffer */
516
517 /* > 8 bits color. */
518 switch (d->bit_depth) {
519 case 24:
520 r = d->framebuffer[fb_addr];
521 g = d->framebuffer[fb_addr + 1];
522 b = d->framebuffer[fb_addr + 2];
523 break;
524 default:
525 r = g = b = random() & 255;
526 }
527 color_r += r;
528 color_g += g;
529 color_b += b;
530 }
531 r = color_r / scaledownXscaledown;
532 g = color_g / scaledownXscaledown;
533 b = color_b / scaledownXscaledown;
534 macro_put_pixel();
535 x++;
536 }
537 }
538 }
539
540
541 /*
542 * dev_fb_tick():
543 *
544 */
545 void dev_fb_tick(struct cpu *cpu, void *extra)
546 {
547 struct vfb_data *d = extra;
548 #ifdef WITH_X11
549 int need_to_flush_x11 = 0;
550 int need_to_redraw_cursor = 0;
551 #endif
552
553 if (!cpu->machine->use_x11)
554 return;
555
556 #ifdef BINTRANS
557 do {
558 uint64_t low = -1, high;
559 int x, y;
560
561 memory_device_bintrans_access(cpu, cpu->mem,
562 extra, &low, &high);
563 if ((int64_t)low == -1)
564 break;
565
566 /* printf("low=%016llx high=%016llx\n",
567 (long long)low, (long long)high); */
568
569 x = (low % d->bytes_per_line) * 8 / d->bit_depth;
570 y = low / d->bytes_per_line;
571 if (x < d->update_x1 || d->update_x1 == -1)
572 d->update_x1 = x;
573 if (x > d->update_x2 || d->update_x2 == -1)
574 d->update_x2 = x;
575 if (y < d->update_y1 || d->update_y1 == -1)
576 d->update_y1 = y;
577 if (y > d->update_y2 || d->update_y2 == -1)
578 d->update_y2 = y;
579
580 x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
581 y = (low+7) / d->bytes_per_line;
582 if (x < d->update_x1 || d->update_x1 == -1)
583 d->update_x1 = x;
584 if (x > d->update_x2 || d->update_x2 == -1)
585 d->update_x2 = x;
586 if (y < d->update_y1 || d->update_y1 == -1)
587 d->update_y1 = y;
588 if (y > d->update_y2 || d->update_y2 == -1)
589 d->update_y2 = y;
590
591 x = (high % d->bytes_per_line) * 8 / d->bit_depth;
592 y = high / d->bytes_per_line;
593 if (x < d->update_x1 || d->update_x1 == -1)
594 d->update_x1 = x;
595 if (x > d->update_x2 || d->update_x2 == -1)
596 d->update_x2 = x;
597 if (y < d->update_y1 || d->update_y1 == -1)
598 d->update_y1 = y;
599 if (y > d->update_y2 || d->update_y2 == -1)
600 d->update_y2 = y;
601
602 x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
603 y = (high+7) / d->bytes_per_line;
604 if (x < d->update_x1 || d->update_x1 == -1)
605 d->update_x1 = x;
606 if (x > d->update_x2 || d->update_x2 == -1)
607 d->update_x2 = x;
608 if (y < d->update_y1 || d->update_y1 == -1)
609 d->update_y1 = y;
610 if (y > d->update_y2 || d->update_y2 == -1)
611 d->update_y2 = y;
612
613 /*
614 * An update covering more than one line will automatically
615 * force an update of all the affected lines:
616 */
617 if (d->update_y1 != d->update_y2) {
618 d->update_x1 = 0;
619 d->update_x2 = d->xsize-1;
620 }
621 } while (0);
622 #endif
623
624 #ifdef WITH_X11
625 /* Do we need to redraw the cursor? */
626 if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
627 d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
628 d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
629 d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
630 d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
631 need_to_redraw_cursor = 1;
632
633 if (d->update_x2 != -1) {
634 if ( (d->update_x1 >= d->fb_window->OLD_cursor_x &&
635 d->update_x1 < (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ||
636 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
637 d->update_x2 < (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ||
638 (d->update_x1 < d->fb_window->OLD_cursor_x &&
639 d->update_x2 >= (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ) {
640 if ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
641 d->update_y1 < (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) ||
642 (d->update_y2 >= d->fb_window->OLD_cursor_y &&
643 d->update_y2 < (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) ||
644 (d->update_y1 < d->fb_window->OLD_cursor_y &&
645 d->update_y2 >= (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) )
646 need_to_redraw_cursor = 1;
647 }
648 }
649
650 if (need_to_redraw_cursor) {
651 /* Remove old cursor, if any: */
652 if (d->fb_window->OLD_cursor_on) {
653 XPutImage(d->fb_window->x11_display,
654 d->fb_window->x11_fb_window,
655 d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
656 d->fb_window->OLD_cursor_x/d->vfb_scaledown,
657 d->fb_window->OLD_cursor_y/d->vfb_scaledown,
658 d->fb_window->OLD_cursor_x/d->vfb_scaledown,
659 d->fb_window->OLD_cursor_y/d->vfb_scaledown,
660 d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
661 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown + 1);
662 }
663 }
664 #endif
665
666 if (d->update_x2 != -1) {
667 int y, addr, addr2, q = d->vfb_scaledown;
668
669 if (d->update_x1 >= d->visible_xsize) d->update_x1 = d->visible_xsize - 1;
670 if (d->update_x2 >= d->visible_xsize) d->update_x2 = d->visible_xsize - 1;
671 if (d->update_y1 >= d->visible_ysize) d->update_y1 = d->visible_ysize - 1;
672 if (d->update_y2 >= d->visible_ysize) d->update_y2 = d->visible_ysize - 1;
673
674 /* Without these, we might miss the right most / bottom pixel: */
675 d->update_x2 += (q - 1);
676 d->update_y2 += (q - 1);
677
678 d->update_x1 = d->update_x1 / q * q;
679 d->update_x2 = d->update_x2 / q * q;
680 d->update_y1 = d->update_y1 / q * q;
681 d->update_y2 = d->update_y2 / q * q;
682
683 addr = d->update_y1 * d->bytes_per_line + d->update_x1 * d->bit_depth / 8;
684 addr2 = d->update_y1 * d->bytes_per_line + d->update_x2 * d->bit_depth / 8;
685
686 for (y=d->update_y1; y<=d->update_y2; y+=q) {
687 update_framebuffer(d, addr, addr2 - addr);
688 addr += d->bytes_per_line * q;
689 addr2 += d->bytes_per_line * q;
690 }
691
692 #ifdef WITH_X11
693 XPutImage(d->fb_window->x11_display, d->fb_window->x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
694 d->update_x1/d->vfb_scaledown, d->update_y1/d->vfb_scaledown,
695 d->update_x1/d->vfb_scaledown, d->update_y1/d->vfb_scaledown,
696 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
697 (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
698
699 need_to_flush_x11 = 1;
700 #endif
701
702 d->update_x1 = d->update_y1 = 99999;
703 d->update_x2 = d->update_y2 = -1;
704 }
705
706 #ifdef WITH_X11
707 if (need_to_redraw_cursor) {
708 /* Paint new cursor: */
709 if (d->fb_window->cursor_on) {
710 x11_redraw_cursor(cpu->machine, d->fb_window->fb_number);
711 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
712 d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
713 d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
714 d->fb_window->OLD_cursor_xsize = d->fb_window->cursor_xsize;
715 d->fb_window->OLD_cursor_ysize = d->fb_window->cursor_ysize;
716 }
717 }
718 #endif
719
720 #ifdef WITH_X11
721 if (need_to_flush_x11)
722 XFlush(d->fb_window->x11_display);
723 #endif
724 }
725
726
727 /*
728 * dev_fb_access():
729 */
730 int dev_fb_access(struct cpu *cpu, struct memory *mem,
731 uint64_t relative_addr, unsigned char *data, size_t len,
732 int writeflag, void *extra)
733 {
734 struct vfb_data *d = extra;
735 int i;
736
737 #ifdef FB_DEBUG
738 if (writeflag == MEM_WRITE) { if (data[0]) {
739 fatal("[ dev_fb: write to addr=%08lx, data = ",
740 (long)relative_addr);
741 for (i=0; i<len; i++)
742 fatal("%02x ", data[i]);
743 fatal("]\n");
744 } else {
745 fatal("[ dev_fb: read from addr=%08lx, data = ",
746 (long)relative_addr);
747 for (i=0; i<len; i++)
748 fatal("%02x ", d->framebuffer[relative_addr + i]);
749 fatal("]\n");
750 }
751 #endif
752
753 /* See if a write actually modifies the framebuffer contents: */
754 if (writeflag == MEM_WRITE) {
755 for (i=0; i<len; i++) {
756 if (data[i] != d->framebuffer[relative_addr + i])
757 break;
758
759 /* If all bytes are equal to what is already stored
760 in the framebuffer, then simply return: */
761 if (i==len-1)
762 return 1;
763 }
764 }
765
766 /*
767 * If the framebuffer is modified, then we should keep a track
768 * of which area(s) we modify, so that the display isn't updated
769 * unnecessarily.
770 */
771 if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
772 int x, y, x2,y2;
773
774 x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
775 y = relative_addr / d->bytes_per_line;
776 x2 = ((relative_addr + len) % d->bytes_per_line)
777 * 8 / d->bit_depth;
778 y2 = (relative_addr + len) / d->bytes_per_line;
779
780 if (x < d->update_x1 || d->update_x1 == -1)
781 d->update_x1 = x;
782 if (x > d->update_x2 || d->update_x2 == -1)
783 d->update_x2 = x;
784
785 if (y < d->update_y1 || d->update_y1 == -1)
786 d->update_y1 = y;
787 if (y > d->update_y2 || d->update_y2 == -1)
788 d->update_y2 = y;
789
790 if (x2 < d->update_x1 || d->update_x1 == -1)
791 d->update_x1 = x2;
792 if (x2 > d->update_x2 || d->update_x2 == -1)
793 d->update_x2 = x2;
794
795 if (y2 < d->update_y1 || d->update_y1 == -1)
796 d->update_y1 = y2;
797 if (y2 > d->update_y2 || d->update_y2 == -1)
798 d->update_y2 = y2;
799
800 /*
801 * An update covering more than one line will automatically
802 * force an update of all the affected lines:
803 */
804 if (y != y2) {
805 d->update_x1 = 0;
806 d->update_x2 = d->xsize-1;
807 }
808 }
809
810 /*
811 * Read from/write to the framebuffer:
812 * (TODO: take the color_plane_mask into account)
813 *
814 * Calling memcpy() is probably overkill, as it usually is just one
815 * or a few bytes that are read/written at a time.
816 */
817 if (writeflag == MEM_WRITE) {
818 if (len > 8)
819 memcpy(d->framebuffer + relative_addr, data, len);
820 else
821 for (i=0; i<len; i++)
822 d->framebuffer[relative_addr + i] = data[i];
823 } else {
824 if (len > 8)
825 memcpy(data, d->framebuffer + relative_addr, len);
826 else
827 for (i=0; i<len; i++)
828 data[i] = d->framebuffer[relative_addr + i];
829 }
830
831 return 1;
832 }
833
834
835 /*
836 * dev_fb_init():
837 *
838 * xsize and ysize are ignored if vfb_type is VFB_DEC_VFB01 or 02.
839 */
840 struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
841 uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
842 int xsize, int ysize, int bit_depth, char *name, int logo)
843 {
844 struct vfb_data *d;
845 size_t size;
846 int x, y;
847 char title[400];
848 char *name2;
849 int flags;
850
851 d = malloc(sizeof(struct vfb_data));
852 if (d == NULL) {
853 fprintf(stderr, "out of memory\n");
854 exit(1);
855 }
856 memset(d, 0, sizeof(struct vfb_data));
857
858 d->vfb_type = vfb_type;
859
860 /* Defaults: */
861 d->xsize = xsize; d->visible_xsize = visible_xsize;
862 d->ysize = ysize; d->visible_ysize = visible_ysize;
863
864 d->bit_depth = bit_depth;
865
866 if (bit_depth == 15) {
867 d->color32k = 1;
868 bit_depth = d->bit_depth = 16;
869 }
870
871 /* Specific types: */
872 switch (vfb_type) {
873 case VFB_DEC_VFB01:
874 /* DECstation VFB01 (monochrome) */
875 d->xsize = 2048; d->visible_xsize = 1024;
876 d->ysize = 1024; d->visible_ysize = 864;
877 d->bit_depth = 1;
878 break;
879 case VFB_DEC_VFB02:
880 /* DECstation VFB02 (color) */
881 d->xsize = 1024; d->visible_xsize = 1024;
882 d->ysize = 1024; d->visible_ysize = 864;
883 d->bit_depth = 8;
884 break;
885 case VFB_DEC_MAXINE:
886 /* DECstation Maxine (1024x768x8) */
887 d->xsize = 1024; d->visible_xsize = d->xsize;
888 d->ysize = 768; d->visible_ysize = d->ysize;
889 d->bit_depth = 8;
890 break;
891 case VFB_PLAYSTATION2:
892 /* Playstation 2 */
893 d->xsize = xsize; d->visible_xsize = d->xsize;
894 d->ysize = ysize; d->visible_ysize = d->ysize;
895 d->bit_depth = 24;
896 break;
897 default:
898 ;
899 }
900
901 if (d->bit_depth == 2 || d->bit_depth == 4)
902 set_grayscale_palette(d, 1 << d->bit_depth);
903 else if (d->bit_depth == 8 || d->bit_depth == 1)
904 set_blackwhite_palette(d, 1 << d->bit_depth);
905
906 d->vfb_scaledown = machine->x11_scaledown;
907
908 d->bytes_per_line = d->xsize * d->bit_depth / 8;
909 size = d->ysize * d->bytes_per_line;
910
911 d->framebuffer = malloc(size);
912 if (d->framebuffer == NULL) {
913 fprintf(stderr, "out of memory\n");
914 exit(1);
915 }
916
917 /* Clear the framebuffer (all black pixels): */
918 d->framebuffer_size = size;
919 memset(d->framebuffer, 0, size);
920
921 d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
922 d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
923
924 d->update_x1 = d->update_y1 = 99999;
925 d->update_x2 = d->update_y2 = -1;
926
927
928 /* A nice bootup logo: */
929 if (logo) {
930 int logo_bottom_margin = LOGO_BOTTOM_MARGIN;
931
932 d->update_x1 = 0;
933 d->update_x2 = LOGO_XSIZE-1;
934 d->update_y1 = d->visible_ysize-LOGO_YSIZE-logo_bottom_margin;
935 d->update_y2 = d->visible_ysize-logo_bottom_margin;
936 for (y=0; y<LOGO_YSIZE; y++)
937 for (x=0; x<LOGO_XSIZE; x++) {
938 int s, a = ((y + d->visible_ysize - LOGO_YSIZE
939 - logo_bottom_margin)*d->xsize + x)
940 * d->bit_depth / 8;
941 int b = fb_logo[(y*LOGO_XSIZE+x) / 8] &
942 (128 >> (x&7));
943 for (s=0; s<d->bit_depth / 8; s++)
944 d->framebuffer[a+s] = b? 0 : 255;
945 }
946 }
947
948 snprintf(title, sizeof(title), "GXemul: %ix%ix%i %s framebuffer",
949 d->visible_xsize, d->visible_ysize, d->bit_depth, name);
950 title[sizeof(title)-1] = '\0';
951
952 #ifdef WITH_X11
953 if (machine->use_x11)
954 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
955 title, machine->x11_scaledown, machine);
956 else
957 #endif
958 d->fb_window = NULL;
959
960 name2 = malloc(strlen(name) + 10);
961 if (name2 == NULL) {
962 fprintf(stderr, "out of memory in dev_fb_init()\n");
963 exit(1);
964 }
965 sprintf(name2, "fb [%s]", name);
966
967 flags = MEM_DEFAULT;
968 if ((baseaddr & 0xfff) == 0)
969 flags = MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK;
970
971 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
972 d, flags, d->framebuffer);
973
974 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT);
975 return d;
976 }
977

  ViewVC Help
Powered by ViewVC 1.1.26