2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 /* This is the Playstation 2 implementation of YUV video overlays */
28 #include <sys/ioctl.h>
30 #include <asm/page.h> /* For definition of PAGE_SIZE */
32 #include "SDL_video.h"
33 #include "SDL_gsyuv_c.h"
34 #include "../SDL_yuvfuncs.h"
36 /* The maximum number of 16x16 pixel block converted at once */
37 #define MAX_MACROBLOCKS 1024 /* 2^10 macroblocks at once */
39 /* The functions used to manipulate video overlays */
40 static struct private_yuvhwfuncs gs_yuvfuncs = {
47 struct private_yuvhwdata {
56 unsigned long long *stretch_x1y1;
57 unsigned long long *stretch_x2y2;
58 struct ps2_plist plist;
60 /* These are just so we don't have to allocate them separately */
65 static int power_of_2(int value)
69 for ( shift = 0; (1<<shift) < value; ++shift ) {
75 SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display)
78 struct private_yuvhwdata *hwdata;
80 unsigned long long *tags;
86 struct ps2_packet *packet;
87 struct ps2_packet tex_packet;
89 /* We can only decode blocks of 16x16 pixels */
90 if ( (width & 15) || (height & 15) ) {
91 SDL_SetError("Overlay width/height must be multiples of 16");
94 /* Make sure the image isn't too large for a single DMA transfer */
95 if ( ((width/16) * (height/16)) > MAX_MACROBLOCKS ) {
96 SDL_SetError("Overlay too large (maximum size: %d pixels)",
97 MAX_MACROBLOCKS * 16 * 16);
101 /* Double-check the requested format. For simplicity, we'll only
102 support planar YUV formats.
105 case SDL_YV12_OVERLAY:
106 case SDL_IYUV_OVERLAY:
107 /* Supported planar YUV format */
110 SDL_SetError("Unsupported YUV format");
114 /* Create the overlay structure */
115 overlay = (SDL_Overlay *)SDL_malloc(sizeof *overlay);
116 if ( overlay == NULL ) {
120 SDL_memset(overlay, 0, (sizeof *overlay));
122 /* Fill in the basic members */
123 overlay->format = format;
127 /* Set up the YUV surface function structure */
128 overlay->hwfuncs = &gs_yuvfuncs;
129 overlay->hw_overlay = 1;
131 /* Create the pixel data */
132 hwdata = (struct private_yuvhwdata *)SDL_malloc(sizeof *hwdata);
133 overlay->hwdata = hwdata;
134 if ( hwdata == NULL ) {
135 SDL_FreeYUVOverlay(overlay);
140 hwdata->pixels = (Uint8 *)SDL_malloc(width*height*2);
141 if ( hwdata->pixels == NULL ) {
142 SDL_FreeYUVOverlay(overlay);
146 hwdata->macroblocks = (width/16) * (height/16);
148 /* Find the pitch and offset values for the overlay */
149 overlay->pitches = hwdata->pitches;
150 overlay->pixels = hwdata->planes;
152 case SDL_YV12_OVERLAY:
153 case SDL_IYUV_OVERLAY:
154 overlay->pitches[0] = overlay->w;
155 overlay->pitches[1] = overlay->pitches[0] / 2;
156 overlay->pitches[2] = overlay->pitches[0] / 2;
157 overlay->pixels[0] = hwdata->pixels;
158 overlay->pixels[1] = overlay->pixels[0] +
159 overlay->pitches[0] * overlay->h;
160 overlay->pixels[2] = overlay->pixels[1] +
161 overlay->pitches[1] * overlay->h / 2;
165 /* We should never get here (caught above) */
169 /* Theoretically we could support several concurrent decode
170 streams queueing up on the same file descriptor, but for
171 simplicity we'll support only one. Opening the IPU more
172 than once will fail with EBUSY.
174 hwdata->ipu_fd = open("/dev/ps2ipu", O_RDWR);
175 if ( hwdata->ipu_fd < 0 ) {
176 SDL_FreeYUVOverlay(overlay);
177 SDL_SetError("Playstation 2 IPU busy");
181 /* Allocate a DMA area for pixel conversion */
182 bpp = this->screen->format->BytesPerPixel;
183 map_offset = (mapped_len + (sysconf(_SC_PAGESIZE) - 1)) & ~(sysconf(_SC_PAGESIZE) - 1);
184 hwdata->dma_len = hwdata->macroblocks * (16 * 16 + 8 * 8 + 8 * 8) +
185 width * height * bpp +
186 hwdata->macroblocks * (16 * sizeof(long long)) +
187 12 * sizeof(long long);
188 hwdata->dma_mem = mmap(0, hwdata->dma_len, PROT_READ|PROT_WRITE,
189 MAP_SHARED, memory_fd, map_offset);
190 if ( hwdata->dma_mem == MAP_FAILED ) {
191 hwdata->ipu_imem = (caddr_t)0;
192 SDL_FreeYUVOverlay(overlay);
193 SDL_SetError("Unable to map %d bytes for DMA", hwdata->dma_len);
196 hwdata->ipu_imem = hwdata->dma_mem;
197 hwdata->ipu_omem = hwdata->ipu_imem +
198 hwdata->macroblocks * (16 * 16 + 8 * 8 + 8 * 8);
199 hwdata->dma_tags = hwdata->ipu_omem + width * height * bpp;
201 /* Allocate memory for the DMA packets */
202 hwdata->plist.num = hwdata->macroblocks * 4 + 1;
203 hwdata->plist.packet = (struct ps2_packet *)SDL_malloc(
204 hwdata->plist.num*sizeof(struct ps2_packet));
205 if ( ! hwdata->plist.packet ) {
206 SDL_FreeYUVOverlay(overlay);
211 packet = hwdata->plist.packet;
213 /* Set up the tags to send the image to the screen */
214 tags = (unsigned long long *)hwdata->dma_tags;
215 base = hwdata->ipu_omem;
216 fbp = screen_image.fbp;
217 fbw = screen_image.fbw;
218 psm = screen_image.psm;
219 y = screen_image.y + screen_image.h; /* Offscreen video memory */
220 for ( h=height/16; h; --h ) {
221 x = 0; /* Visible video memory */
222 for ( w=width/16; w; --w ) {
224 packet[pnum].ptr = &tags[0];
225 packet[pnum].len = 10 * sizeof(*tags);
227 tags[0] = 4 | (1LL << 60); /* GIFtag */
228 tags[1] = 0x0e; /* A+D */
229 tags[2] = ((unsigned long long)fbp << 32) |
230 ((unsigned long long)fbw << 48) |
231 ((unsigned long long)psm << 56);
232 tags[3] = PS2_GS_BITBLTBUF;
233 tags[4] = ((unsigned long long)x << 32) |
234 ((unsigned long long)y << 48);
235 tags[5] = PS2_GS_TRXPOS;
236 tags[6] = (unsigned long long)16 |
237 ((unsigned long long)16 << 32);
238 tags[7] = PS2_GS_TRXREG;
240 tags[9] = PS2_GS_TRXDIR;
241 /* Now the actual image data */
242 packet[pnum].ptr = &tags[10];
243 packet[pnum].len = 2 * sizeof(*tags);
245 tags[10] = ((16*16*bpp) >> 4) | (2LL << 58);
247 packet[pnum].ptr = (void *)base;
248 packet[pnum].len = 16 * 16 * bpp;
250 packet[pnum].ptr = &tags[12];
251 packet[pnum].len = 2 * sizeof(*tags);
253 tags[12] = (0 >> 4) | (1 << 15) | (2LL << 58);
257 base += 16 * 16 * bpp;
264 /* Set up the texture memory area for the video */
265 tex_packet.ptr = tags;
266 tex_packet.len = 8 * sizeof(*tags);
267 tags[0] = 3 | (1LL << 60); /* GIFtag */
268 tags[1] = 0x0e; /* A+D */
269 tags[2] = ((screen_image.y + screen_image.h) * screen_image.w) / 64 +
270 ((unsigned long long)fbw << 14) +
271 ((unsigned long long)psm << 20) +
272 ((unsigned long long)power_of_2(width) << 26) +
273 ((unsigned long long)power_of_2(height) << 30) +
274 ((unsigned long long)1 << 34) +
275 ((unsigned long long)1 << 35);
276 tags[3] = PS2_GS_TEX0_1;
277 tags[4] = (1 << 5) + (1 << 6);
278 tags[5] = PS2_GS_TEX1_1;
280 tags[7] = PS2_GS_TEXFLUSH;
281 ioctl(console_fd, PS2IOC_SEND, &tex_packet);
283 /* Set up the tags for scaling the image */
284 packet[pnum].ptr = tags;
285 packet[pnum].len = 12 * sizeof(*tags);
287 tags[0] = 5 | (1LL << 60); /* GIFtag */
288 tags[1] = 0x0e; /* A+D */
289 tags[2] = 6 + (1 << 4) + (1 << 8);
290 tags[3] = PS2_GS_PRIM;
291 tags[4] = ((unsigned long long)0 * 16) +
292 (((unsigned long long)0 * 16) << 16);
294 tags[6] = 0; /* X1, Y1 */
295 tags[7] = PS2_GS_XYZ2;
296 hwdata->stretch_x1y1 = &tags[6];
297 tags[8] = ((unsigned long long)overlay->w * 16) +
298 (((unsigned long long)overlay->h * 16) << 16);
300 tags[10] = 0; /* X2, Y2 */
301 tags[11] = PS2_GS_XYZ2;
302 hwdata->stretch_x2y2 = &tags[10];
304 /* We're all done.. */
308 int GS_LockYUVOverlay(_THIS, SDL_Overlay *overlay)
313 void GS_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay)
318 int GS_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst)
320 struct private_yuvhwdata *hwdata;
322 struct ps2_packet packet;
324 Uint32 *lum, *Cr, *Cb;
327 Uint32 *lum_src, *Cr_src, *Cb_src;
332 /* Find out where the various portions of the image are */
333 hwdata = overlay->hwdata;
334 switch (overlay->format) {
335 case SDL_YV12_OVERLAY:
336 lum = (Uint32 *)overlay->pixels[0];
337 Cr = (Uint32 *)overlay->pixels[1];
338 Cb = (Uint32 *)overlay->pixels[2];
340 case SDL_IYUV_OVERLAY:
341 lum = (Uint32 *)overlay->pixels[0];
342 Cr = (Uint32 *)overlay->pixels[2];
343 Cb = (Uint32 *)overlay->pixels[1];
345 SDL_SetError("Unsupported YUV format in blit (?)");
348 dstp = (Uint32 *)hwdata->ipu_imem;
349 lum_pitch = overlay->w/4;
350 crb_pitch = (overlay->w/2)/4;
352 /* Copy blocks of 16x16 pixels to the DMA area */
353 for ( h=overlay->h/16; h; --h ) {
357 for ( w=overlay->w/16; w; --w ) {
359 for ( i=0; i<16; ++i ) {
368 for ( i=0; i<8; ++i ) {
375 for ( i=0; i<8; ++i ) {
385 lum += lum_pitch * 16;
390 /* Send the macroblock data to the IPU */
392 fprintf(stderr, "Sending data to IPU..\n");
394 packet.ptr = hwdata->ipu_imem;
395 packet.len = hwdata->macroblocks * (16 * 16 + 8 * 8 + 8 * 8);
396 ioctl(hwdata->ipu_fd, PS2IOC_SENDA, &packet);
398 /* Trigger the DMA to the IPU for conversion */
400 fprintf(stderr, "Trigging conversion command\n");
402 cmd = (7 << 28) + hwdata->macroblocks;
403 if ( screen_image.psm == PS2_GS_PSMCT16 ) {
404 cmd += (1 << 27) + /* Output RGB 555 */
405 (1 << 26); /* Dither output */
407 ioctl(hwdata->ipu_fd, PS2IOC_SIPUCMD, &cmd);
409 /* Retrieve the converted image from the IPU */
411 fprintf(stderr, "Retrieving data from IPU..\n");
413 packet.ptr = hwdata->ipu_omem;
414 packet.len = overlay->w * overlay->h *
415 this->screen->format->BytesPerPixel;
416 ioctl(hwdata->ipu_fd, PS2IOC_RECV, &packet);
419 fprintf(stderr, "Copying image to screen..\n");
421 /* Wait for previous DMA to complete */
422 ioctl(console_fd, PS2IOC_SENDQCT, 1);
424 /* Send the current image to the screen and scale it */
425 screen = this->screen;
426 x = (unsigned int)dst->x;
427 y = (unsigned int)dst->y;
428 if ( screen->offset ) {
429 x += (screen->offset % screen->pitch) /
430 screen->format->BytesPerPixel;
431 y += (screen->offset / screen->pitch);
434 *hwdata->stretch_x1y1 = (x * 16) + ((y * 16) << 16);
435 x += (unsigned int)dst->w;
436 y += (unsigned int)dst->h;
437 *hwdata->stretch_x2y2 = (x * 16) + ((y * 16) << 16);
438 return ioctl(console_fd, PS2IOC_SENDL, &hwdata->plist);
441 void GS_FreeYUVOverlay(_THIS, SDL_Overlay *overlay)
443 struct private_yuvhwdata *hwdata;
445 hwdata = overlay->hwdata;
447 if ( hwdata->ipu_fd >= 0 ) {
448 close(hwdata->ipu_fd);
450 if ( hwdata->dma_mem ) {
451 munmap(hwdata->dma_mem, hwdata->dma_len);
453 if ( hwdata->plist.packet ) {
454 SDL_free(hwdata->plist.packet);
456 if ( hwdata->pixels ) {
457 SDL_free(hwdata->pixels);