Mercurial > sdl-ios-xcode
comparison src/video/ps3/SDL_ps3render.c @ 3257:94fb40a4a9a7
Merged Martin's code changes from Google Summer of Code 2009
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 07 Sep 2009 04:51:29 +0000 |
parents | |
children | f638ded38b8a |
comparison
equal
deleted
inserted
replaced
3256:83c87f2b2aab | 3257:94fb40a4a9a7 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997-2009 Sam Lantinga | |
4 | |
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. | |
9 | |
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. | |
14 | |
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 | |
18 | |
19 Sam Lantinga | |
20 slouken@libsdl.org | |
21 */ | |
22 #include "SDL_config.h" | |
23 | |
24 #include "SDL_video.h" | |
25 #include "../SDL_sysvideo.h" | |
26 #include "../SDL_yuv_sw_c.h" | |
27 #include "../SDL_renderer_sw.h" | |
28 | |
29 #include "SDL_ps3video.h" | |
30 #include "SDL_ps3spe_c.h" | |
31 | |
32 #include <fcntl.h> | |
33 #include <stdlib.h> | |
34 #include <sys/ioctl.h> | |
35 #include <linux/kd.h> | |
36 #include <linux/fb.h> | |
37 #include <sys/mman.h> | |
38 #include <asm/ps3fb.h> | |
39 | |
40 | |
41 /* Stores the executable name */ | |
42 extern spe_program_handle_t yuv2rgb_spu; | |
43 extern spe_program_handle_t bilin_scaler_spu; | |
44 | |
45 /* SDL surface based renderer implementation */ | |
46 static SDL_Renderer *SDL_PS3_CreateRenderer(SDL_Window * window, | |
47 Uint32 flags); | |
48 static int SDL_PS3_DisplayModeChanged(SDL_Renderer * renderer); | |
49 static int SDL_PS3_ActivateRenderer(SDL_Renderer * renderer); | |
50 static int SDL_PS3_RenderPoint(SDL_Renderer * renderer, int x, int y); | |
51 static int SDL_PS3_RenderLine(SDL_Renderer * renderer, int x1, int y1, | |
52 int x2, int y2); | |
53 static int SDL_PS3_RenderFill(SDL_Renderer * renderer, | |
54 const SDL_Rect * rect); | |
55 static int SDL_PS3_RenderCopy(SDL_Renderer * renderer, | |
56 SDL_Texture * texture, | |
57 const SDL_Rect * srcrect, | |
58 const SDL_Rect * dstrect); | |
59 static void SDL_PS3_RenderPresent(SDL_Renderer * renderer); | |
60 static void SDL_PS3_DestroyRenderer(SDL_Renderer * renderer); | |
61 | |
62 /* Texture */ | |
63 static int PS3_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
64 static int PS3_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch); | |
65 static int PS3_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch); | |
66 static int PS3_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, int markDirty, void **pixels, int *pitch); | |
67 static void PS3_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
68 static void PS3_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
69 | |
70 | |
71 SDL_RenderDriver SDL_PS3_RenderDriver = { | |
72 SDL_PS3_CreateRenderer, | |
73 { | |
74 "ps3", | |
75 (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTVSYNC | | |
76 SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTDISCARD | | |
77 SDL_RENDERER_ACCELERATED), | |
78 (SDL_TEXTUREMODULATE_NONE), | |
79 (SDL_BLENDMODE_NONE), | |
80 /* We use bilinear scaling on the SPE for YV12 & IYUV | |
81 * (width and height % 8 = 0) */ | |
82 (SDL_TEXTURESCALEMODE_SLOW) | |
83 } | |
84 }; | |
85 | |
86 typedef struct | |
87 { | |
88 int current_screen; | |
89 SDL_Surface *screen; | |
90 SDL_VideoDisplay *display; | |
91 /* adress of the centered image in the framebuffer (double buffered) */ | |
92 uint8_t *center[2]; | |
93 | |
94 /* width of input (bounded by writeable width) */ | |
95 unsigned int bounded_width; | |
96 /* height of input (bounded by writeable height) */ | |
97 unsigned int bounded_height; | |
98 /* offset from the left side (used for centering) */ | |
99 unsigned int offset_left; | |
100 /* offset from the upper side (used for centering) */ | |
101 unsigned int offset_top; | |
102 /* width of screen which is writeable */ | |
103 unsigned int wr_width; | |
104 /* width of screen which is writeable */ | |
105 unsigned int wr_height; | |
106 /* size of a screen line: width * bpp/8 */ | |
107 unsigned int line_length; | |
108 | |
109 /* Is the kernels fb size bigger than ~12MB | |
110 * double buffering will work for 1080p */ | |
111 unsigned int double_buffering; | |
112 | |
113 /* SPE threading stuff */ | |
114 spu_data_t *converter_thread_data; | |
115 spu_data_t *scaler_thread_data; | |
116 | |
117 /* YUV converting transfer data */ | |
118 volatile struct yuv2rgb_parms_t * converter_parms __attribute__((aligned(128))); | |
119 /* Scaler transfer data */ | |
120 volatile struct scale_parms_t * scaler_parms __attribute__((aligned(128))); | |
121 } SDL_PS3_RenderData; | |
122 | |
123 typedef struct | |
124 { | |
125 int pitch; | |
126 /* Image data */ | |
127 volatile void *pixels; | |
128 /* Use software renderer for not supported formats */ | |
129 SDL_SW_YUVTexture *yuv; | |
130 } PS3_TextureData; | |
131 | |
132 SDL_Renderer * | |
133 SDL_PS3_CreateRenderer(SDL_Window * window, Uint32 flags) | |
134 { | |
135 deprintf(1, "+SDL_PS3_CreateRenderer()\n"); | |
136 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | |
137 SDL_DisplayMode *displayMode = &display->current_mode; | |
138 SDL_VideoData *devdata = display->device->driverdata; | |
139 SDL_Renderer *renderer; | |
140 SDL_PS3_RenderData *data; | |
141 struct ps3fb_ioctl_res res; | |
142 int i, n; | |
143 int bpp; | |
144 Uint32 Rmask, Gmask, Bmask, Amask; | |
145 | |
146 if (!SDL_PixelFormatEnumToMasks | |
147 (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { | |
148 SDL_SetError("Unknown display format"); | |
149 return NULL; | |
150 } | |
151 | |
152 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); | |
153 if (!renderer) { | |
154 SDL_OutOfMemory(); | |
155 return NULL; | |
156 } | |
157 | |
158 data = (SDL_PS3_RenderData *) SDL_malloc(sizeof(*data)); | |
159 if (!data) { | |
160 SDL_PS3_DestroyRenderer(renderer); | |
161 SDL_OutOfMemory(); | |
162 return NULL; | |
163 } | |
164 SDL_zerop(data); | |
165 | |
166 renderer->CreateTexture = PS3_CreateTexture; | |
167 renderer->DestroyTexture = PS3_DestroyTexture; | |
168 renderer->QueryTexturePixels = PS3_QueryTexturePixels; | |
169 renderer->UpdateTexture = PS3_UpdateTexture; | |
170 renderer->LockTexture = PS3_LockTexture; | |
171 renderer->UnlockTexture = PS3_UnlockTexture; | |
172 renderer->ActivateRenderer = SDL_PS3_ActivateRenderer; | |
173 renderer->DisplayModeChanged = SDL_PS3_DisplayModeChanged; | |
174 renderer->RenderPoint = SDL_PS3_RenderPoint; | |
175 renderer->RenderLine = SDL_PS3_RenderLine; | |
176 renderer->RenderFill = SDL_PS3_RenderFill; | |
177 renderer->RenderCopy = SDL_PS3_RenderCopy; | |
178 renderer->RenderPresent = SDL_PS3_RenderPresent; | |
179 renderer->DestroyRenderer = SDL_PS3_DestroyRenderer; | |
180 renderer->info.name = SDL_PS3_RenderDriver.info.name; | |
181 renderer->info.flags = 0; | |
182 renderer->window = window->id; | |
183 renderer->driverdata = data; | |
184 | |
185 deprintf(1, "window->w = %u\n", window->w); | |
186 deprintf(1, "window->h = %u\n", window->h); | |
187 | |
188 data->double_buffering = 0; | |
189 | |
190 /* Get ps3 screeninfo */ | |
191 if (ioctl(devdata->fbdev, PS3FB_IOCTL_SCREENINFO, (unsigned long)&res) < 0) { | |
192 SDL_SetError("[PS3] PS3FB_IOCTL_SCREENINFO failed"); | |
193 } | |
194 deprintf(2, "res.num_frames = %d\n", res.num_frames); | |
195 | |
196 /* Only use double buffering if enough fb memory is available */ | |
197 if (res.num_frames > 1) { | |
198 renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2; | |
199 n = 2; | |
200 data->double_buffering = 1; | |
201 } else { | |
202 renderer->info.flags |= SDL_RENDERER_PRESENTCOPY; | |
203 n = 1; | |
204 } | |
205 | |
206 data->screen = | |
207 SDL_CreateRGBSurface(0, window->w, window->h, bpp, Rmask, Gmask, | |
208 Bmask, Amask); | |
209 if (!data->screen) { | |
210 SDL_PS3_DestroyRenderer(renderer); | |
211 return NULL; | |
212 } | |
213 /* Allocate aligned memory for pixels */ | |
214 SDL_free(data->screen->pixels); | |
215 data->screen->pixels = (void *)memalign(16, data->screen->h * data->screen->pitch); | |
216 if (!data->screen->pixels) { | |
217 SDL_FreeSurface(data->screen); | |
218 SDL_OutOfMemory(); | |
219 return NULL; | |
220 } | |
221 SDL_memset(data->screen->pixels, 0, data->screen->h * data->screen->pitch); | |
222 SDL_SetSurfacePalette(data->screen, display->palette); | |
223 | |
224 data->current_screen = 0; | |
225 | |
226 /* Create SPU parms structure */ | |
227 data->converter_parms = (struct yuv2rgb_parms_t *) memalign(16, sizeof(struct yuv2rgb_parms_t)); | |
228 data->scaler_parms = (struct scale_parms_t *) memalign(16, sizeof(struct scale_parms_t)); | |
229 if (data->converter_parms == NULL || data->scaler_parms == NULL) { | |
230 SDL_PS3_DestroyRenderer(renderer); | |
231 SDL_OutOfMemory(); | |
232 return NULL; | |
233 } | |
234 | |
235 /* Set up the SPE threading data */ | |
236 data->converter_thread_data = (spu_data_t *) malloc(sizeof(spu_data_t)); | |
237 data->scaler_thread_data = (spu_data_t *) malloc(sizeof(spu_data_t)); | |
238 if (data->converter_thread_data == NULL || data->scaler_thread_data == NULL) { | |
239 SDL_PS3_DestroyRenderer(renderer); | |
240 SDL_OutOfMemory(); | |
241 return NULL; | |
242 } | |
243 | |
244 /* Set up the SPE scaler (booted) */ | |
245 data->scaler_thread_data->program = bilin_scaler_spu; | |
246 data->scaler_thread_data->program_name = "bilin_scaler_spu"; | |
247 data->scaler_thread_data->keepalive = 0; | |
248 data->scaler_thread_data->booted = 0; | |
249 | |
250 /* Set up the SPE converter (always running) */ | |
251 data->converter_thread_data->program = yuv2rgb_spu; | |
252 data->converter_thread_data->program_name = "yuv2rgb_spu"; | |
253 data->converter_thread_data->keepalive = 1; | |
254 data->converter_thread_data->booted = 0; | |
255 | |
256 SPE_Start(data->converter_thread_data); | |
257 | |
258 deprintf(1, "-SDL_PS3_CreateRenderer()\n"); | |
259 return renderer; | |
260 } | |
261 | |
262 static int | |
263 SDL_PS3_ActivateRenderer(SDL_Renderer * renderer) | |
264 { | |
265 deprintf(1, "+PS3_ActivateRenderer()\n"); | |
266 SDL_PS3_RenderData *data = (SDL_PS3_RenderData *) renderer->driverdata; | |
267 | |
268 deprintf(1, "-PS3_ActivateRenderer()\n"); | |
269 return 0; | |
270 } | |
271 | |
272 static int SDL_PS3_DisplayModeChanged(SDL_Renderer * renderer) { | |
273 deprintf(1, "+PS3_DisplayModeChanged()\n"); | |
274 SDL_PS3_RenderData *data = (SDL_PS3_RenderData *) renderer->driverdata; | |
275 | |
276 deprintf(1, "-PS3_DisplayModeChanged()\n"); | |
277 return 0; | |
278 } | |
279 | |
280 static int | |
281 PS3_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { | |
282 deprintf(1, "+PS3_CreateTexture()\n"); | |
283 PS3_TextureData *data; | |
284 data = (PS3_TextureData *) SDL_calloc(1, sizeof(*data)); | |
285 if (!data) { | |
286 SDL_OutOfMemory(); | |
287 return -1; | |
288 } | |
289 data->pitch = (texture->w * SDL_BYTESPERPIXEL(texture->format)); | |
290 | |
291 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
292 /* Use SDLs SW_YUVTexture */ | |
293 data->yuv = | |
294 SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h); | |
295 if (!data->yuv) { | |
296 SDL_OutOfMemory(); | |
297 return -1; | |
298 } | |
299 /* but align pixels */ | |
300 SDL_free(data->yuv->pixels); | |
301 data->yuv->pixels = (Uint8 *)memalign(16, texture->w * texture->h * 2); | |
302 if (!data->yuv->pixels) { | |
303 SDL_OutOfMemory(); | |
304 return -1; | |
305 } | |
306 | |
307 /* Redo: Find the pitch and offset values for the overlay */ | |
308 SDL_SW_YUVTexture *swdata = (SDL_SW_YUVTexture *) data->yuv; | |
309 switch (texture->format) { | |
310 case SDL_PIXELFORMAT_YV12: | |
311 case SDL_PIXELFORMAT_IYUV: | |
312 swdata->pitches[0] = texture->w; | |
313 swdata->pitches[1] = swdata->pitches[0] / 2; | |
314 swdata->pitches[2] = swdata->pitches[0] / 2; | |
315 swdata->planes[0] = swdata->pixels; | |
316 swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * texture->h; | |
317 swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * texture->h / 2; | |
318 break; | |
319 case SDL_PIXELFORMAT_YUY2: | |
320 case SDL_PIXELFORMAT_UYVY: | |
321 case SDL_PIXELFORMAT_YVYU: | |
322 swdata->pitches[0] = texture->w * 2; | |
323 swdata->planes[0] = swdata->pixels; | |
324 break; | |
325 default: | |
326 /* We should never get here (caught above) */ | |
327 break; | |
328 } | |
329 } else { | |
330 data->pixels = NULL; | |
331 data->pixels = SDL_malloc(texture->h * data->pitch); | |
332 if (!data->pixels) { | |
333 PS3_DestroyTexture(renderer, texture); | |
334 SDL_OutOfMemory(); | |
335 return -1; | |
336 } | |
337 } | |
338 texture->driverdata = data; | |
339 deprintf(1, "-PS3_CreateTexture()\n"); | |
340 return 0; | |
341 } | |
342 | |
343 static int | |
344 PS3_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, | |
345 void **pixels, int *pitch) | |
346 { | |
347 deprintf(1, "+PS3_QueryTexturePixels()\n"); | |
348 PS3_TextureData *data = (PS3_TextureData *) texture->driverdata; | |
349 | |
350 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
351 return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch); | |
352 } else { | |
353 *pixels = (void *)data->pixels; | |
354 *pitch = data->pitch; | |
355 } | |
356 | |
357 deprintf(1, "-PS3_QueryTexturePixels()\n"); | |
358 return 0; | |
359 } | |
360 | |
361 static int | |
362 PS3_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
363 const SDL_Rect * rect, const void *pixels, int pitch) | |
364 { | |
365 deprintf(1, "+PS3_UpdateTexture()\n"); | |
366 PS3_TextureData *data = (PS3_TextureData *) texture->driverdata; | |
367 | |
368 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
369 return SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch); | |
370 } else { | |
371 Uint8 *src, *dst; | |
372 int row; | |
373 size_t length; | |
374 Uint8 *dstpixels; | |
375 | |
376 src = (Uint8 *) pixels; | |
377 dst = (Uint8 *) dstpixels + rect->y * data->pitch + rect->x | |
378 * SDL_BYTESPERPIXEL(texture->format); | |
379 length = rect->w * SDL_BYTESPERPIXEL(texture->format); | |
380 /* Update the texture */ | |
381 for (row = 0; row < rect->h; ++row) { | |
382 SDL_memcpy(dst, src, length); | |
383 src += pitch; | |
384 dst += data->pitch; | |
385 } | |
386 } | |
387 deprintf(1, "-PS3_UpdateTexture()\n"); | |
388 return 0; | |
389 } | |
390 | |
391 static int | |
392 PS3_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
393 const SDL_Rect * rect, int markDirty, void **pixels, | |
394 int *pitch) | |
395 { | |
396 deprintf(1, "+PS3_LockTexture()\n"); | |
397 PS3_TextureData *data = (PS3_TextureData *) texture->driverdata; | |
398 | |
399 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
400 deprintf(1, "-PS3_LockTexture()\n"); | |
401 return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels, pitch); | |
402 } else { | |
403 *pixels = | |
404 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + | |
405 rect->x * SDL_BYTESPERPIXEL(texture->format)); | |
406 *pitch = data->pitch; | |
407 deprintf(1, "-PS3_LockTexture()\n"); | |
408 return 0; | |
409 } | |
410 } | |
411 | |
412 static void | |
413 PS3_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
414 { | |
415 deprintf(1, "+PS3_UnlockTexture()\n"); | |
416 PS3_TextureData *data = (PS3_TextureData *) texture->driverdata; | |
417 | |
418 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
419 SDL_SW_UnlockYUVTexture(data->yuv); | |
420 } | |
421 deprintf(1, "-PS3_UnlockTexture()\n"); | |
422 } | |
423 | |
424 static void | |
425 PS3_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
426 { | |
427 deprintf(1, "+PS3_DestroyTexture()\n"); | |
428 PS3_TextureData *data = (PS3_TextureData *) texture->driverdata; | |
429 | |
430 if (!data) { | |
431 return; | |
432 } | |
433 if (data->yuv) { | |
434 SDL_SW_DestroyYUVTexture(data->yuv); | |
435 } | |
436 if (data->pixels) { | |
437 SDL_free((void *)data->pixels); | |
438 } | |
439 deprintf(1, "-PS3_DestroyTexture()\n"); | |
440 } | |
441 | |
442 static int | |
443 SDL_PS3_RenderPoint(SDL_Renderer * renderer, int x, int y) | |
444 { | |
445 SDL_PS3_RenderData *data = | |
446 (SDL_PS3_RenderData *) renderer->driverdata; | |
447 SDL_Surface *target = data->screen; | |
448 int status; | |
449 | |
450 if (renderer->blendMode == SDL_BLENDMODE_NONE || | |
451 renderer->blendMode == SDL_BLENDMODE_MASK) { | |
452 Uint32 color = | |
453 SDL_MapRGBA(target->format, renderer->r, renderer->g, renderer->b, | |
454 renderer->a); | |
455 | |
456 status = SDL_DrawPoint(target, x, y, color); | |
457 } else { | |
458 status = | |
459 SDL_BlendPoint(target, x, y, renderer->blendMode, renderer->r, | |
460 renderer->g, renderer->b, renderer->a); | |
461 } | |
462 return status; | |
463 } | |
464 | |
465 static int | |
466 SDL_PS3_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) | |
467 { | |
468 SDL_PS3_RenderData *data = | |
469 (SDL_PS3_RenderData *) renderer->driverdata; | |
470 SDL_Surface *target = data->screen; | |
471 int status; | |
472 | |
473 if (renderer->blendMode == SDL_BLENDMODE_NONE || | |
474 renderer->blendMode == SDL_BLENDMODE_MASK) { | |
475 Uint32 color = | |
476 SDL_MapRGBA(target->format, renderer->r, renderer->g, renderer->b, | |
477 renderer->a); | |
478 | |
479 status = SDL_DrawLine(target, x1, y1, x2, y2, color); | |
480 } else { | |
481 status = | |
482 SDL_BlendLine(target, x1, y1, x2, y2, renderer->blendMode, | |
483 renderer->r, renderer->g, renderer->b, renderer->a); | |
484 } | |
485 return status; | |
486 } | |
487 | |
488 static int | |
489 SDL_PS3_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect) | |
490 { | |
491 deprintf(1, "SDL_PS3_RenderFill()\n"); | |
492 SDL_PS3_RenderData *data = | |
493 (SDL_PS3_RenderData *) renderer->driverdata; | |
494 SDL_Surface *target = data->screen; | |
495 SDL_Rect real_rect = *rect; | |
496 int status; | |
497 | |
498 if (renderer->blendMode == SDL_BLENDMODE_NONE) { | |
499 Uint32 color = | |
500 SDL_MapRGBA(target->format, renderer->r, renderer->g, renderer->b, | |
501 renderer->a); | |
502 | |
503 status = SDL_FillRect(target, &real_rect, color); | |
504 } else { | |
505 status = | |
506 SDL_BlendRect(target, &real_rect, renderer->blendMode, | |
507 renderer->r, renderer->g, renderer->b, renderer->a); | |
508 } | |
509 return status; | |
510 } | |
511 | |
512 static int | |
513 SDL_PS3_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
514 const SDL_Rect * srcrect, const SDL_Rect * dstrect) | |
515 { | |
516 deprintf(1, "+SDL_PS3_RenderCopy()\n"); | |
517 SDL_PS3_RenderData *data = | |
518 (SDL_PS3_RenderData *) renderer->driverdata; | |
519 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
520 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | |
521 PS3_TextureData *txdata = (PS3_TextureData *) texture->driverdata; | |
522 SDL_VideoData *devdata = display->device->driverdata; | |
523 | |
524 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
525 deprintf(1, "Texture is in a FOURCC format\n"); | |
526 if ((texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) | |
527 && texture->w % 8 == 0 && texture->h % 8 == 0 | |
528 && dstrect->w % 8 == 0 && dstrect->h % 8 == 0) { | |
529 deprintf(1, "Use SPE for scaling/converting\n"); | |
530 | |
531 SDL_SW_YUVTexture *swdata = (SDL_SW_YUVTexture *) txdata->yuv; | |
532 Uint8 *lum, *Cr, *Cb; | |
533 Uint8 *scaler_out = NULL; | |
534 Uint8 *dstpixels; | |
535 switch (texture->format) { | |
536 case SDL_PIXELFORMAT_YV12: | |
537 lum = swdata->planes[0]; | |
538 Cr = swdata->planes[1]; | |
539 Cb = swdata->planes[2]; | |
540 break; | |
541 case SDL_PIXELFORMAT_IYUV: | |
542 lum = swdata->planes[0]; | |
543 Cr = swdata->planes[2]; | |
544 Cb = swdata->planes[1]; | |
545 break; | |
546 default: | |
547 /* We should never get here (caught above) */ | |
548 return -1; | |
549 } | |
550 | |
551 if (srcrect->w != dstrect->w || srcrect->h != dstrect->h) { | |
552 deprintf(1, "We need to scale the texture from %u x %u to %u x %u\n", | |
553 srcrect->w, srcrect->h, dstrect->w, dstrect->h); | |
554 /* Alloc mem for scaled YUV picture */ | |
555 scaler_out = (Uint8 *) memalign(16, dstrect->w * dstrect->h + ((dstrect->w * dstrect->h) >> 1)); | |
556 if (scaler_out == NULL) { | |
557 SDL_OutOfMemory(); | |
558 return -1; | |
559 } | |
560 | |
561 /* Set parms for scaling */ | |
562 data->scaler_parms->src_pixel_width = srcrect->w; | |
563 data->scaler_parms->src_pixel_height = srcrect->h; | |
564 data->scaler_parms->dst_pixel_width = dstrect->w; | |
565 data->scaler_parms->dst_pixel_height = dstrect->h; | |
566 data->scaler_parms->y_plane = lum; | |
567 data->scaler_parms->v_plane = Cr; | |
568 data->scaler_parms->u_plane = Cb; | |
569 data->scaler_parms->dstBuffer = scaler_out; | |
570 data->scaler_thread_data->argp = (void *)data->scaler_parms; | |
571 | |
572 /* Scale the YUV overlay to given size */ | |
573 SPE_Start(data->scaler_thread_data); | |
574 SPE_Stop(data->scaler_thread_data); | |
575 | |
576 /* Set parms for converting after scaling */ | |
577 data->converter_parms->y_plane = scaler_out; | |
578 data->converter_parms->v_plane = scaler_out + dstrect->w * dstrect->h; | |
579 data->converter_parms->u_plane = scaler_out + dstrect->w * dstrect->h + ((dstrect->w * dstrect->h) >> 2); | |
580 } else { | |
581 data->converter_parms->y_plane = lum; | |
582 data->converter_parms->v_plane = Cr; | |
583 data->converter_parms->u_plane = Cb; | |
584 } | |
585 | |
586 dstpixels = (Uint8 *) data->screen->pixels + dstrect->y * data->screen->pitch + dstrect->x | |
587 * SDL_BYTESPERPIXEL(texture->format); | |
588 data->converter_parms->src_pixel_width = dstrect->w; | |
589 data->converter_parms->src_pixel_height = dstrect->h; | |
590 data->converter_parms->dstBuffer = dstpixels/*(Uint8 *)data->screen->pixels*/; | |
591 data->converter_thread_data->argp = (void *)data->converter_parms; | |
592 | |
593 /* Convert YUV texture to RGB */ | |
594 SPE_SendMsg(data->converter_thread_data, SPU_START); | |
595 SPE_SendMsg(data->converter_thread_data, (unsigned int)data->converter_thread_data->argp); | |
596 | |
597 /* We can probably move that to RenderPresent() */ | |
598 SPE_WaitForMsg(data->converter_thread_data, SPU_FIN); | |
599 if (scaler_out) { | |
600 free(scaler_out); | |
601 } | |
602 } else { | |
603 deprintf(1, "Use software for scaling/converting\n"); | |
604 Uint8 *dst; | |
605 /* FIXME: Not good */ | |
606 dst = (Uint8 *) data->screen->pixels + dstrect->y * data->screen->pitch + dstrect->x | |
607 * SDL_BYTESPERPIXEL(texture->format); | |
608 return SDL_SW_CopyYUVToRGB(txdata->yuv, srcrect, display->current_mode.format, | |
609 dstrect->w, dstrect->h, dst/*data->screen->pixels*/, | |
610 data->screen->pitch); | |
611 } | |
612 } else { | |
613 deprintf(1, "SDL_ISPIXELFORMAT_FOURCC = false\n"); | |
614 | |
615 Uint8 *src, *dst; | |
616 int row; | |
617 size_t length; | |
618 Uint8 *dstpixels; | |
619 | |
620 src = (Uint8 *) txdata->pixels; | |
621 dst = (Uint8 *) data->screen->pixels + dstrect->y * data->screen->pitch + dstrect->x | |
622 * SDL_BYTESPERPIXEL(texture->format); | |
623 length = dstrect->w * SDL_BYTESPERPIXEL(texture->format); | |
624 for (row = 0; row < dstrect->h; ++row) { | |
625 SDL_memcpy(dst, src, length); | |
626 src += txdata->pitch; | |
627 dst += data->screen->pitch; | |
628 } | |
629 } | |
630 | |
631 deprintf(1, "-SDL_PS3_RenderCopy()\n"); | |
632 return 0; | |
633 } | |
634 | |
635 static void | |
636 SDL_PS3_RenderPresent(SDL_Renderer * renderer) | |
637 { | |
638 deprintf(1, "+SDL_PS3_RenderPresent()\n"); | |
639 SDL_PS3_RenderData *data = | |
640 (SDL_PS3_RenderData *) renderer->driverdata; | |
641 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
642 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | |
643 SDL_VideoData *devdata = display->device->driverdata; | |
644 | |
645 /* Send the data to the screen */ | |
646 /* Get screeninfo */ | |
647 struct fb_fix_screeninfo fb_finfo; | |
648 if (ioctl(devdata->fbdev, FBIOGET_FSCREENINFO, &fb_finfo)) { | |
649 SDL_SetError("[PS3] Can't get fixed screeninfo"); | |
650 } | |
651 struct fb_var_screeninfo fb_vinfo; | |
652 if (ioctl(devdata->fbdev, FBIOGET_VSCREENINFO, &fb_vinfo)) { | |
653 SDL_SetError("[PS3] Can't get VSCREENINFO"); | |
654 } | |
655 | |
656 /* 16 and 15 bpp is reported as 16 bpp */ | |
657 //txdata->bpp = fb_vinfo.bits_per_pixel; | |
658 //if (txdata->bpp == 16) | |
659 // txdata->bpp = fb_vinfo.red.length + fb_vinfo.green.length + fb_vinfo.blue.length; | |
660 | |
661 /* Adjust centering */ | |
662 data->bounded_width = window->w < fb_vinfo.xres ? window->w : fb_vinfo.xres; | |
663 data->bounded_height = window->h < fb_vinfo.yres ? window->h : fb_vinfo.yres; | |
664 /* We could use SDL's CENTERED flag for centering */ | |
665 data->offset_left = (fb_vinfo.xres - data->bounded_width) >> 1; | |
666 data->offset_top = (fb_vinfo.yres - data->bounded_height) >> 1; | |
667 data->center[0] = devdata->frame_buffer + data->offset_left * /*txdata->bpp/8*/ 4 + | |
668 data->offset_top * fb_finfo.line_length; | |
669 data->center[1] = data->center[0] + fb_vinfo.yres * fb_finfo.line_length; | |
670 | |
671 deprintf(1, "offset_left = %u\n", data->offset_left); | |
672 deprintf(1, "offset_top = %u\n", data->offset_top); | |
673 | |
674 /* Set SPU parms for copying the surface to framebuffer */ | |
675 devdata->fb_parms->data = (unsigned char *)data->screen->pixels; | |
676 devdata->fb_parms->center = data->center[data->current_screen]; | |
677 devdata->fb_parms->out_line_stride = fb_finfo.line_length; | |
678 devdata->fb_parms->in_line_stride = window->w * /*txdata->bpp / 8*/4; | |
679 devdata->fb_parms->bounded_input_height = data->bounded_height; | |
680 devdata->fb_parms->bounded_input_width = data->bounded_width; | |
681 //devdata->fb_parms->fb_pixel_size = txdata->bpp / 8; | |
682 devdata->fb_parms->fb_pixel_size = 4;//SDL_BYTESPERPIXEL(window->format); | |
683 | |
684 deprintf(3, "[PS3->SPU] fb_thread_data->argp = 0x%x\n", devdata->fb_thread_data->argp); | |
685 | |
686 /* Copying.. */ | |
687 SPE_SendMsg(devdata->fb_thread_data, SPU_START); | |
688 SPE_SendMsg(devdata->fb_thread_data, (unsigned int)devdata->fb_thread_data->argp); | |
689 | |
690 SPE_WaitForMsg(devdata->fb_thread_data, SPU_FIN); | |
691 | |
692 /* Wait for vsync */ | |
693 if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { | |
694 unsigned long crt = 0; | |
695 deprintf(1, "[PS3] Wait for vsync\n"); | |
696 ioctl(devdata->fbdev, FBIO_WAITFORVSYNC, &crt); | |
697 } | |
698 | |
699 /* Page flip */ | |
700 deprintf(1, "[PS3] Page flip to buffer #%u 0x%x\n", data->current_screen, data->center[data->current_screen]); | |
701 ioctl(devdata->fbdev, PS3FB_IOCTL_FSEL, (unsigned long)&data->current_screen); | |
702 | |
703 /* Update the flipping chain, if any */ | |
704 if (data->double_buffering) { | |
705 data->current_screen = (data->current_screen + 1) % 2; | |
706 } | |
707 deprintf(1, "-SDL_PS3_RenderPresent()\n"); | |
708 } | |
709 | |
710 static void | |
711 SDL_PS3_DestroyRenderer(SDL_Renderer * renderer) | |
712 { | |
713 deprintf(1, "+SDL_PS3_DestroyRenderer()\n"); | |
714 SDL_PS3_RenderData *data = | |
715 (SDL_PS3_RenderData *) renderer->driverdata; | |
716 int i; | |
717 | |
718 if (data) { | |
719 for (i = 0; i < SDL_arraysize(data->screen); ++i) { | |
720 if (data->screen) { | |
721 SDL_FreeSurface(data->screen); | |
722 } | |
723 } | |
724 | |
725 /* Shutdown SPE and release related resources */ | |
726 if (data->scaler_thread_data) { | |
727 free((void *)data->scaler_thread_data); | |
728 } | |
729 if (data->scaler_parms) { | |
730 free((void *)data->scaler_parms); | |
731 } | |
732 if (data->converter_thread_data) { | |
733 SPE_Shutdown(data->converter_thread_data); | |
734 free((void *)data->converter_thread_data); | |
735 } | |
736 if (data->converter_parms) { | |
737 free((void *)data->converter_parms); | |
738 } | |
739 | |
740 SDL_free(data); | |
741 } | |
742 SDL_free(renderer); | |
743 deprintf(1, "-SDL_PS3_DestroyRenderer()\n"); | |
744 } | |
745 | |
746 /* vi: set ts=4 sw=4 expandtab: */ |