SDL_Overlay *PS3_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) { /* Only RGB packed pixel conversion supported */ if ((display->format->BytesPerPixel != 2) && (display->format->BytesPerPixel != 3) && (display->format->BytesPerPixel != 4)) { SDL_SetError ("Can't use YUV data on non 16/24/32 bit surfaces"); return NULL; } /* Double-check the requested format. We'll only support YV12 */ switch (format) { case SDL_IYUV_OVERLAY: case SDL_YV12_OVERLAY: /* Supported YUV format */ break; default: SDL_SetError("Unsupported YUV format"); return NULL; } SDL_Overlay* overlay; struct private_yuvhwdata* hwdata; /* Create the overlay structure */ overlay = (SDL_Overlay *) SDL_calloc(1, sizeof(SDL_Overlay)); if (overlay == NULL) { SDL_OutOfMemory(); return NULL; } SDL_memset(overlay, 0, (sizeof *overlay)); /* Set the basic attributes */ overlay->format = format; overlay->w = width; overlay->h = height; overlay->hwdata = NULL; /* Set up the PS3 YUV surface function structure */ overlay->hwfuncs = &ps3_yuvfuncs; /* Create the pixel data and lookup tables */ hwdata = (struct private_yuvhwdata *) SDL_calloc(1, sizeof(struct private_yuvhwdata)); if (hwdata == NULL) { SDL_OutOfMemory(); SDL_FreeYUVOverlay(overlay); return NULL; } overlay->hwdata = hwdata; hwdata->stretch = NULL; hwdata->display = display; /* Create SPU parms structure */ hwdata->converter_parms = (struct yuv2rgb_parms_t *) memalign(16, sizeof(struct yuv2rgb_parms_t)); hwdata->scaler_parms = (struct scale_parms_t *) memalign(16, sizeof(struct scale_parms_t)); if (hwdata->converter_parms == NULL || hwdata->scaler_parms == NULL) { SDL_FreeYUVOverlay(overlay); SDL_OutOfMemory(); return(NULL); } /* Set up the SPEs */ scaler_thread_data = (spu_data_t *) malloc(sizeof(spu_data_t)); converter_thread_data = (spu_data_t *) malloc(sizeof(spu_data_t)); if (converter_thread_data == NULL || scaler_thread_data == NULL) { SDL_FreeYUVOverlay(overlay); SDL_OutOfMemory(); return(NULL); } scaler_thread_data->program = bilin_scaler_spu; scaler_thread_data->program_name = "bilin_scaler_spu"; scaler_thread_data->keepalive = 0; scaler_thread_data->booted = 0; converter_thread_data->program = yuv2rgb_spu; converter_thread_data->program_name = "yuv2rgb_spu"; converter_thread_data->keepalive = 1; converter_thread_data->booted = 0; SPE_Start(this, converter_thread_data); hwdata->pixels = (Uint8 *) memalign(16, width * height + ((width * height) >> 1)); if (hwdata->pixels == NULL) { SDL_FreeYUVOverlay(overlay); SDL_OutOfMemory(); return(NULL); } /* Find the pitch and offset values for the overlay */ overlay->pitches = hwdata->pitches; overlay->pixels = hwdata->planes; switch (format) { case SDL_YV12_OVERLAY: case SDL_IYUV_OVERLAY: overlay->pitches[0] = overlay->w; overlay->pitches[1] = overlay->pitches[0] / 2; overlay->pitches[2] = overlay->pitches[0] / 2; overlay->pixels[0] = (Uint8 *)hwdata->pixels; overlay->pixels[1] = overlay->pixels[0] + overlay->pitches[0] * overlay->h; overlay->pixels[2] = overlay->pixels[1] + overlay->pitches[1] * overlay->h / 2; overlay->planes = 3; break; default: /* We should never get here (caught above) */ break; } /* We're all done.. */ return overlay; }
static int PS3_VideoInit(_THIS, SDL_PixelFormat * vformat) { enable_cursor(0); fb_parms = (struct fb_writer_parms_t *) memalign(16, sizeof(struct fb_writer_parms_t)); fb_thread_data = (spu_data_t *) malloc(sizeof(spu_data_t)); if (fb_parms == NULL || fb_thread_data == NULL) { SDL_OutOfMemory(); return -1; } fb_thread_data->program = fb_writer_spu; fb_thread_data->program_name = "fb_writer_spu"; fb_thread_data->argp = (void *)fb_parms; fb_thread_data->keepalive = 1; fb_thread_data->booted = 0; SPE_Start(this, fb_thread_data); fb_dev_fd = open(PS3_DEV_FB, O_RDWR); if (fb_dev_fd < 0) { SDL_SetError("[PS3] Unable to open device %s", PS3_DEV_FB); return -1; } if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) { SDL_SetError("[PS3] Can't get VSCREENINFO"); if (fb_dev_fd >= 0) close(fb_dev_fd); fb_dev_fd = -1; return -1; } this->info.current_w = fb_vinfo.xres; this->info.current_h = fb_vinfo.yres; this->info.wm_available = 0; this->info.hw_available = 1; fb_orig_vinfo = fb_vinfo; fb_bits_per_pixel = fb_vinfo.bits_per_pixel; if (fb_bits_per_pixel == 16) fb_bits_per_pixel = fb_vinfo.red.length + fb_vinfo.green.length + fb_vinfo.blue.length; vformat->BitsPerPixel = fb_vinfo.bits_per_pixel; fb_vinfo.xres_virtual = fb_vinfo.xres; fb_vinfo.yres_virtual = fb_vinfo.yres; if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_vinfo)) { SDL_SetError("[PS3] Can't put VSCREENINFO"); if (fb_dev_fd >= 0) close(fb_dev_fd); fb_dev_fd = -1; return -1; } s_fb_pixel_size = fb_vinfo.bits_per_pixel / 8; s_writeable_width = fb_vinfo.xres; s_writeable_height = fb_vinfo.yres; if (ioctl(fb_dev_fd, PS3FB_IOCTL_SCREENINFO, (unsigned long)&res) < 0) { SDL_SetError("[PS3] PS3FB_IOCTL_SCREENINFO failed"); } deprintf(1, "[PS3] xres:%d yres:%d xoff:%d yoff:%d\n", res.xres, res.yres, res.xoff, res.yoff); if (res.num_frames < 2) { double_buffering = 0; } else { double_buffering = 1; } real_width = res.xres; real_height = res.yres; ioctl(fb_dev_fd, PS3FB_IOCTL_ON, 0); ioctl(fb_dev_fd, FBIOBLANK, 0); return 0; }
int PS3_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst) { if ((overlay == NULL) || (overlay->hwdata == NULL)) { return -1; } Uint8 *lum, *Cr, *Cb; struct private_yuvhwdata *hwdata; SDL_Surface *display; hwdata = overlay->hwdata; display = hwdata->display; /* Do we have to scale? */ if ((src->w != dst->w) || (src->h != dst->h) ) { hwdata->scale = 1; deprintf(1, "[PS3] We need to scale\n"); } else { hwdata->scale = 0; deprintf(1, "[PS3] No scaling\n"); } /* Find out where the various portions of the image are */ switch (overlay->format) { case SDL_YV12_OVERLAY: lum = (Uint8 *)overlay->pixels[0]; Cr = (Uint8 *)overlay->pixels[1]; Cb = (Uint8 *)overlay->pixels[2]; break; case SDL_IYUV_OVERLAY: lum = (Uint8 *)overlay->pixels[0]; Cr = (Uint8 *)overlay->pixels[2]; Cb = (Uint8 *)overlay->pixels[1]; break; default: SDL_SetError("Unsupported YUV format in blit"); return -1; } if (hwdata->scale) { /* Alloc mem for scaled YUV picture */ hwdata->scaler_out = (Uint8 *) memalign(16, dst->w * dst->h + ((dst->w * dst->h) >> 1)); if (hwdata->scaler_out == NULL) { SDL_FreeYUVOverlay(overlay); SDL_OutOfMemory(); return -1; } /* Set parms for scaling */ hwdata->scaler_parms->src_pixel_width = src->w; hwdata->scaler_parms->src_pixel_height = src->h; hwdata->scaler_parms->dst_pixel_width = dst->w; hwdata->scaler_parms->dst_pixel_height = dst->h; hwdata->scaler_parms->y_plane = lum; hwdata->scaler_parms->v_plane = Cr; hwdata->scaler_parms->u_plane = Cb; hwdata->scaler_parms->dstBuffer = hwdata->scaler_out; scaler_thread_data->argp = (void *)hwdata->scaler_parms; /* Scale the YUV overlay to given size */ SPE_Start(this, scaler_thread_data); SPE_Stop(this, scaler_thread_data); /* Set parms for converting after scaling */ hwdata->converter_parms->y_plane = hwdata->scaler_out; hwdata->converter_parms->v_plane = hwdata->scaler_out + dst->w * dst->h; hwdata->converter_parms->u_plane = hwdata->scaler_out + dst->w * dst->h + ((dst->w * dst->h) >> 2); } else {
int PS3_VideoInit(_THIS) { int i; deprintf(1, "PS3_VideoInit()\n"); SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; SDL_DisplayMode mode; /* Create SPU fb_parms and thread structure */ data->fb_parms = (struct fb_writer_parms_t *) memalign(16, sizeof(struct fb_writer_parms_t)); data->fb_thread_data = (spu_data_t *) malloc(sizeof(spu_data_t)); if (data->fb_parms == NULL || data->fb_thread_data == NULL) { SDL_OutOfMemory(); return -1; } data->fb_thread_data->program = fb_writer_spu; data->fb_thread_data->program_name = "fb_writer_spu"; data->fb_thread_data->argp = (void *)data->fb_parms; data->fb_thread_data->keepalive = 1; data->fb_thread_data->booted = 0; SPE_Start(data->fb_thread_data); /* Open the device */ data->fbdev = open(PS3DEV, O_RDWR); if (data->fbdev < 0) { SDL_SetError("[PS3] Unable to open device %s", PS3DEV); return -1; } /* Take control of frame buffer from kernel, for details see * http://felter.org/wesley/files/ps3/linux-20061110-docs/ApplicationProgrammingEnvironment.html * kernel will no longer flip the screen itself */ ioctl(data->fbdev, PS3FB_IOCTL_ON, 0); /* Unblank screen */ ioctl(data->fbdev, FBIOBLANK, 0); struct fb_fix_screeninfo fb_finfo; if (ioctl(data->fbdev, FBIOGET_FSCREENINFO, &fb_finfo)) { SDL_SetError("[PS3] Can't get fixed screeninfo"); return (0); } /* Note: on PS3, fb_finfo.smem_len is enough for double buffering */ if ((data->frame_buffer = (uint8_t *)mmap(0, fb_finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, data->fbdev, 0)) == (uint8_t *) - 1) { SDL_SetError("[PS3] Can't mmap for %s", PS3DEV); return (0); } else { /* Enable double buffering */ } /* Blank screen */ memset(data->frame_buffer, 0x00, fb_finfo.smem_len); PS3_InitModes(_this); for (i = 0; i < _this->num_displays; ++i) { SDL_AddRenderDriver(&_this->displays[i], &SDL_PS3_RenderDriver); } /* We're done! */ return 0; }