/[gxemul]/trunk/src/devices/dev_fb.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_fb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 29268 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26