/[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 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 29560 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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.107 2005/09/18 19:54:15 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 19
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 /* 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]
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 /* HPCmips is reverse: */
525 if (d->vfb_type == VFB_HPCMIPS)
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_HPCMIPS, 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 = MEM_DEFAULT;
1060 if ((baseaddr & 0xfff) == 0)
1061 flags = MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK;
1062
1063 flags |= MEM_READING_HAS_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