/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (12 years ago) by dpavlin
File MIME type: text/plain
File size: 29543 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26