dev_fb.cc Source File

Back to the index.

dev_fb.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2018 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  * COMMENT: Generic framebuffer device
29  *
30  * DECstation VFB01 monochrome framebuffer, 1024x864
31  * DECstation VFB02 8-bit color framebuffer, 1024x864
32  * DECstation Maxine, 1024x768 8-bit color
33  * Playstation 2 (24-bit color)
34  * Generic (any resolution, several bit depths possible, useful for
35  * testmachines)
36  *
37  *
38  * TODO: This should actually be independent of X11, but that
39  * might be too hard to do right now.
40  *
41  * TODO: playstation 2 pixels are stored in another format, actually
42  */
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include "console.h"
49 #include "cpu.h"
50 #include "devices.h"
51 #include "machine.h"
52 #include "memory.h"
53 #include "misc.h"
54 #include "x11.h"
55 
56 #ifdef WITH_X11
57 #include <X11/Xlib.h>
58 #include <X11/Xos.h>
59 #include <X11/Xutil.h>
60 #endif
61 
62 
63 #define FB_TICK_SHIFT 19
64 
65 
66 /* #define FB_DEBUG */
67 
68 /*
69  * set_grayscale_palette():
70  *
71  * Fill d->rgb_palette with grayscale values. ncolors should
72  * be something like 2, 4, 16, or 256.
73  */
74 void set_grayscale_palette(struct vfb_data *d, int ncolors)
75 {
76  int i, gray;
77 
78  for (i=0; i<256; i++) {
79  gray = 255*i/(ncolors-1);
80  d->rgb_palette[i*3 + 0] = gray;
81  d->rgb_palette[i*3 + 1] = gray;
82  d->rgb_palette[i*3 + 2] = gray;
83  }
84 }
85 
86 
87 /*
88  * set_blackwhite_palette():
89  *
90  * Set color 0 = black, all others to white.
91  */
92 void set_blackwhite_palette(struct vfb_data *d, int ncolors)
93 {
94  int i, gray;
95 
96  for (i=0; i<256; i++) {
97  gray = i==0? 0 : 255;
98  d->rgb_palette[i*3 + 0] = gray;
99  d->rgb_palette[i*3 + 1] = gray;
100  d->rgb_palette[i*3 + 2] = gray;
101  }
102 }
103 
104 
105 static void set_title(struct vfb_data *d)
106 {
107  snprintf(d->title, sizeof(d->title),"GXemul: %ix%ix%i %s framebuffer",
108  d->visible_xsize, d->visible_ysize, d->bit_depth, d->name);
109  d->title[sizeof(d->title)-1] = '\0';
110 }
111 
112 
113 /*
114  * dev_fb_resize():
115  *
116  * Resize a framebuffer window. (This functionality is probably a bit buggy,
117  * because I didn't think of including it from the start.)
118  *
119  * SUPER-IMPORTANT: Anyone who resizes a framebuffer by calling this function
120  * must also clear all dyntrans address translations manually, in all cpus
121  * which might have access to the framebuffer!
122  */
123 void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
124 {
125  unsigned char *new_framebuffer;
126  int y, new_bytes_per_line;
127  size_t size;
128 
129  if (d == NULL) {
130  fatal("dev_fb_resize(): d == NULL\n");
131  return;
132  }
133 
134  if (new_xsize < 10 || new_ysize < 10) {
135  fatal("dev_fb_resize(): size too small.\n");
136  exit(1);
137  }
138 
139  new_bytes_per_line = new_xsize * d->bit_depth / 8;
140  size = new_ysize * new_bytes_per_line;
141 
142  CHECK_ALLOCATION(new_framebuffer = (unsigned char *) malloc(size));
143 
144  /* Copy the old framebuffer to the new: */
145  if (d->framebuffer != NULL) {
146  for (y=0; y<new_ysize; y++) {
147  size_t fromofs = d->bytes_per_line * y;
148  size_t toofs = new_bytes_per_line * y;
149  size_t len_to_copy = d->bytes_per_line <
150  new_bytes_per_line? d->bytes_per_line
151  : new_bytes_per_line;
152  memset(new_framebuffer + toofs, 0, new_bytes_per_line);
153  if (y < d->x11_ysize)
154  memmove(new_framebuffer + toofs,
155  d->framebuffer + fromofs, len_to_copy);
156  }
157 
158  free(d->framebuffer);
159  }
160 
161  d->framebuffer = new_framebuffer;
162  d->framebuffer_size = size;
163 
164  if (new_xsize > d->xsize || new_ysize > d->ysize) {
165  d->update_x1 = d->update_y1 = 0;
166  d->update_x2 = new_xsize - 1;
167  d->update_y2 = new_ysize - 1;
168  }
169 
170  d->bytes_per_line = new_bytes_per_line;
171  d->xsize = d->visible_xsize = new_xsize;
172  d->ysize = d->visible_ysize = new_ysize;
173 
174  d->x11_xsize = d->xsize / d->vfb_scaledown;
175  d->x11_ysize = d->ysize / d->vfb_scaledown;
176 
178 
179  set_title(d);
180 
181 #ifdef WITH_X11
182  if (d->fb_window != NULL) {
185  }
186 #endif
187 }
188 
189 
190 /*
191  * dev_fb_setcursor():
192  */
193 void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on,
194  int cursor_xsize, int cursor_ysize)
195 {
196  if (cursor_x < 0)
197  cursor_x = 0;
198  if (cursor_y < 0)
199  cursor_y = 0;
200  if (cursor_x + cursor_xsize >= d->xsize)
201  cursor_x = d->xsize - cursor_xsize;
202  if (cursor_y + cursor_ysize >= d->ysize)
203  cursor_y = d->ysize - cursor_ysize;
204 
205 #ifdef WITH_X11
206  if (d->fb_window != NULL) {
207  d->fb_window->cursor_x = cursor_x;
208  d->fb_window->cursor_y = cursor_y;
209  d->fb_window->cursor_on = on;
210  d->fb_window->cursor_xsize = cursor_xsize;
211  d->fb_window->cursor_ysize = cursor_ysize;
212  }
213 #endif
214 
215  /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n",
216  cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */
217 }
218 
219 
220 /*
221  * framebuffer_blockcopyfill():
222  *
223  * This function should be used by devices that are capable of doing
224  * block copy/fill.
225  *
226  * If fillflag is non-zero, then fill_[rgb] should contain the color
227  * with which to fill. (In 8-bit mode, only fill_r is used.)
228  *
229  * If fillflag is zero, copy mode is used, and from_[xy] should contain
230  * the offset on the framebuffer where we should copy from.
231  *
232  * NOTE: Overlapping copies are undefined!
233  */
234 void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r,
235  int fill_g, int fill_b, int x1, int y1, int x2, int y2,
236  int from_x, int from_y)
237 {
238  int x, y;
239  size_t from_ofs, dest_ofs, linelen;
240 
241  if (fillflag)
242  debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, "
243  "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b);
244  else
245  debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from "
246  "%i,%i)\n", x1,y1, x2,y2, from_x,from_y);
247 
248  /* Clip x: */
249  if (x1 < 0) x1 = 0;
250  if (x1 >= d->xsize) x1 = d->xsize-1;
251  if (x2 < 0) x2 = 0;
252  if (x2 >= d->xsize) x2 = d->xsize-1;
253 
254  dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1;
255  linelen = (x2-x1 + 1) * (d->bit_depth/8);
256  /* NOTE: linelen is nr of bytes, not pixels */
257 
258  if (fillflag) {
259  for (y=y1; y<=y2; y++) {
260  if (y>=0 && y<d->ysize) {
261  unsigned char *buf =
262  d->framebuffer + dest_ofs;
263 
264  if (d->bit_depth == 24) {
265  for (x=0; x<(ssize_t)linelen && x <
266  (int) sizeof(buf); x += 3) {
267  buf[x] = fill_r;
268  buf[x+1] = fill_g;
269  buf[x+2] = fill_b;
270  }
271  } else if (d->bit_depth == 8) {
272  memset(buf, fill_r, linelen);
273  } else {
274  fatal("Unimplemented bit-depth (%i)"
275  " for fb fill\n", d->bit_depth);
276  exit(1);
277  }
278  }
279 
280  dest_ofs += d->bytes_per_line;
281  }
282  } else {
283  from_ofs = d->bytes_per_line * from_y +
284  (d->bit_depth/8) * from_x;
285  for (y=y1; y<=y2; y++) {
286  if (y >= 0 && y < d->ysize) {
287  if (from_y >= 0 && from_y < d->ysize)
288  memmove(d->framebuffer + dest_ofs,
289  d->framebuffer + from_ofs, linelen);
290  else
291  memset(d->framebuffer + dest_ofs,
292  0, linelen);
293  }
294  from_y ++;
295  from_ofs += d->bytes_per_line;
296  dest_ofs += d->bytes_per_line;
297  }
298  }
299 
300  if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1;
301  if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1;
302  if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2;
303  if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2;
304 
305  if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1;
306  if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1;
307  if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2;
308  if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2;
309 }
310 
311 
312 #ifdef WITH_X11
313 
314 #define REDRAW redraw_fallback
315 #include "fb_include.cc"
316 #undef REDRAW
317 
318 #define FB_24
319 #define REDRAW redraw_24
320 #include "fb_include.cc"
321 #undef REDRAW
322 #undef FB_24
323 #define FB_16
324 #define REDRAW redraw_16
325 #include "fb_include.cc"
326 #undef FB_16
327 #undef REDRAW
328 #define FB_15
329 #define REDRAW redraw_15
330 #include "fb_include.cc"
331 #undef REDRAW
332 #undef FB_15
333 
334 #define FB_BO
335 #define FB_24
336 #define REDRAW redraw_24_bo
337 #include "fb_include.cc"
338 #undef REDRAW
339 #undef FB_24
340 #define FB_16
341 #define REDRAW redraw_16_bo
342 #include "fb_include.cc"
343 #undef FB_16
344 #undef REDRAW
345 #define FB_15
346 #define REDRAW redraw_15_bo
347 #include "fb_include.cc"
348 #undef REDRAW
349 #undef FB_15
350 #undef FB_BO
351 
352 #define FB_SCALEDOWN
353 
354 #define REDRAW redraw_fallback_sd
355 #include "fb_include.cc"
356 #undef REDRAW
357 
358 #define FB_24
359 #define REDRAW redraw_24_sd
360 #include "fb_include.cc"
361 #undef REDRAW
362 #undef FB_24
363 #define FB_16
364 #define REDRAW redraw_16_sd
365 #include "fb_include.cc"
366 #undef FB_16
367 #undef REDRAW
368 #define FB_15
369 #define REDRAW redraw_15_sd
370 #include "fb_include.cc"
371 #undef REDRAW
372 #undef FB_15
373 
374 #define FB_BO
375 #define FB_24
376 #define REDRAW redraw_24_bo_sd
377 #include "fb_include.cc"
378 #undef REDRAW
379 #undef FB_24
380 #define FB_16
381 #define REDRAW redraw_16_bo_sd
382 #include "fb_include.cc"
383 #undef FB_16
384 #undef REDRAW
385 #define FB_15
386 #define REDRAW redraw_15_bo_sd
387 #include "fb_include.cc"
388 #undef REDRAW
389 #undef FB_15
390 #undef FB_BO
391 
392 void (*redraw[2 * 4 * 2])(struct vfb_data *, int, int) = {
393  redraw_fallback, redraw_fallback,
394  redraw_15, redraw_15_bo,
395  redraw_16, redraw_16_bo,
396  redraw_24, redraw_24_bo,
397  redraw_fallback_sd, redraw_fallback_sd,
398  redraw_15_sd, redraw_15_bo_sd,
399  redraw_16_sd, redraw_16_bo_sd,
400  redraw_24_sd, redraw_24_bo_sd };
401 
402 #endif /* WITH_X11 */
403 
404 
406 {
407  struct vfb_data *d = (struct vfb_data *) extra;
408 #ifdef WITH_X11
409  int need_to_flush_x11 = 0;
410  int need_to_redraw_cursor = 0;
411 #endif
412 
413  if (!cpu->machine->x11_md.in_use)
414  return;
415 
416  do {
417  uint64_t high, low = (uint64_t)(int64_t) -1;
418  int x, y;
419 
421  extra, &low, &high);
422  if ((int64_t)low == -1)
423  break;
424 
425  /* printf("low=%016llx high=%016llx\n",
426  (long long)low, (long long)high); */
427 
428  x = (low % d->bytes_per_line) * 8 / d->bit_depth;
429  y = low / d->bytes_per_line;
430  if (x < d->update_x1 || d->update_x1 == -1)
431  d->update_x1 = x;
432  if (x > d->update_x2 || d->update_x2 == -1)
433  d->update_x2 = x;
434  if (y < d->update_y1 || d->update_y1 == -1)
435  d->update_y1 = y;
436  if (y > d->update_y2 || d->update_y2 == -1)
437  d->update_y2 = y;
438 
439  x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth;
440  y = (low+7) / d->bytes_per_line;
441  if (x < d->update_x1 || d->update_x1 == -1)
442  d->update_x1 = x;
443  if (x > d->update_x2 || d->update_x2 == -1)
444  d->update_x2 = x;
445  if (y < d->update_y1 || d->update_y1 == -1)
446  d->update_y1 = y;
447  if (y > d->update_y2 || d->update_y2 == -1)
448  d->update_y2 = y;
449 
450  x = (high % d->bytes_per_line) * 8 / d->bit_depth;
451  y = high / d->bytes_per_line;
452  if (x < d->update_x1 || d->update_x1 == -1)
453  d->update_x1 = x;
454  if (x > d->update_x2 || d->update_x2 == -1)
455  d->update_x2 = x;
456  if (y < d->update_y1 || d->update_y1 == -1)
457  d->update_y1 = y;
458  if (y > d->update_y2 || d->update_y2 == -1)
459  d->update_y2 = y;
460 
461  x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth;
462  y = (high+7) / d->bytes_per_line;
463  if (x < d->update_x1 || d->update_x1 == -1)
464  d->update_x1 = x;
465  if (x > d->update_x2 || d->update_x2 == -1)
466  d->update_x2 = x;
467  if (y < d->update_y1 || d->update_y1 == -1)
468  d->update_y1 = y;
469  if (y > d->update_y2 || d->update_y2 == -1)
470  d->update_y2 = y;
471 
472  /*
473  * An update covering more than one line will automatically
474  * force an update of all the affected lines:
475  */
476  if (d->update_y1 != d->update_y2) {
477  d->update_x1 = 0;
478  d->update_x2 = d->xsize-1;
479  }
480  } while (0);
481 
482 #ifdef WITH_X11
483  /* Do we need to redraw the cursor? */
484  if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on ||
489  need_to_redraw_cursor = 1;
490 
491  if (d->update_x2 != -1) {
492  if (((d->update_x1 >= d->fb_window->OLD_cursor_x &&
493  d->update_x1 < (d->fb_window->OLD_cursor_x +
494  d->fb_window->OLD_cursor_xsize)) ||
495  (d->update_x2 >= d->fb_window->OLD_cursor_x &&
496  d->update_x2 < (d->fb_window->OLD_cursor_x +
497  d->fb_window->OLD_cursor_xsize)) ||
498  (d->update_x1 < d->fb_window->OLD_cursor_x &&
499  d->update_x2 >= (d->fb_window->OLD_cursor_x +
500  d->fb_window->OLD_cursor_xsize)) ) &&
501  ( (d->update_y1 >= d->fb_window->OLD_cursor_y &&
502  d->update_y1 < (d->fb_window->OLD_cursor_y +
503  d->fb_window->OLD_cursor_ysize)) ||
504  (d->update_y2 >= d->fb_window->OLD_cursor_y &&
505  d->update_y2 < (d->fb_window->OLD_cursor_y +
506  d->fb_window->OLD_cursor_ysize)) ||
507  (d->update_y1 < d->fb_window->OLD_cursor_y &&
508  d->update_y2 >= (d->fb_window->OLD_cursor_y +
509  d->fb_window->OLD_cursor_ysize)) ) )
510  need_to_redraw_cursor = 1;
511  }
512 
513  if (need_to_redraw_cursor) {
514  /* Remove old cursor, if any: */
515  if (d->fb_window->OLD_cursor_on) {
516  XPutImage(d->fb_window->x11_display,
525  }
526  }
527 #endif
528 
529  if (d->update_x2 != -1) {
530 #ifdef WITH_X11
531  int y;
532 #endif
533  int addr, addr2, q = d->vfb_scaledown;
534 
535  if (d->update_x1 >= d->visible_xsize)
536  d->update_x1 = d->visible_xsize - 1;
537  if (d->update_x2 >= d->visible_xsize)
538  d->update_x2 = d->visible_xsize - 1;
539  if (d->update_y1 >= d->visible_ysize)
540  d->update_y1 = d->visible_ysize - 1;
541  if (d->update_y2 >= d->visible_ysize)
542  d->update_y2 = d->visible_ysize - 1;
543 
544  /* Without these, we might miss the rightmost/bottom pixel: */
545  d->update_x2 += (q - 1);
546  d->update_y2 += (q - 1);
547 
548  d->update_x1 = d->update_x1 / q * q;
549  d->update_x2 = d->update_x2 / q * q;
550  d->update_y1 = d->update_y1 / q * q;
551  d->update_y2 = d->update_y2 / q * q;
552 
553  addr = d->update_y1 * d->bytes_per_line +
554  d->update_x1 * d->bit_depth / 8;
555  addr2 = d->update_y1 * d->bytes_per_line +
556  d->update_x2 * d->bit_depth / 8;
557 
558 #ifdef WITH_X11
559  for (y=d->update_y1; y<=d->update_y2; y+=q) {
560  d->redraw_func(d, addr, addr2 - addr);
561  addr += d->bytes_per_line * q;
562  addr2 += d->bytes_per_line * q;
563  }
564 
565  XPutImage(d->fb_window->x11_display, d->fb_window->
566  x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->
567  fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/
569  d->update_y1/d->vfb_scaledown,
570  (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1,
571  (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1);
572 
573  need_to_flush_x11 = 1;
574 #endif
575 
576  d->update_x1 = d->update_y1 = 99999;
577  d->update_x2 = d->update_y2 = -1;
578  }
579 
580 #ifdef WITH_X11
581  if (need_to_redraw_cursor) {
582  /* Paint new cursor: */
583  if (d->fb_window->cursor_on) {
585  d->fb_window->fb_number);
590  cursor_xsize;
592  cursor_ysize;
593  need_to_flush_x11 = 1;
594  }
595  }
596 #endif
597 
598 #ifdef WITH_X11
599  if (need_to_flush_x11)
600  XFlush(d->fb_window->x11_display);
601 #endif
602 
603 #if 0
604 
605 This is a hack used to produce raw ppm image dumps, which can then be
606 used to make movies, e.g. http://www.youtube.com/watch?v=Afh1ECLWac8
607 
608 {
609  static struct timeval tv_last;
610  static bool first = true;
611 
612  struct timeval tv;
613  gettimeofday(&tv, NULL);
614 
615  if (first)
616  {
617  tv_last = tv;
618  first = false;
619  }
620  else
621  {
622  double diff = (tv.tv_sec - tv_last.tv_sec) + (tv.tv_usec - tv_last.tv_usec) / 1000000.0;
623  if (diff > 0.2)
624  {
625  static int outputNr = 0;
626  outputNr ++;
627  tv_last = tv;
628 
629  char name[50];
630  snprintf(name, sizeof(name), "gxemul-%06i.ppm", outputNr);
631 
632  FILE *f = fopen(name, "w");
633  if (f == NULL)
634  {
635  perror(name);
636  }
637  else
638  {
639  const int xsize = 640;
640  const int ysize = 480;
641  fprintf(f, "P6\n%i %i\n255\n", xsize, ysize);
642  unsigned char buf[xsize*ysize*3];
643  memset(buf, 0, xsize*ysize*3);
644 
645  // Calculate scaledown:
646  int scaledown = 1;
647 
648  while (d->visible_xsize / scaledown > xsize ||
649  d->visible_ysize / scaledown > ysize)
650  {
651  scaledown ++;
652  }
653 
654  // printf("scaledown = %i\n", scaledown);
655 
656  int xofs = (xsize - d->visible_xsize / scaledown) / 2;
657  int yofs = (ysize - d->visible_ysize / scaledown) / 2;
658 
659  for (int y = 0; y < d->visible_ysize / scaledown; ++y)
660  for (int x = 0; x < d->visible_xsize / scaledown; ++x)
661  {
662  int r = 0, g = 0, b = 0, n = 0;
663  for (int suby = 0; suby < scaledown; ++suby)
664  for (int subx = 0; subx < scaledown; ++subx)
665  {
666  ++n;
667  int rx = x * scaledown + subx;
668  int ry = y * scaledown + suby;
669  int i = (d->xsize * ry + rx) * d->bit_depth / 8;
670 
671 #if 0
672  r += d->framebuffer[i+0];
673  g += d->framebuffer[i+1];
674  b += d->framebuffer[i+2];
675 #else
676  int col = d->framebuffer[i];
677  r += d->rgb_palette[col*3 + 0];
678  g += d->rgb_palette[col*3 + 1];
679  b += d->rgb_palette[col*3 + 2];
680 #endif
681  }
682 
683  r /= n; g /= n; b /= n;
684  int j = (y + yofs) * xsize + x + xofs;
685  buf[j*3+0] = r;
686  buf[j*3+1] = g;
687  buf[j*3+2] = b;
688  }
689 
690  fwrite(buf, 1, xsize*ysize*3, f);
691  fclose(f);
692  }
693  }
694  }
695 
696 }
697 
698 #endif
699 
700 
701 }
702 
703 
705 {
706  struct vfb_data *d = (struct vfb_data *) extra;
707  size_t i;
708 
709 #ifdef FB_DEBUG
710  if (writeflag == MEM_WRITE) { if (data[0]) {
711  fatal("[ dev_fb: write to addr=%08lx, data = ",
712  (long)relative_addr);
713  for (i=0; i<len; i++)
714  fatal("%02x ", data[i]);
715  fatal("]\n");
716  } else {
717  fatal("[ dev_fb: read from addr=%08lx, data = ",
718  (long)relative_addr);
719  for (i=0; i<len; i++)
720  fatal("%02x ", d->framebuffer[relative_addr + i]);
721  fatal("]\n");
722  }
723 #endif
724 
725  if (relative_addr >= d->framebuffer_size)
726  return 0;
727 
728  /* See if a write actually modifies the framebuffer contents: */
729  if (writeflag == MEM_WRITE) {
730  for (i=0; i<len; i++) {
731  if (data[i] != d->framebuffer[relative_addr + i])
732  break;
733 
734  /* If all bytes are equal to what is already stored
735  in the framebuffer, then simply return: */
736  if (i == len-1)
737  return 1;
738  }
739  }
740 
741  /*
742  * If the framebuffer is modified, then we should keep a track
743  * of which area(s) we modify, so that the display isn't updated
744  * unnecessarily.
745  */
746  if (writeflag == MEM_WRITE && cpu->machine->x11_md.in_use) {
747  int x, y, x2,y2;
748 
749  x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth;
750  y = relative_addr / d->bytes_per_line;
751  x2 = ((relative_addr + len) % d->bytes_per_line)
752  * 8 / d->bit_depth;
753  y2 = (relative_addr + len) / d->bytes_per_line;
754 
755  if (x < d->update_x1 || d->update_x1 == -1)
756  d->update_x1 = x;
757  if (x > d->update_x2 || d->update_x2 == -1)
758  d->update_x2 = x;
759 
760  if (y < d->update_y1 || d->update_y1 == -1)
761  d->update_y1 = y;
762  if (y > d->update_y2 || d->update_y2 == -1)
763  d->update_y2 = y;
764 
765  if (x2 < d->update_x1 || d->update_x1 == -1)
766  d->update_x1 = x2;
767  if (x2 > d->update_x2 || d->update_x2 == -1)
768  d->update_x2 = x2;
769 
770  if (y2 < d->update_y1 || d->update_y1 == -1)
771  d->update_y1 = y2;
772  if (y2 > d->update_y2 || d->update_y2 == -1)
773  d->update_y2 = y2;
774 
775  /*
776  * An update covering more than one line will automatically
777  * force an update of all the affected lines:
778  */
779  if (y != y2) {
780  d->update_x1 = 0;
781  d->update_x2 = d->xsize-1;
782  }
783  }
784 
785  /*
786  * Read from/write to the framebuffer:
787  * (TODO: take the color_plane_mask into account)
788  *
789  * Calling memcpy() is probably overkill, as it usually is just one
790  * or a few bytes that are read/written at a time.
791  */
792  if (writeflag == MEM_WRITE) {
793  if (len > 8)
794  memcpy(d->framebuffer + relative_addr, data, len);
795  else {
796  for (i=0; i<len; i++)
797  d->framebuffer[relative_addr + i] = data[i];
798  }
799  } else {
800  if (len > 8)
801  memcpy(data, d->framebuffer + relative_addr, len);
802  else {
803  for (i=0; i<len; i++)
804  data[i] = d->framebuffer[relative_addr + i];
805  }
806  }
807 
808  return 1;
809 }
810 
811 
812 /*
813  * dev_fb_init():
814  *
815  * This function is big and ugly, but the point is to initialize a framebuffer
816  * device. :-)
817  *
818  * visible_xsize and visible_ysize are the sizes of the visible display area.
819  * xsize and ysize tell how much memory is actually allocated (for example
820  * visible_xsize could be 640, but xsize could be 1024, for better alignment).
821  *
822  * vfb_type is useful for selecting special features.
823  *
824  * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24.
825  *
826  * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific.
827  *
828  * VFB_HPC is like generic, but the color encoding is done as on HPCmips
829  * and Dreamcast.
830  *
831  * If bit_depth = -15 (note the minus sign), then a special hack is used for
832  * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B.
833  */
834 struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem,
835  uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize,
836  int xsize, int ysize, int bit_depth, const char *name)
837 {
838  struct vfb_data *d;
839  size_t size, nlen;
840  int flags;
841  int reverse_start = 0;
842  char *name2;
843 
844  CHECK_ALLOCATION(d = (struct vfb_data *) malloc(sizeof(struct vfb_data)));
845  memset(d, 0, sizeof(struct vfb_data));
846 
847  if (vfb_type & VFB_REVERSE_START) {
848  vfb_type &= ~VFB_REVERSE_START;
849  reverse_start = 1;
850  }
851 
852  d->memory = mem;
853  d->vfb_type = vfb_type;
854 
855  /* Defaults: */
858 
859  d->bit_depth = bit_depth;
860 
861  if (bit_depth == 15) {
862  d->color32k = 1;
863  bit_depth = d->bit_depth = 16;
864  } else if (bit_depth == -15) {
865  d->psp_15bit = 1;
866  bit_depth = d->bit_depth = 16;
867  }
868 
869  /* Specific types: */
870  switch (vfb_type) {
871  case VFB_DEC_VFB01:
872  /* DECstation VFB01 (monochrome) */
873  d->xsize = 2048; d->visible_xsize = 1024;
874  d->ysize = 1024; d->visible_ysize = 864;
875  d->bit_depth = 1;
876  break;
877  case VFB_DEC_VFB02:
878  /* DECstation VFB02 (color) */
879  d->xsize = 1024; d->visible_xsize = 1024;
880  d->ysize = 1024; d->visible_ysize = 864;
881  d->bit_depth = 8;
882  break;
883  case VFB_DEC_MAXINE:
884  /* DECstation Maxine (1024x768x8) */
885  d->xsize = 1024; d->visible_xsize = d->xsize;
886  d->ysize = 768; d->visible_ysize = d->ysize;
887  d->bit_depth = 8;
888  break;
889  case VFB_PLAYSTATION2:
890  /* Playstation 2 */
891  d->xsize = xsize; d->visible_xsize = d->xsize;
892  d->ysize = ysize; d->visible_ysize = d->ysize;
893  d->bit_depth = 24;
894  break;
895  }
896 
897  if (d->bit_depth == 2 || d->bit_depth == 4)
898  set_grayscale_palette(d, 1 << d->bit_depth);
899  else if (d->bit_depth == 8 || d->bit_depth == 1)
900  set_blackwhite_palette(d, 1 << d->bit_depth);
901 
902  d->vfb_scaledown = machine->x11_md.scaledown;
903 
904  d->bytes_per_line = d->xsize * d->bit_depth / 8;
905  size = d->ysize * d->bytes_per_line;
906 
907  CHECK_ALLOCATION(d->framebuffer = (unsigned char *) malloc(size));
908 
909  /* Clear the framebuffer (all black pixels): */
910  d->framebuffer_size = size;
911  memset(d->framebuffer, reverse_start? 255 : 0, size);
912 
915 
916  /* Only "update" from the start if we need to fill with white. */
917  /* (The Ximage will be black from the start anyway.) */
918  if (reverse_start) {
919  d->update_x1 = d->update_y1 = 0;
920  d->update_x2 = d->xsize - 1;
921  d->update_y2 = d->ysize - 1;
922  } else {
923  d->update_x1 = d->update_y1 = 99999;
924  d->update_x2 = d->update_y2 = -1;
925  }
926 
927  CHECK_ALLOCATION(d->name = strdup(name));
928  set_title(d);
929 
930 #ifdef WITH_X11
931  if (machine->x11_md.in_use) {
932  int i = 0;
934  d->title, machine->x11_md.scaledown, machine);
935  switch (d->fb_window->x11_screen_depth) {
936  case 15: i = 2; break;
937  case 16: i = 4; break;
938  case 24: i = 6; break;
939  }
940  if (d->fb_window->fb_ximage->byte_order)
941  i ++;
942  if (d->vfb_scaledown > 1)
943  i += 8;
944  d->redraw_func = redraw[i];
945  } else
946 #endif
947  d->fb_window = NULL;
948 
949  nlen = strlen(name) + 10;
950  CHECK_ALLOCATION(name2 = (char *) malloc(nlen));
951 
952  snprintf(name2, nlen, "fb [%s]", name);
953 
954  flags = DM_DEFAULT;
955  if ((baseaddr & 0xfff) == 0)
957 
959 
960  memory_device_register(mem, name2, baseaddr, size, dev_fb_access,
961  d, flags, d->framebuffer);
962 
964 
965  return d;
966 }
967 
void memory_device_update_data(struct memory *mem, void *extra, unsigned char *data)
Definition: memory.cc:318
void fatal(const char *fmt,...)
Definition: main.cc:152
#define DM_DEFAULT
Definition: memory.h:130
size_t framebuffer_size
Definition: devices.h:217
int cursor_on
Definition: x11.h:76
int update_x2
Definition: devices.h:220
#define VFB_PLAYSTATION2
Definition: devices.h:195
int OLD_cursor_x
Definition: x11.h:77
struct vfb_data * dev_fb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize, int xsize, int ysize, int bit_depth, const char *name)
Definition: dev_fb.cc:834
int visible_ysize
Definition: devices.h:215
int bit_depth
Definition: devices.h:206
struct memory * mem
Definition: cpu.h:362
int xsize
Definition: devices.h:204
int OLD_cursor_xsize
Definition: x11.h:79
struct machine * machine
Definition: cpu.h:328
char * name
Definition: devices.h:225
void f(int s, int func, int only_name)
int x11_screen_depth
Definition: x11.h:60
int cursor_xsize
Definition: x11.h:74
char title[100]
Definition: devices.h:226
int OLD_cursor_on
Definition: x11.h:81
int update_y1
Definition: devices.h:220
Display * x11_display
Definition: x11.h:57
#define VFB_DEC_MAXINE
Definition: devices.h:194
int fb_number
Definition: x11.h:51
struct fb_window * x11_fb_init(int xsize, int ysize, char *name, int scaledown, struct machine *machine)
Definition: x11.cc:50
int scaledown
Definition: machine.h:83
int cursor_y
Definition: x11.h:73
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
void x11_redraw_cursor(struct machine *m, int i)
Definition: x11.cc:46
struct memory * memory
Definition: devices.h:199
#define DM_READS_HAVE_NO_SIDE_EFFECTS
Definition: memory.h:133
u_short data
Definition: siireg.h:79
int bytes_per_line
Definition: devices.h:212
struct fb_window * fb_window
Definition: devices.h:232
int cursor_ysize
Definition: x11.h:75
void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r, int fill_g, int fill_b, int x1, int y1, int x2, int y2, int from_x, int from_y)
Definition: dev_fb.cc:234
DEVICE_TICK(fb)
Definition: dev_fb.cc:405
int update_x1
Definition: devices.h:220
#define DM_DYNTRANS_WRITE_OK
Definition: memory.h:132
#define VFB_REVERSE_START
Definition: devices.h:197
#define MEM_WRITE
Definition: memory.h:117
int cursor_x
Definition: x11.h:72
int vfb_scaledown
Definition: devices.h:202
unsigned char buf[DEV_ETHER_BUFFER_SIZE]
Definition: dev_ether.cc:52
int x11_ysize
Definition: devices.h:218
void(* redraw_func)(struct vfb_data *, int, int)
Definition: devices.h:228
void x11_fb_resize(struct fb_window *win, int new_xsize, int new_ysize)
GC x11_fb_gc
Definition: x11.h:65
DEVICE_ACCESS(fb)
Definition: dev_fb.cc:704
int vfb_type
Definition: devices.h:200
struct x11_md x11_md
Definition: machine.h:179
uint32_t addr
int visible_xsize
Definition: devices.h:214
#define debug
Definition: dev_adb.cc:57
int color32k
Definition: devices.h:207
void x11_set_standard_properties(struct fb_window *fb_window, char *name)
void set_grayscale_palette(struct vfb_data *d, int ncolors)
Definition: dev_fb.cc:74
Definition: cpu.h:326
int OLD_cursor_y
Definition: x11.h:78
void dev_fb_tick(struct cpu *, void *)
int psp_15bit
Definition: devices.h:208
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
XImage * fb_ximage
Definition: x11.h:67
int dev_fb_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *)
void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
Definition: dev_fb.cc:123
unsigned char * framebuffer
Definition: devices.h:231
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
#define DM_DYNTRANS_OK
Definition: memory.h:131
int in_use
Definition: machine.h:82
#define FB_TICK_SHIFT
Definition: dev_fb.cc:63
void memory_device_dyntrans_access(struct cpu *, struct memory *mem, void *extra, uint64_t *low, uint64_t *high)
Definition: memory.cc:264
Definition: memory.h:75
addr & if(addr >=0x24 &&page !=NULL)
void set_blackwhite_palette(struct vfb_data *d, int ncolors)
Definition: dev_fb.cc:92
#define VFB_DEC_VFB02
Definition: devices.h:193
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
Window x11_fb_window
Definition: x11.h:64
int x11_xsize
Definition: devices.h:218
#define VFB_DEC_VFB01
Definition: devices.h:192
int update_y2
Definition: devices.h:220
unsigned char rgb_palette[256 *3]
Definition: devices.h:223
void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on, int cursor_xsize, int cursor_ysize)
Definition: dev_fb.cc:193
int OLD_cursor_ysize
Definition: x11.h:80
int ysize
Definition: devices.h:205

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13