1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
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 <stdint.h>
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <sys/spu_initialize.h>
24 
25 #include <compat/strl.h>
26 
27 #include "../../configuration.h"
28 #include "../../retroarch.h"
29 #include "../../verbosity.h"
30 #include <defines/ps3_defines.h>
31 #include "../../frontend/frontend_driver.h"
32 #include "../common/gl_common.h"
33 
34 typedef struct gfx_ctx_ps3_data
35 {
36 #if defined(HAVE_PSGL)
37    PSGLdevice* gl_device;
38    PSGLcontext* gl_context;
39 #else
40    void *empty;
41 #endif
42 } gfx_ctx_ps3_data_t;
43 
44 /* TODO/FIXME - static global */
45 static enum gfx_ctx_api ps3_api = GFX_CTX_NONE;
46 
gfx_ctx_ps3_get_resolution(unsigned idx,unsigned * width,unsigned * height)47 static void gfx_ctx_ps3_get_resolution(unsigned idx,
48       unsigned *width, unsigned *height)
49 {
50    CellVideoOutResolution resolution;
51    cellVideoOutGetResolution(idx, &resolution);
52 
53    *width  = resolution.width;
54    *height = resolution.height;
55 }
56 
gfx_ctx_ps3_get_aspect_ratio(void * data)57 static float gfx_ctx_ps3_get_aspect_ratio(void *data)
58 {
59    CellVideoOutState videoState;
60 
61    cellVideoOutGetState(CELL_VIDEO_OUT_PRIMARY, 0, &videoState);
62 
63    switch (videoState.displayMode.aspect)
64    {
65       case CELL_VIDEO_OUT_ASPECT_4_3:
66          return 4.0f/3.0f;
67       case CELL_VIDEO_OUT_ASPECT_16_9:
68          break;
69    }
70 
71    return 16.0f/9.0f;
72 }
73 
gfx_ctx_ps3_get_available_resolutions(void)74 static void gfx_ctx_ps3_get_available_resolutions(void)
75 {
76    unsigned i;
77    uint32_t videomode[] = {
78       CELL_VIDEO_OUT_RESOLUTION_480,
79       CELL_VIDEO_OUT_RESOLUTION_576,
80       CELL_VIDEO_OUT_RESOLUTION_960x1080,
81       CELL_VIDEO_OUT_RESOLUTION_720,
82       CELL_VIDEO_OUT_RESOLUTION_1280x1080,
83       CELL_VIDEO_OUT_RESOLUTION_1440x1080,
84       CELL_VIDEO_OUT_RESOLUTION_1600x1080,
85       CELL_VIDEO_OUT_RESOLUTION_1080
86    };
87    uint32_t resolution_count = 0;
88    bool defaultresolution    = true;
89    uint16_t num_videomodes   = sizeof(videomode) / sizeof(uint32_t);
90    global_t       *global    = global_get_ptr();
91 
92    if (global->console.screen.resolutions.check)
93       return;
94 
95    for (i = 0; i < num_videomodes; i++)
96    {
97       if (cellVideoOutGetResolutionAvailability(
98                CELL_VIDEO_OUT_PRIMARY, videomode[i],
99                CELL_VIDEO_OUT_ASPECT_AUTO, 0))
100          resolution_count++;
101    }
102 
103    global->console.screen.resolutions.count = 0;
104    global->console.screen.resolutions.list  =
105       malloc(resolution_count * sizeof(uint32_t));
106 
107    for (i = 0; i < num_videomodes; i++)
108    {
109       if (cellVideoOutGetResolutionAvailability(
110                CELL_VIDEO_OUT_PRIMARY,
111                videomode[i],
112                CELL_VIDEO_OUT_ASPECT_AUTO, 0))
113       {
114          global->console.screen.resolutions.list[
115             global->console.screen.resolutions.count++] = videomode[i];
116          global->console.screen.resolutions.initial.id = videomode[i];
117 
118          if (global->console.screen.resolutions.current.id == videomode[i])
119          {
120             defaultresolution = false;
121             global->console.screen.resolutions.current.idx =
122                global->console.screen.resolutions.count-1;
123          }
124       }
125    }
126 
127    /* In case we didn't specify a resolution -
128     * make the last resolution
129       that was added to the list (the highest resolution)
130       the default resolution */
131    if (global->console.screen.resolutions.current.id > num_videomodes || defaultresolution)
132     {
133       global->console.screen.resolutions.current.idx = resolution_count - 1;
134       global->console.screen.resolutions.current.id = global->console.screen.resolutions.list[global->console.screen.resolutions.current.idx];
135     }
136 
137    global->console.screen.resolutions.check = true;
138 }
139 
gfx_ctx_ps3_set_swap_interval(void * data,int interval)140 static void gfx_ctx_ps3_set_swap_interval(void *data, int interval)
141 {
142 #if defined(HAVE_PSGL)
143    if (interval == 1)
144       glEnable(GL_VSYNC_SCE);
145    else
146       glDisable(GL_VSYNC_SCE);
147 #endif
148 }
149 
gfx_ctx_ps3_check_window(void * data,bool * quit,bool * resize,unsigned * width,unsigned * height)150 static void gfx_ctx_ps3_check_window(void *data, bool *quit,
151       bool *resize, unsigned *width, unsigned *height)
152 {
153    gl_t *gl = data;
154 
155    *quit    = false;
156    *resize  = false;
157 
158    if (gl->should_resize)
159       *resize = true;
160 }
161 
gfx_ctx_ps3_has_focus(void * data)162 static bool gfx_ctx_ps3_has_focus(void *data) { return true; }
gfx_ctx_ps3_suppress_screensaver(void * data,bool enable)163 static bool gfx_ctx_ps3_suppress_screensaver(void *data, bool enable) { return false; }
164 
gfx_ctx_ps3_swap_buffers(void * data)165 static void gfx_ctx_ps3_swap_buffers(void *data)
166 {
167 #ifdef HAVE_PSGL
168    psglSwap();
169 #endif
170 #ifdef HAVE_SYSUTILS
171    cellSysutilCheckCallback();
172 #endif
173 }
174 
gfx_ctx_ps3_get_video_size(void * data,unsigned * width,unsigned * height)175 static void gfx_ctx_ps3_get_video_size(void *data,
176       unsigned *width, unsigned *height)
177 {
178    gfx_ctx_ps3_data_t *ps3 = (gfx_ctx_ps3_data_t*)data;
179 
180 #if defined(HAVE_PSGL)
181    if (ps3)
182       psglGetDeviceDimensions(ps3->gl_device, width, height);
183 #endif
184 }
185 
gfx_ctx_ps3_init(void * video_driver)186 static void *gfx_ctx_ps3_init(void *video_driver)
187 {
188 #ifdef HAVE_PSGL
189    PSGLdeviceParameters params;
190    PSGLinitOptions options;
191 #endif
192    global_t *global = global_get_ptr();
193    gfx_ctx_ps3_data_t *ps3 = (gfx_ctx_ps3_data_t*)
194       calloc(1, sizeof(gfx_ctx_ps3_data_t));
195 
196    if (!ps3)
197       return NULL;
198 
199 #if defined(HAVE_PSGL)
200    options.enable         = PSGL_INIT_MAX_SPUS | PSGL_INIT_INITIALIZE_SPUS;
201    options.maxSPUs        = 1;
202    options.initializeSPUs = GL_FALSE;
203 
204    /* Initialize 6 SPUs but reserve 1 SPU as a raw SPU for PSGL. */
205    sys_spu_initialize(6, 1);
206    psglInit(&options);
207 
208    params.enable            =
209       PSGL_DEVICE_PARAMETERS_COLOR_FORMAT |
210       PSGL_DEVICE_PARAMETERS_DEPTH_FORMAT |
211       PSGL_DEVICE_PARAMETERS_MULTISAMPLING_MODE;
212    params.colorFormat       = GL_ARGB_SCE;
213    params.depthFormat       = GL_NONE;
214    params.multisamplingMode = GL_MULTISAMPLING_NONE_SCE;
215 
216    if (global->console.screen.resolutions.current.id)
217    {
218       params.enable |= PSGL_DEVICE_PARAMETERS_WIDTH_HEIGHT;
219 
220       gfx_ctx_ps3_get_resolution(
221             global->console.screen.resolutions.current.id,
222             &params.width, &params.height);
223 
224       global->console.screen.pal_enable = false;
225 
226       if (params.width == 720 && params.height == 576)
227       {
228          RARCH_LOG("[PSGL Context]: 720x576 resolution detected, setting MODE_VIDEO_PAL_ENABLE.\n");
229          global->console.screen.pal_enable = true;
230       }
231    }
232 
233    if (global->console.screen.pal60_enable)
234    {
235       RARCH_LOG("[PSGL Context]: Setting temporal PAL60 mode.\n");
236       params.enable |= PSGL_DEVICE_PARAMETERS_RESC_PAL_TEMPORAL_MODE;
237       params.enable |= PSGL_DEVICE_PARAMETERS_RESC_RATIO_MODE;
238       params.rescPalTemporalMode = RESC_PAL_TEMPORAL_MODE_60_INTERPOLATE;
239       params.rescRatioMode = RESC_RATIO_MODE_FULLSCREEN;
240    }
241 
242    ps3->gl_device = psglCreateDeviceExtended(&params);
243    ps3->gl_context = psglCreateContext();
244 
245    psglMakeCurrent(ps3->gl_context, ps3->gl_device);
246    psglResetCurrentContext();
247 #endif
248 
249    global->console.screen.pal_enable =
250       cellVideoOutGetResolutionAvailability(
251             CELL_VIDEO_OUT_PRIMARY, CELL_VIDEO_OUT_RESOLUTION_576,
252             CELL_VIDEO_OUT_ASPECT_AUTO, 0);
253 
254    gfx_ctx_ps3_get_available_resolutions();
255 
256    return ps3;
257 }
258 
gfx_ctx_ps3_set_video_mode(void * data,unsigned width,unsigned height,bool fullscreen)259 static bool gfx_ctx_ps3_set_video_mode(void *data,
260       unsigned width, unsigned height,
261       bool fullscreen) { return true; }
262 
gfx_ctx_ps3_destroy_resources(gfx_ctx_ps3_data_t * ps3)263 static void gfx_ctx_ps3_destroy_resources(gfx_ctx_ps3_data_t *ps3)
264 {
265    if (!ps3)
266       return;
267 
268 #if defined(HAVE_PSGL)
269    psglDestroyContext(ps3->gl_context);
270    psglDestroyDevice(ps3->gl_device);
271 
272    psglExit();
273 #endif
274 }
275 
gfx_ctx_ps3_destroy(void * data)276 static void gfx_ctx_ps3_destroy(void *data)
277 {
278    gfx_ctx_ps3_data_t *ps3 = (gfx_ctx_ps3_data_t*)data;
279 
280    if (!ps3)
281       return;
282 
283    gfx_ctx_ps3_destroy_resources(ps3);
284    free(data);
285 }
286 
gfx_ctx_ps3_input_driver(void * data,const char * joypad_name,input_driver_t ** input,void ** input_data)287 static void gfx_ctx_ps3_input_driver(void *data,
288       const char *joypad_name,
289       input_driver_t **input, void **input_data)
290 {
291    void *ps3input       = input_driver_init_wrap(&input_ps3, joypad_name);
292 
293    *input               = ps3input ? &input_ps3 : NULL;
294    *input_data          = ps3input;
295 }
296 
gfx_ctx_ps3_get_api(void * data)297 static enum gfx_ctx_api gfx_ctx_ps3_get_api(void *data) { return ps3_api; }
298 
gfx_ctx_ps3_bind_api(void * data,enum gfx_ctx_api api,unsigned major,unsigned minor)299 static bool gfx_ctx_ps3_bind_api(void *data,
300       enum gfx_ctx_api api, unsigned major, unsigned minor)
301 {
302    ps3_api = api;
303 
304    if (
305          api == GFX_CTX_OPENGL_API ||
306          api == GFX_CTX_OPENGL_ES_API
307       )
308       return true;
309 
310    return false;
311 }
312 
gfx_ctx_ps3_get_video_output_size(void * data,unsigned * width,unsigned * height)313 static void gfx_ctx_ps3_get_video_output_size(void *data,
314       unsigned *width, unsigned *height)
315 {
316    global_t *global = global_get_ptr();
317 
318    if (!global)
319       return;
320 
321    gfx_ctx_ps3_get_resolution(global->console.screen.resolutions.current.id,
322          width, height);
323 
324    if (*width == 720 && *height == 576)
325    {
326       if (global->console.screen.pal_enable)
327          global->console.screen.pal60_enable = true;
328    }
329    else
330    {
331       global->console.screen.pal_enable = false;
332       global->console.screen.pal60_enable = false;
333    }
334 }
335 
gfx_ctx_ps3_get_video_output_prev(void * data)336 static void gfx_ctx_ps3_get_video_output_prev(void *data)
337 {
338    global_t *global = global_get_ptr();
339 
340    if (!global)
341       return;
342 
343    if (global->console.screen.resolutions.current.idx)
344    {
345       global->console.screen.resolutions.current.idx--;
346       global->console.screen.resolutions.current.id =
347          global->console.screen.resolutions.list
348          [global->console.screen.resolutions.current.idx];
349    }
350 }
351 
gfx_ctx_ps3_get_video_output_next(void * data)352 static void gfx_ctx_ps3_get_video_output_next(void *data)
353 {
354    global_t *global = global_get_ptr();
355 
356    if (!global)
357       return;
358 
359    if (global->console.screen.resolutions.current.idx + 1 <
360          global->console.screen.resolutions.count)
361    {
362       global->console.screen.resolutions.current.idx++;
363       global->console.screen.resolutions.current.id =
364          global->console.screen.resolutions.list
365          [global->console.screen.resolutions.current.idx];
366    }
367 }
368 
gfx_ctx_ps3_get_flags(void * data)369 static uint32_t gfx_ctx_ps3_get_flags(void *data)
370 {
371    uint32_t flags = 0;
372 
373 #ifdef HAVE_CG
374    BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_CG);
375 #endif
376 
377    return flags;
378 }
379 
gfx_ctx_ps3_set_flags(void * data,uint32_t flags)380 static void gfx_ctx_ps3_set_flags(void *data, uint32_t flags) { }
381 
382 const gfx_ctx_driver_t gfx_ctx_ps3 = {
383    gfx_ctx_ps3_init,
384    gfx_ctx_ps3_destroy,
385    gfx_ctx_ps3_get_api,
386    gfx_ctx_ps3_bind_api,
387    gfx_ctx_ps3_set_swap_interval,
388    gfx_ctx_ps3_set_video_mode,
389    gfx_ctx_ps3_get_video_size,
390    NULL, /* get_refresh_rate */
391    gfx_ctx_ps3_get_video_output_size,
392    gfx_ctx_ps3_get_video_output_prev,
393    gfx_ctx_ps3_get_video_output_next,
394    NULL, /* get_metrics */
395    NULL,
396    NULL, /* update_title */
397    gfx_ctx_ps3_check_window,
398    NULL, /* set_resize */
399    gfx_ctx_ps3_has_focus,
400    gfx_ctx_ps3_suppress_screensaver,
401    false, /* has_windowed */
402    gfx_ctx_ps3_swap_buffers,
403    gfx_ctx_ps3_input_driver,
404    NULL,
405    NULL,
406    NULL,
407    NULL,
408    "ps3",
409    gfx_ctx_ps3_get_flags,
410    gfx_ctx_ps3_set_flags,
411    NULL,
412    NULL
413 };
414