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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 21 - (show annotations)
Mon Oct 8 16:19:28 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 29543 byte(s)
0.3.7
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.110 2005/11/13 00:14:08 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)
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
71 /* #define FB_DEBUG */
72
73 /*
74 * set_grayscale_palette():
75 *
76 * Fill d->rgb_palette with grayscale values. ncolors should
77 * be something like 2, 4, 16, or 256.
78 */
79 void set_grayscale_palette(struct vfb_data *d, int ncolors)
80 {
81 int i, gray;
82
83 for (i=0; i<256; i++) {
84 gray = 255*i/(ncolors-1);
85 d->rgb_palette[i*3 + 0] = gray;
86 d->rgb_palette[i*3 + 1] = gray;
87 d->rgb_palette[i*3 + 2] = gray;
88 }
89 }
90
91
92 /*
93 * set_blackwhite_palette():
94 *
95 * Set color 0 = black, all others to white.
96 */
97 void set_blackwhite_palette(struct vfb_data *d, int ncolors)
98 {
99 int i, gray;
100
101 for (i=0; i<256; i++) {
102 gray = i==0? 0 : 255;
103 d->rgb_palette[i*3 + 0] = gray;
104 d->rgb_palette[i*3 + 1] = gray;
105 d->rgb_palette[i*3 + 2] = gray;
106 }
107 }
108
109
110 /*
111 * dev_fb_resize():
112 *
113 * Resize a framebuffer window. (This functionality is probably a bit buggy,
114 * because I didn't think of including it from the start.)
115 */
116 void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
117 {
118 unsigned char *new_framebuffer;
119 int y, new_bytes_per_line;
120 size_t size;
121
122 if (d == NULL) {
123 fatal("dev_fb_resize(): d == NULL\n");
124 return;
125 }
126
127 new_bytes_per_line = new_xsize * d->bit_depth / 8;
128 size = new_ysize * new_bytes_per_line;
129
130 new_framebuffer = malloc(size);
131 if (new_framebuffer == NULL) {
132 fprintf(stderr, "dev_fb_resize(): out of memory\n");
133 exit(1);
134 }
135
136 /* Copy the old framebuffer to the new: */
137 if (d->framebuffer != NULL) {
138 for (y=0; y<new_ysize; y++) {
139 size_t fromofs = d->bytes_per_line * y;
140 size_t toofs = new_bytes_per_line * y;
141 size_t len_to_copy = d->bytes_per_line <
142 new_bytes_per_line? d->bytes_per_line
143 : new_bytes_per_line;
144 memset(new_framebuffer + toofs, 0, new_bytes_per_line);
145 if (y < d->x11_ysize)
146 memmove(new_framebuffer + toofs,
147 d->framebuffer + fromofs, len_to_copy);
148 }
149
150 free(d->framebuffer);
151 }
152
153 d->framebuffer = new_framebuffer;
154 d->framebuffer_size = size;
155
156 if (new_xsize > d->x11_xsize || new_ysize > d->x11_ysize) {
157 d->update_x1 = d->update_y1 = 0;
158 d->update_x2 = new_xsize - 1;
159 d->update_y2 = new_ysize - 1;
160 }
161
162 d->bytes_per_line = new_bytes_per_line;
163 d->x11_xsize = d->visible_xsize = new_xsize;
164 d->x11_ysize = d->visible_ysize = new_ysize;
165
166 #ifdef WITH_X11
167 if (d->fb_window != NULL)
168 x11_fb_resize(d->fb_window, new_xsize, new_ysize);
169 #endif
170 }
171
172
173 /*
174 * dev_fb_setcursor():
175 */
176 void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
177 int cursor_xsize, int cursor_ysize)
178 {
179 if (cursor_x < 0)
180 cursor_x = 0;
181 if (cursor_y < 0)
182 cursor_y = 0;
183 if (cursor_x + cursor_xsize >= d->xsize)
184 cursor_x = d->xsize - cursor_xsize;
185 if (cursor_y + cursor_ysize >= d->ysize)
186 cursor_y = d->ysize - cursor_ysize;
187
188 #ifdef WITH_X11
189 if (d->fb_window != NULL) {
190 d->fb_window->cursor_x = cursor_x;
191 d->fb_window->cursor_y = cursor_y;
192 d->fb_window->cursor_on = on;
193 d->fb_window->cursor_xsize = cursor_xsize;
194 d->fb_window->cursor_ysize = cursor_ysize;
195 }
196 #endif
197
198 if (d->fb_window != NULL)
199 console_set_framebuffer_mouse(cursor_x, cursor_y,
200 d->fb_window->fb_number);
201
202 /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
203 cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
204 }
205
206
207 /*
208 * framebuffer_blockcopyfill():
209 *
210 * This function should be used by devices that are capable of doing
211 * block copy/fill.
212 *
213 * If fillflag is non-zero, then fill_[rgb] should contain the color
214 * with which to fill.
215 *
216 * If fillflag is zero, copy mode is used, and from_[xy] should contain
217 * the offset on the framebuffer where we should copy from.
218 *
219 * NOTE: Overlapping copies are undefined!
220 */
221 void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
222 int fill_g, int fill_b, int x1, int y1, int x2, int y2,
223 int from_x, int from_y)
224 {
225 int y;
226 long from_ofs, dest_ofs, linelen;
227
228 if (fillflag)
229 debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
230 "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
231 else
232 debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
233 "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
234
235 /* Clip x: */
236 if (x1 < 0) x1 = 0;
237 if (x1 >= d->xsize) x1 = d->xsize-1;
238 if (x2 < 0) x2 = 0;
239 if (x2 >= d->xsize) x2 = d->xsize-1;
240
241 dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
242 linelen = (x2-x1 + 1) * (d->bit_depth/8);
243 /* NOTE: linelen is nr of bytes, not pixels */
244
245 if (fillflag) {
246 for (y=y1; y<=y2; y++) {
247 if (y>=0 && y<d->ysize) {
248 int x;
249 char buf[8192 * 3];
250 if (d->bit_depth == 24)
251 for (x=0; x<linelen; x+=3) {
252 buf[x] = fill_r;
253 buf[x+1] = fill_g;
254 buf[x+2] = fill_b;
255 }
256 else
257 printf("TODO: fill for non-24-bit"
258 " modes\n");
259
260 memmove(d->framebuffer + dest_ofs, buf,
261 linelen);
262 }
263
264 dest_ofs += d->bytes_per_line;
265 }
266 } else {
267 from_ofs = d->bytes_per_line * from_y +
268 (d->bit_depth/8) * from_x;
269
270 for (y=y1; y<=y2; y++) {
271 if (y>=0 && y<d->ysize)
272 memmove(d->framebuffer + dest_ofs,
273 d->framebuffer + from_ofs, linelen);
274
275 from_ofs += d->bytes_per_line;
276 dest_ofs += d->bytes_per_line;
277 }
278 }
279
280 if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
281 if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
282 if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
283 if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
284
285 if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
286 if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
287 if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
288 if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
289 }
290
291
292 #ifdef WITH_X11
293 #define macro_put_pixel() { \
294 /* Combine the color into an X11 long and display it: */ \
295 /* TODO: construct color in a more portable way: */ \
296 switch (d->fb_window->x11_screen_depth) { \
297 case 24: \
298 if (d->fb_window->fb_ximage->byte_order) \
299 color = (b << 16) + (g << 8) + r; \
300 else \
301 color = (r << 16) + (g << 8) + b; \
302 break; \
303 case 16: \
304 r >>= 3; g >>= 2; b >>= 3; \
305 if (d->fb_window->fb_ximage->byte_order) { \
306 /* Big endian 16-bit X server: */ \
307 static int first = 1; \
308 if (first) { \
309 fprintf(stderr, "\n*** Please report " \
310 "to the author whether 16-bit X11 " \
311 "colors are rendered correctly or " \
312 "not!\n\n"); \
313 first = 0; \
314 } \
315 color = (b << 11) + (g << 5) + r; \
316 } else { \
317 /* Little endian (eg PC) X servers: */ \
318 color = (r << 11) + (g << 5) + b; \
319 } \
320 break; \
321 case 15: \
322 r >>= 3; g >>= 3; b >>= 3; \
323 if (d->fb_window->fb_ximage->byte_order) { \
324 /* Big endian 15-bit X server: */ \
325 static int first = 1; \
326 if (first) { \
327 fprintf(stderr, "\n*** Please report " \
328 "to the author whether 15-bit X11 " \
329 "colors are rendered correctly or " \
330 "not!\n\n"); \
331 first = 0; \
332 } \
333 color = (b << 10) + (g << 5) + r; \
334 } else { \
335 /* Little endian (eg PC) X servers: */ \
336 color = (r << 10) + (g << 5) + b; \
337 } \
338 break; \
339 default: \
340 color = d->fb_window->x11_graycolor[15 * (r + g + b) \
341 / (255 * 3)].pixel; \
342 } \
343 if (x>=0 && x<d->x11_xsize && y>=0 && y<d->x11_ysize) \
344 XPutPixel(d->fb_window->fb_ximage, x, y, color); \
345 }
346 #else
347 /* If not WITH_X11: */
348 #define macro_put_pixel() { }
349 #endif
350
351
352 /*
353 * update_framebuffer():
354 *
355 * The framebuffer memory has been updated. This function tries to make
356 * sure that the XImage is also updated (1 or more pixels).
357 */
358 void update_framebuffer(struct vfb_data *d, int addr, int len)
359 {
360 int x, y, pixel, npixels;
361 long color_r, color_g, color_b;
362 #ifdef WITH_X11
363 long color;
364 #endif
365 int scaledown = d->vfb_scaledown;
366 int scaledownXscaledown = 1;
367
368 if (scaledown == 1) {
369 /* Which framebuffer pixel does addr correspond to? */
370 pixel = addr * 8 / d->bit_depth;
371 y = pixel / d->xsize;
372 x = pixel % d->xsize;
373
374 /* How many framebuffer pixels? */
375 npixels = len * 8 / d->bit_depth;
376 if (npixels == 0)
377 npixels = 1;
378
379 if (d->bit_depth < 8) {
380 for (pixel=0; pixel<npixels; pixel++) {
381 int fb_addr, c, r, g, b;
382 color_r = color_g = color_b = 0;
383
384 fb_addr = (y * d->xsize + x) * d->bit_depth;
385 /* fb_addr is now which _bit_ in
386 the framebuffer */
387
388 c = d->framebuffer[fb_addr >> 3];
389 fb_addr &= 7;
390
391 /* HPC is reverse: */
392 if (d->vfb_type == VFB_HPC)
393 fb_addr = 8 - d->bit_depth - fb_addr;
394
395 c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
396 /* c <<= (8 - d->bit_depth); */
397
398 r = d->rgb_palette[c*3 + 0];
399 g = d->rgb_palette[c*3 + 1];
400 b = d->rgb_palette[c*3 + 2];
401
402 macro_put_pixel();
403 x++;
404 }
405 } else if (d->bit_depth == 8) {
406 for (pixel=0; pixel<npixels; pixel++) {
407 int fb_addr, c, r, g, b;
408 color_r = color_g = color_b = 0;
409
410 fb_addr = y * d->xsize + x;
411 /* fb_addr is now which byte in framebuffer */
412 c = d->framebuffer[fb_addr];
413 r = d->rgb_palette[c*3 + 0];
414 g = d->rgb_palette[c*3 + 1];
415 b = d->rgb_palette[c*3 + 2];
416
417 macro_put_pixel();
418 x++;
419 }
420 } else { /* d->bit_depth > 8 */
421 for (pixel=0; pixel<npixels; pixel++) {
422 int fb_addr, r, g, b;
423 color_r = color_g = color_b = 0;
424
425 fb_addr = (y * d->xsize + x) * d->bit_depth;
426 /* fb_addr is now which byte in framebuffer */
427
428 /* > 8 bits color. */
429 fb_addr >>= 3;
430 switch (d->bit_depth) {
431 case 24:
432 r = d->framebuffer[fb_addr];
433 g = d->framebuffer[fb_addr + 1];
434 b = d->framebuffer[fb_addr + 2];
435 break;
436 /* TODO: copy to the scaledown code below */
437 case 16:
438 if (d->vfb_type == VFB_HPC) {
439 b = d->framebuffer[fb_addr] +
440 (d->framebuffer[fb_addr+1]
441 << 8);
442
443 if (d->color32k) {
444 r = b >> 11;
445 g = b >> 5;
446 r = r & 31;
447 g = (g & 31) * 2;
448 b = b & 31;
449 } else if (d->psp_15bit) {
450 int tmp;
451 r = (b >> 10) & 0x1f;
452 g = (b >> 5) & 0x1f;
453 b = b & 0x1f;
454 g <<= 1;
455 tmp = r; r = b; b = tmp;
456 } else {
457 r = (b >> 11) & 0x1f;
458 g = (b >> 5) & 0x3f;
459 b = b & 0x1f;
460 }
461 } else {
462 r = d->framebuffer[fb_addr] >> 3;
463 g = (d->framebuffer[fb_addr] << 5) +
464 (d->framebuffer[fb_addr + 1] >>5);
465 b = d->framebuffer[fb_addr + 1]&31;
466 }
467
468 r *= 8;
469 g *= 4;
470 b *= 8;
471 break;
472 default:
473 r = g = b = random() & 255;
474 }
475
476 macro_put_pixel();
477 x++;
478 }
479 }
480
481 return;
482 }
483
484 /* scaledown > 1: */
485
486 scaledown = d->vfb_scaledown;
487 scaledownXscaledown = scaledown * scaledown;
488
489 /* Which framebuffer pixel does addr correspond to? */
490 pixel = addr * 8 / d->bit_depth;
491 y = pixel / d->xsize;
492 x = pixel % d->xsize;
493
494 /* How many framebuffer pixels? */
495 npixels = len * 8 / d->bit_depth;
496
497 /* Which x11 pixel? */
498 x /= scaledown;
499 y /= scaledown;
500
501 /* How many x11 pixels: */
502 npixels /= scaledown;
503 if (npixels == 0)
504 npixels = 1;
505
506 if (d->bit_depth < 8) {
507 for (pixel=0; pixel<npixels; pixel++) {
508 int subx, suby, r, g, b;
509 color_r = color_g = color_b = 0;
510 for (suby=0; suby<scaledown; suby++)
511 for (subx=0; subx<scaledown; subx++) {
512 int fb_x, fb_y, fb_addr, c;
513
514 fb_x = x * scaledown + subx;
515 fb_y = y * scaledown + suby;
516 fb_addr = fb_y * d->xsize + fb_x;
517 fb_addr = fb_addr * d->bit_depth;
518 /* fb_addr is now which _bit_ in
519 the framebuffer */
520
521 c = d->framebuffer[fb_addr >> 3];
522 fb_addr &= 7;
523
524 /* HPC is reverse: */
525 if (d->vfb_type == VFB_HPC)
526 fb_addr = 8 - d->bit_depth - fb_addr;
527
528 c = (c >> fb_addr) & ((1<<d->bit_depth) - 1);
529 /* c <<= (8 - d->bit_depth); */
530
531 r = d->rgb_palette[c*3 + 0];
532 g = d->rgb_palette[c*3 + 1];
533 b = d->rgb_palette[c*3 + 2];
534
535 color_r += r;
536 color_g += g;
537 color_b += b;
538 }
539
540 r = color_r / scaledownXscaledown;
541 g = color_g / scaledownXscaledown;
542 b = color_b / scaledownXscaledown;
543 macro_put_pixel();
544 x++;
545 }
546 } else if (d->bit_depth == 8) {
547 for (pixel=0; pixel<npixels; pixel++) {
548 int subx, suby, r, g, b;
549 color_r = color_g = color_b = 0;
550 for (suby=0; suby<scaledown; suby++)
551 for (subx=0; subx<scaledown; subx++) {
552 int fb_x, fb_y, fb_addr, c;
553
554 fb_x = x * scaledown + subx;
555 fb_y = y * scaledown + suby;
556 fb_addr = fb_y * d->xsize + fb_x;
557 /* fb_addr is which _byte_ in framebuffer */
558 c = d->framebuffer[fb_addr] * 3;
559 r = d->rgb_palette[c + 0];
560 g = d->rgb_palette[c + 1];
561 b = d->rgb_palette[c + 2];
562 color_r += r;
563 color_g += g;
564 color_b += b;
565 }
566
567 r = color_r / scaledownXscaledown;
568 g = color_g / scaledownXscaledown;
569 b = color_b / scaledownXscaledown;
570 macro_put_pixel();
571 x++;
572 }
573 } else {
574 /* Generic > 8 bit bit-depth: */
575 for (pixel=0; pixel<npixels; pixel++) {
576 int subx, suby, r, g, b;
577 color_r = color_g = color_b = 0;
578 for (suby=0; suby<scaledown; suby++)
579 for (subx=0; subx<scaledown; subx++) {
580 int fb_x, fb_y, fb_addr;
581
582 fb_x = x * scaledown + subx;
583 fb_y = y * scaledown + suby;
584 fb_addr = fb_y * d->xsize + fb_x;
585 fb_addr = (fb_addr * d->bit_depth) >> 3;
586 /* fb_addr is which _byte_ in framebuffer */
587
588 /* > 8 bits color. */
589 switch (d->bit_depth) {
590 case 24:
591 r = d->framebuffer[fb_addr];
592 g = d->framebuffer[fb_addr + 1];
593 b = d->framebuffer[fb_addr + 2];
594 break;
595 default:
596 r = g = b = random() & 255;
597 }
598 color_r += r;
599 color_g += g;
600 color_b += b;
601 }
602 r = color_r / scaledownXscaledown;
603 g = color_g / scaledownXscaledown;
604 b = color_b / scaledownXscaledown;
605 macro_put_pixel();
606 x++;
607 }
608 }
609 }
610
611
612 /*
613 * dev_fb_tick():
614 *
615 */
616 void dev_fb_tick(struct cpu *cpu, void *extra)
617 {
618 struct vfb_data *d = extra;
619 #ifdef WITH_X11
620 int need_to_flush_x11 = 0;
621 int need_to_redraw_cursor = 0;
622 #endif
623
624 if (!cpu->machine->use_x11)
625 return;
626
627 do {
628 uint64_t high, low = (uint64_t)(int64_t) -1;
629 int x, y;
630
631 memory_device_dyntrans_access(cpu, cpu->mem,
632 extra, &low, &high);
633 if ((int64_t)low == -1)
634 break;
635
636 /* printf("low=%016llx high=%016llx\n",
637 (long long)low, (long long)high); */
638
639 x = (low % d->bytes_per_line) * 8 / d->bit_depth;
640 y = low / d->bytes_per_line;
641 if (x < d->update_x1 || d->update_x1 == -1)
642 d->update_x1 = x;
643 if (x > d->update_x2 || d->update_x2 == -1)
644 d->update_x2 = x;
645 if (y < d->update_y1 || d->update_y1 == -1)
646 d->update_y1 = y;
647 if (y > d->update_y2 || d->update_y2 == -1)
648 d->update_y2 = y;
649
650 x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
651 y = (low+7) / d->bytes_per_line;
652 if (x < d->update_x1 || d->update_x1 == -1)
653 d->update_x1 = x;
654 if (x > d->update_x2 || d->update_x2 == -1)
655 d->update_x2 = x;
656 if (y < d->update_y1 || d->update_y1 == -1)
657 d->update_y1 = y;
658 if (y > d->update_y2 || d->update_y2 == -1)
659 d->update_y2 = y;
660
661 x = (high % d->bytes_per_line) * 8 / d->bit_depth;
662 y = high / d->bytes_per_line;
663 if (x < d->update_x1 || d->update_x1 == -1)
664 d->update_x1 = x;
665 if (x > d->update_x2 || d->update_x2 == -1)
666 d->update_x2 = x;
667 if (y < d->update_y1 || d->update_y1 == -1)
668 d->update_y1 = y;
669 if (y > d->update_y2 || d->update_y2 == -1)
670 d->update_y2 = y;
671
672 x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
673 y = (high+7) / d->bytes_per_line;
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 if (y < d->update_y1 || d->update_y1 == -1)
679 d->update_y1 = y;
680 if (y > d->update_y2 || d->update_y2 == -1)
681 d->update_y2 = y;
682
683 /*
684 * An update covering more than one line will automatically
685 * force an update of all the affected lines:
686 */
687 if (d->update_y1 != d->update_y2) {
688 d->update_x1 = 0;
689 d->update_x2 = d->xsize-1;
690 }
691 } while (0);
692
693 #ifdef WITH_X11
694 /* Do we need to redraw the cursor? */
695 if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
696 d->fb_window->cursor_x != d->fb_window->OLD_cursor_x ||
697 d->fb_window->cursor_y != d->fb_window->OLD_cursor_y ||
698 d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize ||
699 d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize)
700 need_to_redraw_cursor = 1;
701
702 if (d->update_x2 != -1) {
703 if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
704 d->update_x1 < (d->fb_window->OLD_cursor_x +
705 d->fb_window->OLD_cursor_xsize)) ||
706 (d->update_x2 >= d->fb_window->OLD_cursor_x &&
707 d->update_x2 < (d->fb_window->OLD_cursor_x +
708 d->fb_window->OLD_cursor_xsize)) ||
709 (d->update_x1 < d->fb_window->OLD_cursor_x &&
710 d->update_x2 >= (d->fb_window->OLD_cursor_x +
711 d->fb_window->OLD_cursor_xsize)) ) &&
712 ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
713 d->update_y1 < (d->fb_window->OLD_cursor_y +
714 d->fb_window->OLD_cursor_ysize)) ||
715 (d->update_y2 >= d->fb_window->OLD_cursor_y &&
716 d->update_y2 < (d->fb_window->OLD_cursor_y +
717 d->fb_window->OLD_cursor_ysize)) ||
718 (d->update_y1 < d->fb_window->OLD_cursor_y &&
719 d->update_y2 >= (d->fb_window->OLD_cursor_y +
720 d->fb_window->OLD_cursor_ysize)) ) )
721 need_to_redraw_cursor = 1;
722 }
723
724 if (need_to_redraw_cursor) {
725 /* Remove old cursor, if any: */
726 if (d->fb_window->OLD_cursor_on) {
727 XPutImage(d->fb_window->x11_display,
728 d->fb_window->x11_fb_window,
729 d->fb_window->x11_fb_gc, d->fb_window->fb_ximage,
730 d->fb_window->OLD_cursor_x/d->vfb_scaledown,
731 d->fb_window->OLD_cursor_y/d->vfb_scaledown,
732 d->fb_window->OLD_cursor_x/d->vfb_scaledown,
733 d->fb_window->OLD_cursor_y/d->vfb_scaledown,
734 d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1,
735 d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1);
736 }
737 }
738 #endif
739
740 if (d->update_x2 != -1) {
741 int y, addr, addr2, q = d->vfb_scaledown;
742
743 if (d->update_x1 >= d->visible_xsize)
744 d->update_x1 = d->visible_xsize - 1;
745 if (d->update_x2 >= d->visible_xsize)
746 d->update_x2 = d->visible_xsize - 1;
747 if (d->update_y1 >= d->visible_ysize)
748 d->update_y1 = d->visible_ysize - 1;
749 if (d->update_y2 >= d->visible_ysize)
750 d->update_y2 = d->visible_ysize - 1;
751
752 /* Without these, we might miss the rightmost/bottom pixel: */
753 d->update_x2 += (q - 1);
754 d->update_y2 += (q - 1);
755
756 d->update_x1 = d->update_x1 / q * q;
757 d->update_x2 = d->update_x2 / q * q;
758 d->update_y1 = d->update_y1 / q * q;
759 d->update_y2 = d->update_y2 / q * q;
760
761 addr = d->update_y1 * d->bytes_per_line +
762 d->update_x1 * d->bit_depth / 8;
763 addr2 = d->update_y1 * d->bytes_per_line +
764 d->update_x2 * d->bit_depth / 8;
765
766 for (y=d->update_y1; y<=d->update_y2; y+=q) {
767 update_framebuffer(d, addr, addr2 - addr);
768 addr += d->bytes_per_line * q;
769 addr2 += d->bytes_per_line * q;
770 }
771
772 #ifdef WITH_X11
773 XPutImage(d->fb_window->x11_display, d->fb_window->
774 x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
775 fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
776 d->vfb_scaledown, d->update_x1/d->vfb_scaledown,
777 d->update_y1/d->vfb_scaledown,
778 (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
779 (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
780
781 need_to_flush_x11 = 1;
782 #endif
783
784 d->update_x1 = d->update_y1 = 99999;
785 d->update_x2 = d->update_y2 = -1;
786 }
787
788 #ifdef WITH_X11
789 if (need_to_redraw_cursor) {
790 /* Paint new cursor: */
791 if (d->fb_window->cursor_on) {
792 x11_redraw_cursor(cpu->machine,
793 d->fb_window->fb_number);
794 d->fb_window->OLD_cursor_on = d->fb_window->cursor_on;
795 d->fb_window->OLD_cursor_x = d->fb_window->cursor_x;
796 d->fb_window->OLD_cursor_y = d->fb_window->cursor_y;
797 d->fb_window->OLD_cursor_xsize = d->fb_window->
798 cursor_xsize;
799 d->fb_window->OLD_cursor_ysize = d->fb_window->
800 cursor_ysize;
801 }
802 }
803 #endif
804
805 #ifdef WITH_X11
806 if (need_to_flush_x11)
807 XFlush(d->fb_window->x11_display);
808 #endif
809 }
810
811
812 /*
813 * dev_fb_access():
814 */
815 int dev_fb_access(struct cpu *cpu, struct memory *mem,
816 uint64_t relative_addr, unsigned char *data, size_t len,
817 int writeflag, void *extra)
818 {
819 struct vfb_data *d = extra;
820 int i;
821
822 #ifdef FB_DEBUG
823 if (writeflag == MEM_WRITE) { if (data[0]) {
824 fatal("[ dev_fb: write to addr=%08lx, data = ",
825 (long)relative_addr);
826 for (i=0; i<len; i++)
827 fatal("%02x ", data[i]);
828 fatal("]\n");
829 } else {
830 fatal("[ dev_fb: read from addr=%08lx, data = ",
831 (long)relative_addr);
832 for (i=0; i<len; i++)
833 fatal("%02x ", d->framebuffer[relative_addr + i]);
834 fatal("]\n");
835 }
836 #endif
837
838 if (relative_addr >= d->framebuffer_size)
839 return 0;
840
841 /* See if a write actually modifies the framebuffer contents: */
842 if (writeflag == MEM_WRITE) {
843 for (i=0; i<len; i++) {
844 if (data[i] != d->framebuffer[relative_addr + i])
845 break;
846
847 /* If all bytes are equal to what is already stored
848 in the framebuffer, then simply return: */
849 if (i==len-1)
850 return 1;
851 }
852 }
853
854 /*
855 * If the framebuffer is modified, then we should keep a track
856 * of which area(s) we modify, so that the display isn't updated
857 * unnecessarily.
858 */
859 if (writeflag == MEM_WRITE && cpu->machine->use_x11) {
860 int x, y, x2,y2;
861
862 x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
863 y = relative_addr / d->bytes_per_line;
864 x2 = ((relative_addr + len) % d->bytes_per_line)
865 * 8 / d->bit_depth;
866 y2 = (relative_addr + len) / d->bytes_per_line;
867
868 if (x < d->update_x1 || d->update_x1 == -1)
869 d->update_x1 = x;
870 if (x > d->update_x2 || d->update_x2 == -1)
871 d->update_x2 = x;
872
873 if (y < d->update_y1 || d->update_y1 == -1)
874 d->update_y1 = y;
875 if (y > d->update_y2 || d->update_y2 == -1)
876 d->update_y2 = y;
877
878 if (x2 < d->update_x1 || d->update_x1 == -1)
879 d->update_x1 = x2;
880 if (x2 > d->update_x2 || d->update_x2 == -1)
881 d->update_x2 = x2;
882
883 if (y2 < d->update_y1 || d->update_y1 == -1)
884 d->update_y1 = y2;
885 if (y2 > d->update_y2 || d->update_y2 == -1)
886 d->update_y2 = y2;
887
888 /*
889 * An update covering more than one line will automatically
890 * force an update of all the affected lines:
891 */
892 if (y != y2) {
893 d->update_x1 = 0;
894 d->update_x2 = d->xsize-1;
895 }
896 }
897
898 /*
899 * Read from/write to the framebuffer:
900 * (TODO: take the color_plane_mask into account)
901 *
902 * Calling memcpy() is probably overkill, as it usually is just one
903 * or a few bytes that are read/written at a time.
904 */
905 if (writeflag == MEM_WRITE) {
906 if (len > 8)
907 memcpy(d->framebuffer + relative_addr, data, len);
908 else
909 for (i=0; i<len; i++)
910 d->framebuffer[relative_addr + i] = data[i];
911 } else {
912 if (len > 8)
913 memcpy(data, d->framebuffer + relative_addr, len);
914 else
915 for (i=0; i<len; i++)
916 data[i] = d->framebuffer[relative_addr + i];
917 }
918
919 return 1;
920 }
921
922
923 /*
924 * dev_fb_init():
925 *
926 * This function is big and ugly, but the point is to initialize a framebuffer
927 * device. :-)
928 *
929 * visible_xsize and visible_ysize are the sizes of the visible display area.
930 * xsize and ysize tell how much memory is actually allocated (for example
931 * visible_xsize could be 640, but xsize could be 1024, for better alignment).
932 *
933 * vfb_type is useful for selecting special features.
934 *
935 * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
936 *
937 * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
938 *
939 * If type is VFB_HPC, then color encoding differs from the generic case.
940 *
941 * If bit_depth = -15 (note the minus sign), then a special hack is used for
942 * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
943 */
944 struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
945 uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
946 int xsize, int ysize, int bit_depth, char *name)
947 {
948 struct vfb_data *d;
949 size_t size, nlen;
950 int flags;
951 char title[400];
952 char *name2;
953
954 d = malloc(sizeof(struct vfb_data));
955 if (d == NULL) {
956 fprintf(stderr, "out of memory\n");
957 exit(1);
958 }
959 memset(d, 0, sizeof(struct vfb_data));
960
961 d->vfb_type = vfb_type;
962
963 /* Defaults: */
964 d->xsize = xsize; d->visible_xsize = visible_xsize;
965 d->ysize = ysize; d->visible_ysize = visible_ysize;
966
967 d->bit_depth = bit_depth;
968
969 if (bit_depth == 15) {
970 d->color32k = 1;
971 bit_depth = d->bit_depth = 16;
972 } else if (bit_depth == -15) {
973 d->psp_15bit = 1;
974 bit_depth = d->bit_depth = 16;
975 }
976
977 /* Specific types: */
978 switch (vfb_type) {
979 case VFB_DEC_VFB01:
980 /* DECstation VFB01 (monochrome) */
981 d->xsize = 2048; d->visible_xsize = 1024;
982 d->ysize = 1024; d->visible_ysize = 864;
983 d->bit_depth = 1;
984 break;
985 case VFB_DEC_VFB02:
986 /* DECstation VFB02 (color) */
987 d->xsize = 1024; d->visible_xsize = 1024;
988 d->ysize = 1024; d->visible_ysize = 864;
989 d->bit_depth = 8;
990 break;
991 case VFB_DEC_MAXINE:
992 /* DECstation Maxine (1024x768x8) */
993 d->xsize = 1024; d->visible_xsize = d->xsize;
994 d->ysize = 768; d->visible_ysize = d->ysize;
995 d->bit_depth = 8;
996 break;
997 case VFB_PLAYSTATION2:
998 /* Playstation 2 */
999 d->xsize = xsize; d->visible_xsize = d->xsize;
1000 d->ysize = ysize; d->visible_ysize = d->ysize;
1001 d->bit_depth = 24;
1002 break;
1003 default:
1004 ;
1005 }
1006
1007 if (d->bit_depth == 2 || d->bit_depth == 4)
1008 set_grayscale_palette(d, 1 << d->bit_depth);
1009 else if (d->bit_depth == 8 || d->bit_depth == 1)
1010 set_blackwhite_palette(d, 1 << d->bit_depth);
1011
1012 d->vfb_scaledown = machine->x11_scaledown;
1013
1014 d->bytes_per_line = d->xsize * d->bit_depth / 8;
1015 size = d->ysize * d->bytes_per_line;
1016
1017 d->framebuffer = malloc(size);
1018 if (d->framebuffer == NULL) {
1019 fprintf(stderr, "out of memory\n");
1020 exit(1);
1021 }
1022
1023 /* Clear the framebuffer (all black pixels): */
1024 d->framebuffer_size = size;
1025 memset(d->framebuffer, 0, size);
1026
1027 d->x11_xsize = d->visible_xsize / d->vfb_scaledown;
1028 d->x11_ysize = d->visible_ysize / d->vfb_scaledown;
1029
1030 d->update_x1 = d->update_y1 = 99999;
1031 d->update_x2 = d->update_y2 = -1;
1032
1033
1034 /* Don't set the title to include the size of the framebuffer for
1035 VGA, since then the resolution might change during runtime. */
1036 if (strcmp(name, "VGA") == 0)
1037 snprintf(title, sizeof(title),"GXemul: %s framebuffer", name);
1038 else
1039 snprintf(title, sizeof(title),"GXemul: %ix%ix%i %s framebuffer",
1040 d->visible_xsize, d->visible_ysize, d->bit_depth, name);
1041 title[sizeof(title)-1] = '\0';
1042
1043 #ifdef WITH_X11
1044 if (machine->use_x11)
1045 d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize,
1046 title, machine->x11_scaledown, machine);
1047 else
1048 #endif
1049 d->fb_window = NULL;
1050
1051 nlen = strlen(name) + 10;
1052 name2 = malloc(nlen);
1053 if (name2 == NULL) {
1054 fprintf(stderr, "out of memory in dev_fb_init()\n");
1055 exit(1);
1056 }
1057 snprintf(name2, nlen, "fb [%s]", name);
1058
1059 flags = DM_DEFAULT;
1060 if ((baseaddr & 0xfff) == 0)
1061 flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK;
1062
1063 flags |= DM_READS_HAVE_NO_SIDE_EFFECTS;
1064
1065 memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
1066 d, flags, d->framebuffer);
1067
1068 machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT);
1069 return d;
1070 }
1071

  ViewVC Help
Powered by ViewVC 1.1.26