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 #include <bps/screen.h>
20 #include <bps/navigator.h>
21 #include <bps/event.h>
22 #include <screen/screen.h>
23 #include <sys/platform.h>
24 
25 #ifdef HAVE_CONFIG_H
26 #include "../../config.h"
27 #endif
28 
29 #ifdef HAVE_OPENGLES2
30 #include <GLES2/gl2.h>
31 #elif HAVE_OPENGLES3
32 #include <GLES3/gl3.h>
33 #endif
34 
35 #ifdef HAVE_EGL
36 #include <EGL/egl.h>
37 #endif
38 
39 #ifdef HAVE_EGL
40 #include "../common/egl_common.h"
41 #endif
42 
43 #ifdef HAVE_OPENGLES
44 #include "../common/gl_common.h"
45 #endif
46 
47 #include "../../configuration.h"
48 #include "../../verbosity.h"
49 
50 #define WINDOW_BUFFERS 2
51 
52 typedef struct
53 {
54 #ifdef HAVE_EGL
55    egl_ctx_data_t egl;
56 #endif
57    screen_display_t screen_disp;
58    bool resize;
59 } qnx_ctx_data_t;
60 
61 /* TODO/FIXME - globals with public scope */
62 screen_context_t screen_ctx;
63 screen_window_t screen_win;
64 
65 
gfx_ctx_qnx_destroy(void * data)66 static void gfx_ctx_qnx_destroy(void *data)
67 {
68    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
69 
70 #ifdef HAVE_EGL
71    egl_destroy(&qnx->egl);
72 #endif
73 
74    free(data);
75 }
76 
gfx_ctx_qnx_init(void * video_driver)77 static void *gfx_ctx_qnx_init(void *video_driver)
78 {
79    EGLint n;
80    EGLint major, minor;
81    int usage, format;
82 #ifndef HAVE_BB10
83    int angle, size[2];
84    screen_display_mode_t screen_mode;
85 #endif
86    EGLint context_attributes[] = {
87 #ifdef HAVE_OPENGLES2
88            EGL_CONTEXT_CLIENT_VERSION, 2,
89 #elif HAVE_OPENGLES3
90            EGL_CONTEXT_CLIENT_VERSION, 3,
91 #endif
92       EGL_NONE
93    };
94 
95    const EGLint attribs[] = {
96 #ifdef HAVE_OPENGLES2
97       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
98 #elif HAVE_OPENGLES3
99       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
100 #endif
101       EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
102       EGL_BLUE_SIZE, 8,
103       EGL_GREEN_SIZE, 8,
104       EGL_RED_SIZE, 8,
105       EGL_NONE
106    };
107 
108    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)calloc(1, sizeof(*qnx));
109 
110    if (!qnx)
111        goto screen_error;
112 
113    /* Create a screen context that will be used to
114     * create an EGL surface to receive libscreen events */
115 
116    RARCH_LOG("Initializing screen context...\n");
117    if (!screen_ctx)
118    {
119       screen_create_context(&screen_ctx, 0);
120 
121       if (screen_request_events(screen_ctx) != BPS_SUCCESS)
122       {
123          RARCH_ERR("screen_request_events failed.\n");
124          goto screen_error;
125       }
126 
127       if (navigator_request_events(0) != BPS_SUCCESS)
128       {
129          RARCH_ERR("navigator_request_events failed.\n");
130          goto screen_error;
131       }
132 
133       if (navigator_rotation_lock(false) != BPS_SUCCESS)
134       {
135          RARCH_ERR("navigator_location_lock failed.\n");
136          goto screen_error;
137       }
138    }
139 
140 #ifdef HAVE_EGL
141    if (!egl_init_context(&qnx->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor,
142             &n, attribs, NULL))
143       goto error;
144 
145    if (!egl_create_context(&qnx->egl, context_attributes))
146       goto error;
147 #endif
148 
149    if(!screen_win)
150    {
151       if (screen_create_window(&screen_win, screen_ctx))
152       {
153              RARCH_ERR("screen_create_window failed:.\n");
154 	     goto error;
155       }
156    }
157 
158    format = SCREEN_FORMAT_RGBX8888;
159    if (screen_set_window_property_iv(screen_win,
160             SCREEN_PROPERTY_FORMAT, &format))
161    {
162       RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_FORMAT] failed.\n");
163       goto error;
164    }
165 
166 #ifdef HAVE_OPENGLES2
167    usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_ROTATION;
168 #elif HAVE_OPENGLES3
169    usage = SCREEN_USAGE_OPENGL_ES3 | SCREEN_USAGE_ROTATION;
170 #endif
171    if (screen_set_window_property_iv(screen_win,
172             SCREEN_PROPERTY_USAGE, &usage))
173    {
174       RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_USAGE] failed.\n");
175       goto error;
176    }
177 
178    if (screen_get_window_property_pv(screen_win,
179             SCREEN_PROPERTY_DISPLAY, (void **)&qnx->screen_disp))
180    {
181       RARCH_ERR("screen_get_window_property_pv [SCREEN_PROPERTY_DISPLAY] failed.\n");
182       goto error;
183    }
184 
185    int screen_resolution[2];
186 
187    if (screen_get_display_property_iv(qnx->screen_disp,
188             SCREEN_PROPERTY_SIZE, screen_resolution))
189    {
190       RARCH_ERR("screen_get_window_property_iv [SCREEN_PROPERTY_SIZE] failed.\n");
191       goto error;
192    }
193 
194 #ifndef HAVE_BB10
195    angle = atoi(getenv("ORIENTATION"));
196 
197    if (screen_get_display_property_pv(qnx->screen_disp,
198             SCREEN_PROPERTY_MODE, (void**)&screen_mode))
199    {
200       RARCH_ERR("screen_get_display_property_pv [SCREEN_PROPERTY_MODE] failed.\n");
201       goto error;
202    }
203 
204    if (screen_get_window_property_iv(screen_win,
205             SCREEN_PROPERTY_BUFFER_SIZE, size))
206    {
207       RARCH_ERR("screen_get_window_property_iv [SCREEN_PROPERTY_BUFFER_SIZE] failed.\n");
208       goto error;
209    }
210 
211    int buffer_size[2] = {size[0], size[1]};
212 
213    if ((angle == 0) || (angle == 180))
214    {
215       if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) ||
216             ((screen_mode.width < screen_mode.height) && (size[0] > size[1])))
217       {
218          buffer_size[1] = size[0];
219          buffer_size[0] = size[1];
220       }
221    }
222    else if ((angle == 90) || (angle == 270))
223    {
224       if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) ||
225             ((screen_mode.width < screen_mode.height && size[0] < size[1])))
226       {
227          buffer_size[1] = size[0];
228          buffer_size[0] = size[1];
229       }
230    }
231    else
232    {
233       RARCH_ERR("Navigator returned an unexpected orientation angle.\n");
234       goto error;
235    }
236 
237    if (screen_set_window_property_iv(screen_win,
238             SCREEN_PROPERTY_BUFFER_SIZE, buffer_size))
239    {
240       RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_BUFFER_SIZE] failed.\n");
241       goto error;
242    }
243 
244    if (screen_set_window_property_iv(screen_win,
245             SCREEN_PROPERTY_ROTATION, &angle))
246    {
247       RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_ROTATION] failed.\n");
248       goto error;
249    }
250 #endif
251 
252    if (screen_create_window_buffers(screen_win, WINDOW_BUFFERS))
253    {
254       RARCH_ERR("screen_create_window_buffers failed.\n");
255       goto error;
256    }
257 
258    if (!egl_create_surface(&qnx->egl, screen_win))
259       goto error;
260 
261    return qnx;
262 
263 error:
264    egl_report_error();
265    gfx_ctx_qnx_destroy(video_driver);
266 screen_error:
267    screen_stop_events(screen_ctx);
268    return NULL;
269 }
270 
gfx_ctx_qnx_get_video_size(void * data,unsigned * width,unsigned * height)271 static void gfx_ctx_qnx_get_video_size(void *data,
272       unsigned *width, unsigned *height)
273 {
274    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
275 
276 #ifdef HAVE_EGL
277    egl_get_video_size(&qnx->egl, width, height);
278 #endif
279 }
280 
gfx_ctx_qnx_check_window(void * data,bool * quit,bool * resize,unsigned * width,unsigned * height)281 static void gfx_ctx_qnx_check_window(void *data, bool *quit,
282       bool *resize, unsigned *width, unsigned *height)
283 {
284    unsigned new_width, new_height;
285    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
286 
287    *quit = false;
288 
289 #ifdef HAVE_EGL
290    egl_get_video_size(&qnx->egl, &new_width, &new_height);
291 #endif
292 
293    if (new_width != *width || new_height != *height)
294    {
295       *width  = new_width;
296       *height = new_height;
297       *resize = true;
298    }
299 }
300 
gfx_ctx_qnx_set_video_mode(void * data,unsigned width,unsigned height,bool fullscreen)301 static bool gfx_ctx_qnx_set_video_mode(void *data,
302       unsigned width, unsigned height,
303       bool fullscreen) { return true; }
304 
gfx_ctx_qnx_input_driver(void * data,const char * joypad_name,input_driver_t ** input,void ** input_data)305 static void gfx_ctx_qnx_input_driver(void *data,
306       const char *joypad_name,
307       input_driver_t **input, void **input_data)
308 {
309    void *qnxinput       = input_driver_init_wrap(&input_qnx, joypad_name);
310 
311    *input               = qnxinput ? &input_qnx : NULL;
312    *input_data          = qnxinput;
313 }
314 
gfx_ctx_qnx_get_api(void * data)315 static enum gfx_ctx_api gfx_ctx_qnx_get_api(void *data) { return GFX_CTX_OPENGL_ES_API; }
316 
gfx_ctx_qnx_bind_api(void * data,enum gfx_ctx_api api,unsigned major,unsigned minor)317 static bool gfx_ctx_qnx_bind_api(void *data,
318       enum gfx_ctx_api api, unsigned major, unsigned minor)
319 {
320    if (api == GFX_CTX_OPENGL_ES_API)
321       return true;
322    return false;
323 }
324 
gfx_ctx_qnx_has_focus(void * data)325 static bool gfx_ctx_qnx_has_focus(void *data) { return true; }
326 
gfx_ctx_qnx_suppress_screensaver(void * data,bool enable)327 static bool gfx_ctx_qnx_suppress_screensaver(void *data, bool enable) { return false; }
328 
dpi_get_density(qnx_ctx_data_t * qnx)329 static int dpi_get_density(qnx_ctx_data_t *qnx)
330 {
331     int screen_dpi[2];
332 
333     if(!qnx)
334         return -1;
335 
336     if (screen_get_display_property_iv(qnx->screen_disp,
337              SCREEN_PROPERTY_DPI, screen_dpi))
338     {
339        RARCH_ERR("screen_get_display_property_iv [SCREEN_PROPERTY_DPI] failed.\n");
340        return -1;
341     }
342 
343     return min(screen_dpi[0], screen_dpi[1]);
344 }
345 
gfx_ctx_qnx__get_metrics(void * data,enum display_metric_types type,float * value)346 static bool gfx_ctx_qnx__get_metrics(void *data,
347     enum display_metric_types type, float *value)
348 {
349    static int dpi = -1;
350    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
351 
352    switch (type)
353    {
354       case DISPLAY_METRIC_MM_WIDTH:
355          return false;
356       case DISPLAY_METRIC_MM_HEIGHT:
357          return false;
358       case DISPLAY_METRIC_DPI:
359          if (dpi == -1)
360          {
361             dpi = dpi_get_density(qnx);
362             if (dpi <= 0)
363                goto dpi_fallback;
364          }
365          *value = (float)dpi;
366          break;
367       case DISPLAY_METRIC_NONE:
368       default:
369          *value = 0;
370          return false;
371    }
372 
373    return true;
374 
375 dpi_fallback:
376    /* Add a fallback in case the device doesn't report DPI.
377     * Calculated as an average of all BB10 device DPIs circa 2016. */
378    dpi    = 345;
379    *value = (float)dpi;
380    return true;
381 }
382 
gfx_ctx_qnx_set_swap_interval(void * data,int swap_interval)383 static void gfx_ctx_qnx_set_swap_interval(void *data, int swap_interval)
384 {
385    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
386 
387 #ifdef HAVE_EGL
388    egl_set_swap_interval(&qnx->egl, swap_interval);
389 #endif
390 }
391 
gfx_ctx_qnx_swap_buffers(void * data)392 static void gfx_ctx_qnx_swap_buffers(void *data)
393 {
394    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
395 
396 #ifdef HAVE_EGL
397    egl_swap_buffers(&qnx->egl);
398 #endif
399 }
400 
gfx_ctx_qnx_bind_hw_render(void * data,bool enable)401 static void gfx_ctx_qnx_bind_hw_render(void *data, bool enable)
402 {
403    qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
404 
405 #ifdef HAVE_EGL
406    egl_bind_hw_render(&qnx->egl, enable);
407 #endif
408 }
409 
gfx_ctx_qnx_get_flags(void * data)410 static uint32_t gfx_ctx_qnx_get_flags(void *data)
411 {
412    uint32_t flags = 0;
413 
414    BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL);
415 
416    return flags;
417 }
418 
gfx_ctx_qnx_set_flags(void * data,uint32_t flags)419 static void gfx_ctx_qnx_set_flags(void *data, uint32_t flags) { }
420 
421 const gfx_ctx_driver_t gfx_ctx_qnx = {
422    gfx_ctx_qnx_init,
423    gfx_ctx_qnx_destroy,
424    gfx_ctx_qnx_get_api,
425    gfx_ctx_qnx_bind_api,
426    gfx_ctx_qnx_set_swap_interval,
427    gfx_ctx_qnx_set_video_mode,
428    gfx_ctx_qnx_get_video_size,
429    NULL, /* get_refresh_rate */
430    NULL, /* get_video_output_size */
431    NULL, /* get_video_output_prev */
432    NULL, /* get_video_output_next */
433    gfx_ctx_qnx__get_metrics,
434    NULL,
435    NULL, /* update_title */
436    gfx_ctx_qnx_check_window,
437    NULL, /* set_resize */
438    gfx_ctx_qnx_has_focus,
439    gfx_ctx_qnx_suppress_screensaver,
440    false, /* has_windowed */
441    gfx_ctx_qnx_swap_buffers,
442    gfx_ctx_qnx_input_driver,
443 #ifdef HAVE_EGL
444    egl_get_proc_address,
445 #else
446    NULL,
447 #endif
448    NULL,
449    NULL,
450    NULL,
451    "egl_qnx",
452    gfx_ctx_qnx_get_flags,
453    gfx_ctx_qnx_set_flags,
454    gfx_ctx_qnx_bind_hw_render,
455    NULL,
456    NULL
457 };
458