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