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