1 /*
2 * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: PlayStation 2 "gif" graphics device
29 *
30 * TODO: Convert dev_fb_access() accesses into direct framebuffer reads and
31 * writes, to improve performance.
32 *
33 * TODO 2: The way things are now, rgb bytes are copied from emulated
34 * space to the framebuffer as rgb, but on X Windows servers on
35 * big-endian machines that should be bgr. (?) Hm...
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "cpu.h"
43 #include "device.h"
44 #include "devices.h"
45 #include "machine.h"
46 #include "memory.h"
47 #include "misc.h"
48
49
50 #define DEV_PS2_GIF_LENGTH 0x10000
51
52 #define PS2_FB_ADDR 0x60000000ULL /* hopefully nothing else here */
53
54
55 struct gif_data {
56 struct cpu *cpu;
57 int xsize, ysize;
58 int bytes_per_pixel;
59 int transparent_text;
60 struct vfb_data *vfb_data;
61 };
62
63
64 /*
65 * test_triangle():
66 *
67 * Draw a triangle:
68 */
test_triangle(struct gif_data * d,int x1,int y1,int r1,int g1,int b1,int x2,int y2,int r2,int g2,int b2,int x3,int y3,int r3,int g3,int b3)69 void test_triangle(struct gif_data *d,
70 int x1, int y1, int r1, int g1, int b1,
71 int x2, int y2, int r2, int g2, int b2,
72 int x3, int y3, int r3, int g3, int b3)
73 {
74 unsigned char *line;
75 int y, tmp, scale = 32768;
76 int xofs, xlen, savedxlen, xdir, x;
77 int r, g, b; /* scaled */
78 int xstart, xstop; /* scaled */
79 int rstart, rstop; /* scaled */
80 int gstart, gstop; /* scaled */
81 int bstart, bstop; /* scaled */
82 int rpx, gpx, bpx; /* scaled */
83 int xpy12, xpy13, xpy23;
84 int rpy12, rpy13, rpy23;
85 int gpy12, gpy13, gpy23;
86 int bpy12, bpy13, bpy23;
87
88 CHECK_ALLOCATION(line = (unsigned char *) malloc(d->xsize * d->bytes_per_pixel));
89
90 if (y2 > y3) {
91 tmp = x2; x2 = x3; x3 = tmp;
92 tmp = y2; y2 = y3; y3 = tmp;
93 tmp = r2; r2 = r3; r3 = tmp;
94 tmp = g2; g2 = g3; g3 = tmp;
95 tmp = b2; b2 = b3; b3 = tmp;
96 }
97
98 if (y1 > y2) {
99 tmp = x1; x1 = x2; x2 = tmp;
100 tmp = y1; y1 = y2; y2 = tmp;
101 tmp = r1; r1 = r2; r2 = tmp;
102 tmp = g1; g1 = g2; g2 = tmp;
103 tmp = b1; b1 = b2; b2 = tmp;
104 }
105
106 if (y1 > y3) {
107 tmp = x1; x1 = x3; x3 = tmp;
108 tmp = y1; y1 = y3; y3 = tmp;
109 tmp = r1; r1 = r3; r3 = tmp;
110 tmp = g1; g1 = g3; g3 = tmp;
111 tmp = b1; b1 = b3; b3 = tmp;
112 }
113
114 /* X change per line: */
115 xpy12 = (y2-y1)? scale*(x2-x1)/(y2-y1) : 0;
116 xpy13 = (y3-y1)? scale*(x3-x1)/(y3-y1) : 0;
117 xpy23 = (y3-y2)? scale*(x3-x2)/(y3-y2) : 0;
118
119 /* Color change per line: */
120 rpy12 = (y2-y1)? scale*(r2-r1)/(y2-y1) : 0;
121 rpy13 = (y3-y1)? scale*(r3-r1)/(y3-y1) : 0;
122 rpy23 = (y3-y2)? scale*(r3-r2)/(y3-y2) : 0;
123
124 gpy12 = (y2-y1)? scale*(g2-g1)/(y2-y1) : 0;
125 gpy13 = (y3-y1)? scale*(g3-g1)/(y3-y1) : 0;
126 gpy23 = (y3-y2)? scale*(g3-g2)/(y3-y2) : 0;
127
128 bpy12 = (y2-y1)? scale*(b2-b1)/(y2-y1) : 0;
129 bpy13 = (y3-y1)? scale*(b3-b1)/(y3-y1) : 0;
130 bpy23 = (y3-y2)? scale*(b3-b2)/(y3-y2) : 0;
131
132 xstart = xstop = x1 * scale;
133 rstart = rstop = r1 * scale;
134 gstart = gstop = g1 * scale;
135 bstart = bstop = b1 * scale;
136
137 for (y=y1; y<=y3; y++) {
138 if (xstart < xstop)
139 xofs = xstart/scale, xlen = (xstop-xstart)/scale + 1;
140 else
141 xofs = xstop/scale, xlen = (xstart-xstop)/scale + 1;
142
143 savedxlen = xlen;
144 xdir = (xstart < xstop)? 1 : -1;
145 r = rstart; g = gstart; b = bstart;
146
147 rpx = (xstop-xstart)? (rstop-rstart) / ((xstop-xstart)
148 / scale) : 0;
149 gpx = (xstop-xstart)? (gstop-gstart) / ((xstop-xstart)
150 / scale) : 0;
151 bpx = (xstop-xstart)? (bstop-bstart) / ((xstop-xstart)
152 / scale): 0;
153
154 x = xstart / scale;
155 while (xlen > 0) {
156 if (x>=0 && x<d->xsize) {
157 int c;
158 c = r/scale;
159 line[x * d->bytes_per_pixel + 0] = c<0?
160 0 : (c > 255? 255 : c);
161 c = g/scale;
162 line[x * d->bytes_per_pixel + 1] = c<0?
163 0 : (c > 255? 255 : c);
164 c = b/scale;
165 line[x * d->bytes_per_pixel + 2] = c<0?
166 0 : (c > 255? 255 : c);
167 }
168 r += rpx;
169 g += gpx;
170 b += bpx;
171 x += xdir;
172 xlen --;
173 }
174
175 dev_fb_access(d->cpu, d->cpu->mem,
176 (y*d->xsize + xofs) * d->bytes_per_pixel,
177 line + xofs * d->bytes_per_pixel,
178 savedxlen * d->bytes_per_pixel,
179 MEM_WRITE, d->vfb_data);
180
181 if (y<y2) {
182 xstart += xpy12;
183 rstart += rpy12;
184 gstart += gpy12;
185 bstart += bpy12;
186 } else {
187 xstart += xpy23;
188 rstart += rpy23;
189 gstart += gpy23;
190 bstart += bpy23;
191 }
192 xstop += xpy13;
193 rstop += rpy13;
194 gstop += gpy13;
195 bstop += bpy13;
196
197 if (y==y2) {
198 xstart = x2 * scale;
199 rstart = r2 * scale;
200 gstart = g2 * scale;
201 bstart = b2 * scale;
202 }
203 }
204 }
205
206
DEVICE_ACCESS(ps2_gif)207 DEVICE_ACCESS(ps2_gif)
208 {
209 unsigned int i;
210 struct gif_data *d = (struct gif_data *) extra;
211
212 if (relative_addr + len > DEV_PS2_GIF_LENGTH)
213 return 0;
214
215 if (writeflag==MEM_READ) {
216 debug("[ gif read from addr 0x%x, len=%i ]\n",
217 (int)relative_addr, (int)len);
218 } else {
219 if (data[0] == 0x08 && data[1] == 0x80) {
220 /* Possibly "initialize 640x480 mode": */
221 debug("[ gif: initialize video mode (?) ]\n");
222 } else if (data[0] == 0x04 && data[1] == 0x00 && len > 300) {
223 /* Possibly "output 8x16 character": */
224 int xbase, ybase, xsize, ysize, x, y;
225
226 xbase = data[9*4 + 0] + (data[9*4 + 1] << 8);
227 ybase = data[9*4 + 2] + (data[9*4 + 3] << 8);
228
229 xsize = data[12*4 + 0] + (data[12*4 + 1] << 8);
230 ysize = data[13*4 + 0] + (data[13*4 + 1] << 8);
231 ysize &= ~0xf; /* multple of 16 */
232
233 /* debug("[ gif: putchar at (%i,%i), size (%i,%i) "
234 "]\n", xbase, ybase, xsize, ysize); */
235
236 /*
237 * NetBSD and Linux:
238 *
239 * [ gif write to addr 0x0 (len=608):
240 * 04 00 00 00 00 00 00 10, 0e 00 00 00 00 00 00 00,
241 * 00 00 00 00 00 00 0a 00, 50 00 00 00 00 00 00 00,
242 * 00 00 00 00 00 00 00 00, 51 00 00 00 00 00 00 00,
243 * 08 00 00 00 16 00 00 00, 52 00 00 00 00 00 00 00,
244 * 00 00 00 00 00 00 00 00, 53 00 00 00 00 00 00 00,
245 * 20 80 00 00 00 00 00 08, 00 00 00 00 00 00 00 00,
246 * 00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80,
247 * 00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80,
248 * aa aa 00 80 aa aa 00 80, 00 00 aa 80 00 00 aa 80,
249 * 00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80,
250 */
251
252 /*
253 fatal("[ gif write to addr 0x%x (len=%i):",
254 (int)relative_addr, (int)len);
255 for (i=0; i<len; i++) {
256 fatal(" %02x", data[i]);
257 if ((i & 7) == 7)
258 fatal(",");
259 if ((i & 31) == 31)
260 fatal("\n");
261 }
262 fatal(" ]\n");
263 */
264
265 for (y=0; y<ysize; y++) {
266 int fb_addr = (xbase + (ybase+y) * d->xsize)
267 * d->bytes_per_pixel;
268 int addr = (24 + y*xsize) * 4;
269 for (x=0; x<xsize; x++) {
270 /* There are three bytes (r,g,b) at
271 data[addr + 0] .. [addr + 2].
272 TODO: This should be translated to a
273 direct update of the framebuffer. */
274
275 dev_fb_access(d->cpu, d->cpu->mem,
276 fb_addr, data + addr, 3, MEM_WRITE,
277 d->vfb_data);
278
279 fb_addr += d->bytes_per_pixel;
280 addr += 4;
281 }
282 }
283 } else if (data[0] == 0x04 && data[1] == 0x80 && len == 0x50) {
284 /* blockcopy */
285 int y_source, y_dest, x_source, x_dest, x_size, y_size;
286 x_source = data[8*4 + 0] + ((data[8*4 + 1]) << 8);
287 y_source = data[8*4 + 2] + ((data[8*4 + 3]) << 8);
288 x_dest = data[9*4 + 0] + ((data[9*4 + 1]) << 8);
289 y_dest = data[9*4 + 2] + ((data[9*4 + 3]) << 8);
290 x_size = data[12*4 + 0] + ((data[12*4 + 1]) << 8);
291 y_size = data[13*4 + 0] + ((data[13*4 + 1]) << 8);
292
293 /* debug("[ gif: blockcopy (%i,%i) -> (%i,%i), size="
294 "(%i,%i) ]\n", x_source,y_source, x_dest,y_dest,
295 x_size,y_size); */
296
297 framebuffer_blockcopyfill(d->vfb_data, 0, 0,0,0,
298 x_dest, y_dest, x_dest + x_size - 1, y_dest +
299 y_size - 1, x_source, y_source);
300 } else if (data[8] == 0x10 && data[9] == 0x55 && len == 48) {
301 /* Linux "clear": This is used by linux to clear the
302 lowest 16 pixels of the framebuffer. */
303 int xbase, ybase, xend, yend;
304
305 xbase = (data[8*4 + 0] + (data[8*4 + 1] << 8)) / 16;
306 ybase = (data[8*4 + 2] + (data[8*4 + 3] << 8)) / 16;
307 xend = (data[8*5 + 0] + (data[8*5 + 1] << 8)) / 16;
308 yend = (data[8*5 + 2] + (data[8*5 + 3] << 8)) / 16;
309
310 /* debug("[ gif: linux \"clear\" (%i,%i)-(%i,%i) ]\n",
311 xbase, ybase, xend, yend); */
312
313 framebuffer_blockcopyfill(d->vfb_data, 1, 0,0,0,
314 xbase, ybase, xend - 1, yend - 1, 0,0);
315 } else if (data[0] == 0x07 && data[1] == 0x80 && len == 128) {
316 /* NetBSD "output cursor": */
317 int xbase, ybase, xend, yend, x, y;
318
319 xbase = (data[20*4 + 0] + (data[20*4 + 1] << 8)) / 16;
320 ybase = (data[20*4 + 2] + (data[20*4 + 3] << 8)) / 16;
321 xend = (data[28*4 + 0] + (data[28*4 + 1] << 8)) / 16;
322 yend = (data[28*4 + 2] + (data[28*4 + 3] << 8)) / 16;
323
324 /* debug("[ gif: NETBSD cursor at (%i,%i)-(%i,%i) ]\n",
325 xbase, ybase, xend, yend); */
326
327 /* Output the cursor to framebuffer memory: */
328
329 for (y=ybase; y<=yend; y++)
330 for (x=xbase; x<=xend; x++) {
331 int fb_addr = (x + y * d->xsize) *
332 d->bytes_per_pixel;
333 unsigned char pixels[3];
334
335 dev_fb_access(d->cpu, d->cpu->mem,
336 fb_addr, pixels, sizeof(pixels),
337 MEM_READ, d->vfb_data);
338
339 pixels[0] = 0xff - pixels[0];
340 pixels[1] = 0xff - pixels[1];
341 pixels[2] = 0xff - pixels[2];
342
343 dev_fb_access(d->cpu, d->cpu->mem,
344 fb_addr, pixels, sizeof(pixels),
345 MEM_WRITE, d->vfb_data);
346 }
347 } else if (data[0] == 0x01 && data[1] == 0x00 && len == 80) {
348 /* Linux "output cursor": */
349 int xbase, ybase, xend, yend, x, y;
350
351 xbase = (data[7*8 + 0] + (data[7*8 + 1] << 8)) / 16;
352 ybase = (data[7*8 + 2] + (data[7*8 + 3] << 8)) / 16;
353 xend = (data[8*8 + 0] + (data[8*8 + 1] << 8)) / 16;
354 yend = (data[8*8 + 2] + (data[8*8 + 3] << 8)) / 16;
355
356 debug("[ gif: LINUX cursor at (%i,%i)-(%i,%i) ]\n",
357 xbase, ybase, xend, yend);
358
359 /* Output the cursor to framebuffer memory: */
360
361 for (y=ybase; y<=yend; y++)
362 for (x=xbase; x<=xend; x++) {
363 int fb_addr = (x + y * d->xsize) *
364 d->bytes_per_pixel;
365 unsigned char pixels[3];
366
367 dev_fb_access(d->cpu, d->cpu->mem,
368 fb_addr, pixels, sizeof(pixels),
369 MEM_READ, d->vfb_data);
370
371 pixels[0] = 0xff - pixels[0];
372 pixels[1] = 0xff - pixels[1];
373 pixels[2] = 0xff - pixels[2];
374
375 dev_fb_access(d->cpu, d->cpu->mem,
376 fb_addr, pixels, sizeof(pixels),
377 MEM_WRITE, d->vfb_data);
378 }
379 } else { /* Unknown command: */
380 fatal("[ gif write to addr 0x%x (len=%i):",
381 (int)relative_addr, len);
382 for (i=0; i<len; i++)
383 fatal(" %02x", data[i]);
384 fatal(" ]\n");
385 /* fatal("Unknown gif command.\n");
386 cpu->running = 0;
387 */ }
388 }
389
390 return 1;
391 }
392
393
394 /*
395 * devinit_ps2_gif():
396 *
397 * Attached to separate memory by devinit_ps2_gs().
398 */
DEVINIT(ps2_gif)399 DEVINIT(ps2_gif)
400 {
401 struct gif_data *d;
402
403 CHECK_ALLOCATION(d = (struct gif_data *) malloc(sizeof(struct gif_data)));
404 memset(d, 0, sizeof(struct gif_data));
405
406 d->transparent_text = 0;
407 d->cpu = devinit->machine->cpus[0]; /* TODO */
408 d->xsize = 640; d->ysize = 480;
409 d->bytes_per_pixel = 3;
410
411 d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory,
412 PS2_FB_ADDR, VFB_PLAYSTATION2,
413 d->xsize, d->ysize, d->xsize, d->ysize, 24, "Playstation 2");
414 if (d->vfb_data == NULL) {
415 fprintf(stderr, "could not initialize fb, out of memory\n");
416 exit(1);
417 }
418
419 #if 0
420 test_triangle(d, 300,50, 255,0,0, 50,150, 0,255,0, 600,400, 0,0,255);
421 test_triangle(d, 310,210, 128,32,0, 175,410, 0,32,0,
422 500,470, 125,255,125);
423 test_triangle(d, 100,450, 255,255,0, 250,370, 0,255,255,
424 400,470, 255,0,255);
425 #endif
426
427 memory_device_register(devinit->machine->memory, devinit->name,
428 devinit->addr, DEV_PS2_GIF_LENGTH, dev_ps2_gif_access, d,
429 DM_DEFAULT, NULL);
430
431 return 1;
432 }
433
434