/[gxemul]/upstream/0.3.1/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 /upstream/0.3.1/devices/dev_fb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 27326 byte(s)
0.3.1
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