dev_ps2_gif.cc Source File

Back to the index.

dev_ps2_gif.cc
Go to the documentation of this file.
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;
60  struct vfb_data *vfb_data;
61 };
62 
63 
64 /*
65  * test_triangle():
66  *
67  * Draw a triangle:
68  */
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 
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  */
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 
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 
428  devinit->addr, DEV_PS2_GIF_LENGTH, dev_ps2_gif_access, d,
429  DM_DEFAULT, NULL);
430 
431  return 1;
432 }
433 
void fatal(const char *fmt,...)
Definition: main.cc:152
#define DM_DEFAULT
Definition: memory.h:130
struct vfb_data * vfb_data
Definition: dev_ps2_gif.cc:60
#define VFB_PLAYSTATION2
Definition: devices.h:195
struct vfb_data * dev_fb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize, int xsize, int ysize, int bit_depth, const char *name)
Definition: dev_fb.cc:834
char * name
Definition: device.h:43
struct memory * mem
Definition: cpu.h:362
DEVINIT(ps2_gif)
Definition: dev_ps2_gif.cc:399
#define MEM_READ
Definition: memory.h:116
struct memory * memory
Definition: machine.h:126
struct cpu ** cpus
Definition: machine.h:140
void 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)
Definition: dev_ps2_gif.cc:69
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
struct cpu * cpu
Definition: dev_ps2_gif.cc:56
#define PS2_FB_ADDR
Definition: dev_ps2_gif.cc:52
u_short data
Definition: siireg.h:79
#define DEV_PS2_GIF_LENGTH
Definition: dev_ps2_gif.cc:50
void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r, int fill_g, int fill_b, int x1, int y1, int x2, int y2, int from_x, int from_y)
Definition: dev_fb.cc:234
#define MEM_WRITE
Definition: memory.h:117
Definition: device.h:40
uint32_t addr
#define debug
Definition: dev_adb.cc:57
Definition: cpu.h:326
struct machine * machine
Definition: device.h:41
int dev_fb_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *)
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
DEVICE_ACCESS(ps2_gif)
Definition: dev_ps2_gif.cc:207
uint64_t addr
Definition: device.h:46
int bytes_per_pixel
Definition: dev_ps2_gif.cc:58
int transparent_text
Definition: dev_ps2_gif.cc:59

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