1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2014-2017 - Ali Bouhlel
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 *
5 * RetroArch is free software: you can redistribute it and/or modify it under the terms
6 * of the GNU General Public License as published by the Free Software Found-
7 * ation, either version 3 of the License, or (at your option) any later version.
8 *
9 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with RetroArch.
14 * If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <pspkernel.h>
18 #include <pspdisplay.h>
19 #include <malloc.h>
20 #include <pspgu.h>
21 #include <pspgum.h>
22 #include <psprtc.h>
23
24 #include <retro_assert.h>
25 #include <retro_inline.h>
26 #include <retro_math.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include "../../config.h"
30 #endif
31
32 #ifdef HAVE_MENU
33 #include "../../menu/menu_driver.h"
34 #endif
35
36 #include "../font_driver.h"
37
38 #include <defines/psp_defines.h>
39
40 #ifndef SCEGU_SCR_WIDTH
41 #define SCEGU_SCR_WIDTH 480
42 #endif
43
44 #ifndef SCEGU_SCR_HEIGHT
45 #define SCEGU_SCR_HEIGHT 272
46 #endif
47
48 #ifndef SCEGU_VRAM_WIDTH
49 #define SCEGU_VRAM_WIDTH 512
50 #endif
51
52 /* Frame buffer */
53 #define SCEGU_VRAM_TOP (0x44000000)
54 /* 16bit mode */
55 #define SCEGU_VRAM_BUFSIZE (SCEGU_VRAM_WIDTH*SCEGU_SCR_HEIGHT*2)
56 #define SCEGU_VRAM_BP_0 ((void *)(SCEGU_VRAM_TOP))
57 #define SCEGU_VRAM_BP_1 ((void *)(SCEGU_VRAM_TOP+SCEGU_VRAM_BUFSIZE))
58 #define SCEGU_VRAM_BP_2 ((void *)(SCEGU_VRAM_TOP+(SCEGU_VRAM_BUFSIZE*2)))
59 /* 32bit mode */
60 #define SCEGU_VRAM_BUFSIZE32 (SCEGU_VRAM_WIDTH*SCEGU_SCR_HEIGHT*4)
61 #define SCEGU_VRAM_BP32_0 ((void *)(SCEGU_VRAM_TOP))
62 #define SCEGU_VRAM_BP32_1 ((void *)(SCEGU_VRAM_TOP+SCEGU_VRAM_BUFSIZE32))
63 #define SCEGU_VRAM_BP32_2 ((void *)(SCEGU_VRAM_TOP+(SCEGU_VRAM_BUFSIZE32*2)))
64
65 #define TO_UNCACHED_PTR(ptr) ((void *)((uint32_t)(ptr)|0x40000000))
66 #define TO_CACHED_PTR(ptr) ((void *)((uint32_t)(ptr)&~0x40000000))
67
68 #define FROM_GU_POINTER(ptr) ((void *)((uint32_t)(ptr)|0x44000000))
69 #define TO_GU_POINTER(ptr) ((void *)((uint32_t)(ptr)&~0x44000000))
70
71 typedef struct __attribute__((packed)) psp1_vertex
72 {
73 float u,v;
74 float x,y,z;
75
76 } psp1_vertex_t;
77
78 typedef struct __attribute__((packed)) psp1_sprite
79 {
80 psp1_vertex_t v0;
81 psp1_vertex_t v1;
82 } psp1_sprite_t;
83
84 typedef struct psp1_menu_frame
85 {
86 void* dList;
87 void* frame;
88 psp1_sprite_t* frame_coords;
89
90 bool active;
91
92 PspGeContext context_storage;
93 } psp1_menu_frame_t;
94
95 typedef struct psp1_video
96 {
97 bool vsync;
98 bool rgb32;
99 bool vblank_not_reached;
100 bool keep_aspect;
101 bool should_resize;
102 bool hw_render;
103
104 int tex_filter;
105 int bpp_log2;
106
107 unsigned rotation;
108
109 psp1_menu_frame_t menu;
110 video_viewport_t vp;
111 void* main_dList;
112 void* frame_dList;
113 void* draw_buffer;
114 void* texture;
115 psp1_sprite_t *frame_coords;
116 } psp1_video_t;
117
118 /* both row and column count need to be a power of 2 */
119 #define PSP_FRAME_ROWS_COUNT 4
120 #define PSP_FRAME_COLUMNS_COUNT 16
121 #define PSP_FRAME_SLICE_COUNT (PSP_FRAME_ROWS_COUNT * PSP_FRAME_COLUMNS_COUNT)
122 #define PSP_FRAME_VERTEX_COUNT (PSP_FRAME_SLICE_COUNT * 2)
123
psp_set_screen_coords(psp1_sprite_t * framecoords,int x,int y,int width,int height,unsigned rotation)124 static INLINE void psp_set_screen_coords (psp1_sprite_t* framecoords,
125 int x, int y, int width, int height, unsigned rotation)
126 {
127 int i;
128 float x0, y0, step_x, step_y;
129 int current_column = 0;
130
131 if (rotation == 0)
132 {
133 x0 = x;
134 y0 = y;
135 step_x = ((float) width) / PSP_FRAME_COLUMNS_COUNT;
136 step_y = ((float) height) / PSP_FRAME_ROWS_COUNT;
137
138 for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
139 {
140 framecoords[i].v0.x = x0;
141 framecoords[i].v0.y = y0;
142
143 framecoords[i].v1.x = (x0 += step_x);
144 framecoords[i].v1.y = y0 + step_y;
145
146 if (++current_column == PSP_FRAME_COLUMNS_COUNT)
147 {
148 x0 = x;
149 y0 += step_y;
150 current_column = 0;
151 }
152 }
153 }
154 else if (rotation == 1) /* 90° */
155 {
156 x0 = x + width;
157 y0 = y;
158 step_x = -((float) width) / PSP_FRAME_ROWS_COUNT;
159 step_y = ((float) height) / PSP_FRAME_COLUMNS_COUNT;
160
161 for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
162 {
163 framecoords[i].v0.x = x0;
164 framecoords[i].v0.y = y0;
165
166 framecoords[i].v1.x = x0 + step_x;
167 framecoords[i].v1.y = (y0 += step_y);
168
169 if (++current_column == PSP_FRAME_COLUMNS_COUNT)
170 {
171 y0 = y;
172 x0 += step_x;
173 current_column = 0;
174 }
175 }
176 }
177 else if (rotation == 2) /* 180° */
178 {
179 x0 = x + width;
180 y0 = y + height;
181 step_x = -((float) width) / PSP_FRAME_COLUMNS_COUNT;
182 step_y = -((float) height) / PSP_FRAME_ROWS_COUNT;
183
184 for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
185 {
186 framecoords[i].v0.x = x0;
187 framecoords[i].v0.y = y0;
188
189 framecoords[i].v1.x = (x0 += step_x);
190 framecoords[i].v1.y = y0 + step_y;
191
192 if (++current_column == PSP_FRAME_COLUMNS_COUNT)
193 {
194 x0 = x + width;
195 y0 += step_y;
196 current_column = 0;
197 }
198 }
199 }
200 else /* 270° */
201 {
202 x0 = x;
203 y0 = y + height;
204 step_x = ((float) width) / PSP_FRAME_ROWS_COUNT;
205 step_y = -((float) height) / PSP_FRAME_COLUMNS_COUNT;
206
207 for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
208 {
209 framecoords[i].v0.x = x0;
210 framecoords[i].v0.y = y0;
211 framecoords[i].v1.x = x0 + step_x;
212 framecoords[i].v1.y = (y0 += step_y);
213
214 if (++current_column == PSP_FRAME_COLUMNS_COUNT)
215 {
216 y0 = y + height;
217 x0 += step_x;
218 current_column = 0;
219 }
220 }
221 }
222 }
223
psp_set_tex_coords(psp1_sprite_t * framecoords,int width,int height)224 static INLINE void psp_set_tex_coords (psp1_sprite_t* framecoords,
225 int width, int height)
226 {
227 int i;
228 int current_column = 0;
229 float u0 = 0;
230 float v0 = 0;
231 float step_u = ((float) width) / PSP_FRAME_COLUMNS_COUNT;
232 float step_v = ((float) height) / PSP_FRAME_ROWS_COUNT;
233
234 for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
235 {
236 framecoords[i].v0.u = u0;
237 framecoords[i].v0.v = v0;
238 u0 += step_u;
239 framecoords[i].v1.u = u0;
240 framecoords[i].v1.v = v0 + step_v;
241
242 if (++current_column == PSP_FRAME_COLUMNS_COUNT)
243 {
244 u0 = 0;
245 v0 += step_v;
246 current_column = 0;
247 }
248 }
249 }
250
psp_update_viewport(psp1_video_t * psp,video_frame_info_t * video_info)251 static void psp_update_viewport(psp1_video_t* psp,
252 video_frame_info_t *video_info)
253 {
254 int x = 0;
255 int y = 0;
256 float device_aspect = ((float)SCEGU_SCR_WIDTH) / SCEGU_SCR_HEIGHT;
257 float width = SCEGU_SCR_WIDTH;
258 float height = SCEGU_SCR_HEIGHT;
259 settings_t *settings = config_get_ptr();
260 bool video_scale_integer = settings->bools.video_scale_integer;
261 unsigned aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
262
263 if (video_scale_integer)
264 {
265 video_viewport_get_scaled_integer(&psp->vp, SCEGU_SCR_WIDTH,
266 SCEGU_SCR_HEIGHT, video_driver_get_aspect_ratio(), psp->keep_aspect);
267 width = psp->vp.width;
268 height = psp->vp.height;
269 }
270 else if (psp->keep_aspect)
271 {
272 #if defined(HAVE_MENU)
273 if (aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
274 {
275 x = video_info->custom_vp_x;
276 y = video_info->custom_vp_y;
277 width = video_info->custom_vp_width;
278 height = video_info->custom_vp_height;
279 }
280 else
281 #endif
282 {
283 float delta;
284 float desired_aspect = video_driver_get_aspect_ratio();
285
286 if ((fabsf(device_aspect - desired_aspect) < 0.0001f)
287 || (fabsf((16.0/9.0) - desired_aspect) < 0.02f))
288 {
289 /* If the aspect ratios of screen and desired aspect
290 * ratio are sufficiently equal (floating point stuff),
291 * assume they are actually equal.
292 */
293 }
294 else if (device_aspect > desired_aspect)
295 {
296 delta = (desired_aspect / device_aspect - 1.0f)
297 / 2.0f + 0.5f;
298 x = (int)roundf(width * (0.5f - delta));
299 width = (unsigned)roundf(2.0f * width * delta);
300 }
301 else
302 {
303 delta = (device_aspect / desired_aspect - 1.0f)
304 / 2.0f + 0.5f;
305 y = (int)roundf(height * (0.5f - delta));
306 height = (unsigned)roundf(2.0f * height * delta);
307 }
308 }
309
310 psp->vp.x = x;
311 psp->vp.y = y;
312 psp->vp.width = width;
313 psp->vp.height = height;
314 }
315 else
316 {
317 psp->vp.x = 0;
318 psp->vp.y = 0;
319 psp->vp.width = width;
320 psp->vp.height = height;
321 }
322
323 psp->vp.width += psp->vp.width & 0x1;
324 psp->vp.height += psp->vp.height & 0x1;
325
326 psp_set_screen_coords(psp->frame_coords, psp->vp.x,
327 psp->vp.y, psp->vp.width, psp->vp.height, psp->rotation);
328
329 psp->should_resize = false;
330
331 }
332
333
psp_on_vblank(u32 sub,psp1_video_t * psp)334 static void psp_on_vblank(u32 sub, psp1_video_t *psp)
335 {
336 if (psp)
337 psp->vblank_not_reached = false;
338 }
339
psp_init(const video_info_t * video,input_driver_t ** input,void ** input_data)340 static void *psp_init(const video_info_t *video,
341 input_driver_t **input, void **input_data)
342 {
343 /* TODO : add ASSERT() checks or use main RAM if
344 * VRAM is too low for desired video->input_scale. */
345
346 int pixel_format, lut_pixel_format, lut_block_count;
347 unsigned int red_shift, color_mask;
348 void *pspinput = NULL;
349 void *displayBuffer = NULL;
350 void *LUT_r = NULL;
351 void *LUT_b = NULL;
352 psp1_video_t *psp = (psp1_video_t*)calloc(1, sizeof(psp1_video_t));
353
354 if (!psp)
355 return NULL;
356
357 sceGuInit();
358
359 psp->vp.x = 0;
360 psp->vp.y = 0;
361 psp->vp.width = SCEGU_SCR_WIDTH;
362 psp->vp.height = SCEGU_SCR_HEIGHT;
363 psp->vp.full_width = SCEGU_SCR_WIDTH;
364 psp->vp.full_height = SCEGU_SCR_HEIGHT;
365
366 /* Make sure anything using uncached pointers reserves
367 * whole cachelines (memory address and size need to be a multiple of 64)
368 * so it isn't overwritten by an unlucky cache writeback.
369 *
370 * This includes display lists since the Gu library uses
371 * uncached pointers to write to them. */
372
373 /* Allocate more space if bigger display lists are needed. */
374 psp->main_dList = memalign(64, 256);
375
376 psp->frame_dList = memalign(64, 256);
377 psp->menu.dList = memalign(64, 256);
378 psp->menu.frame = memalign(16, 2 * 480 * 272);
379 psp->frame_coords = memalign(64,
380 (((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));
381 psp->menu.frame_coords = memalign(64,
382 (((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));
383
384 memset(psp->frame_coords, 0,
385 PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t));
386 memset(psp->menu.frame_coords, 0,
387 PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t));
388
389 sceKernelDcacheWritebackInvalidateAll();
390 psp->frame_coords = TO_UNCACHED_PTR(psp->frame_coords);
391 psp->menu.frame_coords = TO_UNCACHED_PTR(psp->menu.frame_coords);
392
393 psp->frame_coords->v0.x = 60;
394 psp->frame_coords->v0.y = 0;
395 psp->frame_coords->v0.u = 0;
396 psp->frame_coords->v0.v = 0;
397
398 psp->frame_coords->v1.x = 420;
399 psp->frame_coords->v1.y = SCEGU_SCR_HEIGHT;
400 psp->frame_coords->v1.u = 256;
401 psp->frame_coords->v1.v = 240;
402
403 psp->vsync = video->vsync;
404 psp->rgb32 = video->rgb32;
405
406 if(psp->rgb32)
407 {
408 u32 i;
409 uint32_t* LUT_r_local = (uint32_t*)(SCEGU_VRAM_BP32_2);
410 uint32_t* LUT_b_local = (uint32_t*)(SCEGU_VRAM_BP32_2) + (1 << 8);
411
412 red_shift = 8 + 8;
413 color_mask = 0xFF;
414 lut_block_count = (1 << 8) / 8;
415
416 psp->texture = (void*)(LUT_b_local + (1 << 8));
417 psp->draw_buffer = SCEGU_VRAM_BP32_0;
418 psp->bpp_log2 = 2;
419
420 pixel_format = GU_PSM_8888;
421 lut_pixel_format = GU_PSM_T32;
422
423 displayBuffer = SCEGU_VRAM_BP32_1;
424
425 for (i = 0; i < (1 << 8); i++)
426 {
427 LUT_r_local[i] = i;
428 LUT_b_local[i] = i << (8 + 8);
429 }
430
431 LUT_r = (void*)LUT_r_local;
432 LUT_b = (void*)LUT_b_local;
433
434 }
435 else
436 {
437 u16 i;
438 uint16_t* LUT_r_local = (uint16_t*)(SCEGU_VRAM_BP_2);
439 uint16_t* LUT_b_local = (uint16_t*)(SCEGU_VRAM_BP_2) + (1 << 5);
440
441 red_shift = 6 + 5;
442 color_mask = 0x1F;
443 lut_block_count = (1 << 5) / 8;
444
445 psp->texture = (void*)(LUT_b_local + (1 << 5));
446 psp->draw_buffer = SCEGU_VRAM_BP_0;
447 psp->bpp_log2 = 1;
448
449 pixel_format =
450 (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_0RGB1555)
451 ? GU_PSM_5551 : GU_PSM_5650 ;
452
453 lut_pixel_format = GU_PSM_T16;
454
455 displayBuffer = SCEGU_VRAM_BP_1;
456
457 for (i = 0; i < (1 << 5); i++)
458 {
459 LUT_r_local[i] = i;
460 LUT_b_local[i] = i << (5 + 6);
461 }
462
463 LUT_r = (void*)LUT_r_local;
464 LUT_b = (void*)LUT_b_local;
465
466 }
467
468 psp->tex_filter = video->smooth? GU_LINEAR : GU_NEAREST;
469
470 /* TODO: check if necessary. */
471 sceDisplayWaitVblankStart();
472
473 sceGuDisplay(GU_FALSE);
474
475 sceGuStart(GU_DIRECT, psp->main_dList);
476
477 sceGuDrawBuffer(pixel_format, TO_GU_POINTER(psp->draw_buffer),
478 SCEGU_VRAM_WIDTH);
479 sceGuDispBuffer(SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT,
480 TO_GU_POINTER(displayBuffer), SCEGU_VRAM_WIDTH);
481 sceGuClearColor(0);
482 sceGuScissor(0, 0, SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT);
483 sceGuEnable(GU_SCISSOR_TEST);
484 sceGuTexFilter(psp->tex_filter, psp->tex_filter);
485 sceGuTexWrap (GU_CLAMP, GU_CLAMP);
486 sceGuEnable(GU_TEXTURE_2D);
487 sceGuDisable(GU_DEPTH_TEST);
488 sceGuCallMode(GU_FALSE);
489
490 sceGuFinish();
491 sceGuSync(0, 0);
492
493 /* TODO : check if necessary */
494 sceDisplayWaitVblankStart();
495 sceGuDisplay(GU_TRUE);
496
497 pspDebugScreenSetColorMode(pixel_format);
498 pspDebugScreenSetBase(psp->draw_buffer);
499
500 /* fill frame_dList : */
501 sceGuStart(GU_CALL, psp->frame_dList);
502
503 sceGuTexMode(pixel_format, 0, 0, GU_FALSE);
504 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
505 sceGuEnable(GU_BLEND);
506
507 /* green only */
508 sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0x0000FF00, 0xFFFFFFFF);
509
510 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
511 GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
512 (void*)(psp->frame_coords));
513
514 /* restore */
515 sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0xFFFFFFFF, 0xFFFFFFFF);
516
517 sceGuTexMode(lut_pixel_format, 0, 0, GU_FALSE);
518
519 sceGuClutMode(pixel_format, red_shift, color_mask, 0);
520 sceGuClutLoad(lut_block_count, LUT_r);
521
522 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
523 GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
524 (void*)(psp->frame_coords));
525
526 sceGuClutMode(pixel_format, 0, color_mask, 0);
527 sceGuClutLoad(lut_block_count, LUT_b);
528 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
529 GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
530 (void*)(psp->frame_coords));
531
532 sceGuFinish();
533
534 if (input && input_data)
535 {
536 settings_t *settings = config_get_ptr();
537 pspinput = input_driver_init_wrap(&input_psp,
538 settings->arrays.input_joypad_driver);
539 *input = pspinput ? &input_psp : NULL;
540 *input_data = pspinput;
541 }
542
543 psp->vblank_not_reached = true;
544 sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, psp);
545 sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
546
547 psp->keep_aspect = true;
548 psp->should_resize = true;
549 psp->hw_render = false;
550
551 return psp;
552 }
553
psp_frame(void * data,const void * frame,unsigned width,unsigned height,uint64_t frame_count,unsigned pitch,const char * msg,video_frame_info_t * video_info)554 static bool psp_frame(void *data, const void *frame,
555 unsigned width, unsigned height, uint64_t frame_count,
556 unsigned pitch, const char *msg, video_frame_info_t *video_info)
557 {
558 psp1_video_t *psp = (psp1_video_t*)data;
559 #ifdef HAVE_MENU
560 bool menu_is_alive = video_info->menu_is_alive;
561 #endif
562
563 if (!width || !height)
564 return false;
565
566 if (((uint32_t)frame&0x04000000) || (frame == RETRO_HW_FRAME_BUFFER_VALID))
567 psp->hw_render = true;
568 else if (frame)
569 psp->hw_render = false;
570
571 if (!psp->hw_render)
572 sceGuSync(0, 0); /* let the core decide when to sync when HW_RENDER */
573
574 if (msg)
575 {
576 pspDebugScreenSetBase(psp->draw_buffer);
577 pspDebugScreenSetXY(0,0);
578 pspDebugScreenPuts(msg);
579 }
580
581 if ((psp->vsync) && (psp->vblank_not_reached))
582 sceDisplayWaitVblankStart();
583
584 psp->vblank_not_reached = true;
585
586 psp->draw_buffer = FROM_GU_POINTER(sceGuSwapBuffers());
587
588 if (psp->should_resize)
589 psp_update_viewport(psp, video_info);
590
591 psp_set_tex_coords(psp->frame_coords, width, height);
592
593 sceGuStart(GU_DIRECT, psp->main_dList);
594
595 sceGuTexFilter(psp->tex_filter, psp->tex_filter);
596 sceGuClear(GU_COLOR_BUFFER_BIT);
597
598 /* frame in VRAM ? texture/palette was
599 * set in core so draw directly */
600 if (psp->hw_render)
601 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
602 GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
603 (void*)(psp->frame_coords));
604 else
605 {
606 if (frame)
607 {
608 sceKernelDcacheWritebackRange(frame,pitch * height);
609 sceGuCopyImage(psp->rgb32? GU_PSM_8888 : GU_PSM_5650,
610 ((u32)frame & 0xF) >> psp->bpp_log2,
611 0, width, height, pitch >> psp->bpp_log2,
612 (void*)((u32)frame & ~0xF), 0, 0, width, psp->texture);
613 }
614 sceGuTexImage(0, next_pow2(width), next_pow2(height), width, psp->texture);
615 sceGuCallList(psp->frame_dList);
616 }
617
618 sceGuFinish();
619
620 #ifdef HAVE_MENU
621 menu_driver_frame(menu_is_alive, video_info);
622 #endif
623
624 if(psp->menu.active)
625 {
626 sceGuSendList(GU_TAIL, psp->menu.dList, &(psp->menu.context_storage));
627 sceGuSync(0, 0);
628 }
629
630 return true;
631 }
632
psp_set_nonblock_state(void * data,bool toggle,bool adaptive_vsync_enabled,unsigned swap_interval)633 static void psp_set_nonblock_state(void *data, bool toggle,
634 bool adaptive_vsync_enabled, unsigned swap_interval)
635 {
636 psp1_video_t *psp = (psp1_video_t*)data;
637
638 if (psp)
639 psp->vsync = !toggle;
640 }
641
psp_alive(void * data)642 static bool psp_alive(void *data) { return true; }
psp_focus(void * data)643 static bool psp_focus(void *data) { return true; }
psp_suppress_screensaver(void * data,bool enable)644 static bool psp_suppress_screensaver(void *data, bool enable) { return false; }
645
psp_free(void * data)646 static void psp_free(void *data)
647 {
648 psp1_video_t *psp = (psp1_video_t*)data;
649
650 if(!(psp) || !(psp->main_dList))
651 return;
652
653 sceDisplayWaitVblankStart();
654 sceGuDisplay(GU_FALSE);
655 sceGuTerm();
656
657 if (psp->main_dList)
658 free(psp->main_dList);
659 if (psp->frame_dList)
660 free(psp->frame_dList);
661 if (psp->frame_coords)
662 free(TO_CACHED_PTR(psp->frame_coords));
663 if (psp->menu.frame_coords)
664 free(TO_CACHED_PTR(psp->menu.frame_coords));
665 if (psp->menu.dList)
666 free(psp->menu.dList);
667 if (psp->menu.frame)
668 free(psp->menu.frame);
669
670 free(data);
671
672 sceKernelDisableSubIntr(PSP_VBLANK_INT, 0);
673 sceKernelReleaseSubIntrHandler(PSP_VBLANK_INT,0);
674 }
675
psp_set_texture_frame(void * data,const void * frame,bool rgb32,unsigned width,unsigned height,float alpha)676 static void psp_set_texture_frame(void *data, const void *frame, bool rgb32,
677 unsigned width, unsigned height, float alpha)
678 {
679 psp1_video_t *psp = (psp1_video_t*)data;
680
681 (void) rgb32;
682 (void) alpha;
683
684 #ifdef DEBUG
685 /* psp->menu.frame buffer size is (480 * 272)*2 Bytes */
686 retro_assert((width*height) < (480 * 272));
687 #endif
688
689 psp_set_screen_coords(psp->menu.frame_coords, 0, 0,
690 SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT, 0);
691 psp_set_tex_coords(psp->menu.frame_coords, width, height);
692
693 sceKernelDcacheWritebackRange(frame, width * height * 2);
694
695 sceGuStart(GU_DIRECT, psp->main_dList);
696 sceGuCopyImage(GU_PSM_4444, 0, 0, width, height, width,
697 (void*)frame, 0, 0, width, psp->menu.frame);
698 sceGuFinish();
699
700 sceGuStart(GU_SEND, psp->menu.dList);
701 sceGuTexMode(GU_PSM_4444, 0, 0, GU_FALSE);
702 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
703 sceGuTexFilter(GU_LINEAR, GU_LINEAR);
704 sceGuTexImage(0, next_pow2(width), next_pow2(height), width, psp->menu.frame);
705 sceGuEnable(GU_BLEND);
706
707 #if 0
708 /* default blending */
709 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
710 #endif
711 sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0xF0F0F0F0, 0x0F0F0F0F);
712 ;
713 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
714 GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
715 psp->menu.frame_coords);
716 sceGuFinish();
717
718 }
719
psp_set_texture_enable(void * data,bool state,bool full_screen)720 static void psp_set_texture_enable(void *data, bool state, bool full_screen)
721 {
722 (void) full_screen;
723
724 psp1_video_t *psp = (psp1_video_t*)data;
725
726 if (psp)
727 psp->menu.active = state;
728 }
729
psp_set_rotation(void * data,unsigned rotation)730 static void psp_set_rotation(void *data, unsigned rotation)
731 {
732 psp1_video_t *psp = (psp1_video_t*)data;
733
734 if (!psp)
735 return;
736
737 psp->rotation = rotation;
738 psp->should_resize = true;
739 }
psp_set_filtering(void * data,unsigned index,bool smooth,bool ctx_scaling)740 static void psp_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling)
741 {
742 psp1_video_t *psp = (psp1_video_t*)data;
743
744 if (psp)
745 psp->tex_filter = smooth? GU_LINEAR : GU_NEAREST;
746 }
747
psp_set_aspect_ratio(void * data,unsigned aspect_ratio_idx)748 static void psp_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
749 {
750 psp1_video_t *psp = (psp1_video_t*)data;
751
752 if (!psp)
753 return;
754
755 psp->keep_aspect = true;
756 psp->should_resize = true;
757 }
758
psp_apply_state_changes(void * data)759 static void psp_apply_state_changes(void *data)
760 {
761 psp1_video_t *psp = (psp1_video_t*)data;
762
763 if (psp)
764 psp->should_resize = true;
765 }
766
psp_viewport_info(void * data,struct video_viewport * vp)767 static void psp_viewport_info(void *data, struct video_viewport *vp)
768 {
769 psp1_video_t *psp = (psp1_video_t*)data;
770
771 if (psp)
772 *vp = psp->vp;
773 }
774
psp_get_flags(void * data)775 static uint32_t psp_get_flags(void *data)
776 {
777 uint32_t flags = 0;
778
779 BIT32_SET(flags, GFX_CTX_FLAGS_SCREENSHOTS_SUPPORTED);
780
781 return flags;
782 }
783
784 static const video_poke_interface_t psp_poke_interface = {
785 psp_get_flags,
786 NULL,
787 NULL,
788 NULL,
789 NULL, /* get_refresh_rate */
790 psp_set_filtering,
791 NULL, /* get_video_output_size */
792 NULL, /* get_video_output_prev */
793 NULL, /* get_video_output_next */
794 NULL, /* get_current_framebuffer */
795 NULL, /* get_proc_address */
796 psp_set_aspect_ratio,
797 psp_apply_state_changes,
798 psp_set_texture_frame,
799 psp_set_texture_enable,
800 NULL, /* set_osd_msg */
801 NULL, /* show_mouse */
802 NULL, /* grab_mouse_toggle */
803 NULL, /* get_current_shader */
804 NULL, /* get_current_software_framebuffer */
805 NULL /* get_hw_render_interface */
806 };
807
psp_get_poke_interface(void * data,const video_poke_interface_t ** iface)808 static void psp_get_poke_interface(void *data,
809 const video_poke_interface_t **iface)
810 {
811 (void)data;
812 *iface = &psp_poke_interface;
813 }
814
psp_read_viewport(void * data,uint8_t * buffer,bool is_idle)815 static bool psp_read_viewport(void *data, uint8_t *buffer, bool is_idle)
816 {
817 void* src_buffer;
818 int i, j, src_bufferwidth, src_pixelformat, src_x, src_y, src_x_max, src_y_max;
819 uint8_t *dst = buffer;
820 psp1_video_t *psp = (psp1_video_t*)data;
821
822 sceDisplayGetFrameBuf(&src_buffer, &src_bufferwidth, &src_pixelformat, PSP_DISPLAY_SETBUF_NEXTFRAME);
823
824 src_x = (psp->vp.x > 0)? psp->vp.x : 0;
825 src_y = (psp->vp.y > 0)? psp->vp.y : 0;
826 src_x_max = ((psp->vp.x + psp->vp.width) < src_bufferwidth)? (psp->vp.x + psp->vp.width): src_bufferwidth;
827 src_y_max = ((psp->vp.y + psp->vp.height) < SCEGU_SCR_HEIGHT)? (psp->vp.y + psp->vp.height): SCEGU_SCR_HEIGHT;
828
829 switch(src_pixelformat)
830 {
831 case PSP_DISPLAY_PIXEL_FORMAT_565:
832 for (j = (src_y_max - 1); j >= src_y ; j--)
833 {
834 uint16_t* src = (uint16_t*)src_buffer + src_bufferwidth * j + src_x;
835 for (i = src_x; i < src_x_max; i++)
836 {
837
838 *(dst++) = ((*src) >> 11) << 3;
839 *(dst++) = (((*src) >> 5) << 2) &0xFF;
840 *(dst++) = ((*src) & 0x1F) << 3;
841 src++;
842 }
843 }
844 return true;
845
846 case PSP_DISPLAY_PIXEL_FORMAT_5551:
847 for (j = (src_y_max - 1); j >= src_y ; j--)
848 {
849 uint16_t* src = (uint16_t*)src_buffer + src_bufferwidth * j + src_x;
850 for (i = src_x; i < src_x_max; i++)
851 {
852
853 *(dst++) = (((*src) >> 10) << 3) &0xFF;
854 *(dst++) = (((*src) >> 5) << 3) &0xFF;
855 *(dst++) = ((*src) & 0x1F) << 3;
856 src++;
857 }
858 }
859 return true;
860
861 case PSP_DISPLAY_PIXEL_FORMAT_4444:
862 for (j = (src_y_max - 1); j >= src_y ; j--)
863 {
864 uint16_t* src = (uint16_t*)src_buffer + src_bufferwidth * j + src_x;
865 for (i = src_x; i < src_x_max; i++)
866 {
867
868 *(dst++) = ((*src) >> 4) & 0xF0;
869 *(dst++) = (*src) & 0xF0;
870 *(dst++) = ((*src) << 4) & 0xF0;
871 src++;
872 }
873 }
874 return true;
875
876 case PSP_DISPLAY_PIXEL_FORMAT_8888:
877 for (j = (src_y_max - 1); j >= src_y ; j--)
878 {
879 uint32_t* src = (uint32_t*)src_buffer + src_bufferwidth * j + src_x;
880 for (i = src_x; i < src_x_max; i++)
881 {
882
883 *(dst++) = ((*src) >> 16) & 0xFF;
884 *(dst++) = ((*src) >> 8 ) & 0xFF;
885 *(dst++) = (*src) & 0xFF;
886 src++;
887 }
888 }
889 return true;
890 }
891
892 return false;
893 }
894
psp_set_shader(void * data,enum rarch_shader_type type,const char * path)895 static bool psp_set_shader(void *data, enum rarch_shader_type type, const char *path) { return false; }
896
897 video_driver_t video_psp1 = {
898 psp_init,
899 psp_frame,
900 psp_set_nonblock_state,
901 psp_alive,
902 psp_focus,
903 psp_suppress_screensaver,
904 NULL, /* has_windowed */
905 psp_set_shader,
906 psp_free,
907 "psp1",
908 NULL, /* set_viewport */
909 psp_set_rotation,
910 psp_viewport_info,
911 psp_read_viewport,
912 NULL, /* read_frame_raw */
913 #ifdef HAVE_OVERLAY
914 NULL,
915 #endif
916 #ifdef HAVE_VIDEO_LAYOUT
917 NULL,
918 #endif
919 psp_get_poke_interface
920 };
921