1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 * Copyright (C) 2012-2015 - Michael Lelli
5 *
6 * RetroArch is free software: you can redistribute it and/or modify it under the terms
7 * of the GNU General Public License as published by the Free Software Found-
8 * ation, either version 3 of the License, or (at your option) any later version.
9 *
10 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with RetroArch.
15 * If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /* Middle of the road OpenGL driver.
19 *
20 * Minimum version (desktop): OpenGL 2.0+
21 * Minimum version (mobile) : OpenGLES 2.0+
22 */
23
24 #ifdef _MSC_VER
25 #if defined(HAVE_OPENGLES)
26 #pragma comment(lib, "libGLESv2")
27 #else
28 #pragma comment(lib, "opengl32")
29 #endif
30 #endif
31
32 #include <stdint.h>
33 #include <math.h>
34 #include <string.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <compat/strl.h>
41 #include <gfx/scaler/scaler.h>
42 #include <gfx/math/matrix_4x4.h>
43 #include <formats/image.h>
44 #include <retro_inline.h>
45 #include <retro_miscellaneous.h>
46 #include <retro_math.h>
47 #include <string/stdstring.h>
48 #include <libretro.h>
49
50 #include <gfx/gl_capabilities.h>
51 #include <gfx/video_frame.h>
52 #include <glsym/glsym.h>
53
54 #include "../../configuration.h"
55 #include "../../dynamic.h"
56
57 #include "../../retroarch.h"
58 #include "../../verbosity.h"
59 #include "../common/gl_common.h"
60
61 #ifdef HAVE_THREADS
62 #include "../video_thread_wrapper.h"
63 #endif
64
65 #include "../font_driver.h"
66
67 #ifdef HAVE_GLSL
68 #include "../drivers_shader/shader_glsl.h"
69 #endif
70
71 #ifdef GL_DEBUG
72 #include <lists/string_list.h>
73
74 #if defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2)
75 #define HAVE_GL_DEBUG_ES
76 #endif
77 #endif
78
79 #ifdef HAVE_MENU
80 #include "../../menu/menu_driver.h"
81 #endif
82 #ifdef HAVE_GFX_WIDGETS
83 #include "../gfx_widgets.h"
84 #endif
85
86 #ifndef GL_UNSIGNED_INT_8_8_8_8_REV
87 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
88 #endif
89
90 #define SET_TEXTURE_COORDS(coords, xamt, yamt) \
91 coords[2] = xamt; \
92 coords[6] = xamt; \
93 coords[5] = yamt; \
94 coords[7] = yamt
95
96 static const shader_backend_t *gl2_shader_ctx_drivers[] = {
97 #ifdef HAVE_GLSL
98 &gl_glsl_backend,
99 #endif
100 #ifdef HAVE_CG
101 &gl_cg_backend,
102 #endif
103 NULL
104 };
105
106 static struct video_ortho default_ortho = {0, 1, 0, 1, -1, 1};
107
108 /* Used for the last pass when rendering to the back buffer. */
109 static const GLfloat vertexes_flipped[] = {
110 0, 1,
111 1, 1,
112 0, 0,
113 1, 0
114 };
115
116 /* Used when rendering to an FBO.
117 * Texture coords have to be aligned
118 * with vertex coordinates. */
119 static const GLfloat vertexes[] = {
120 0, 0,
121 1, 0,
122 0, 1,
123 1, 1
124 };
125
126 static const GLfloat tex_coords[] = {
127 0, 0,
128 1, 0,
129 0, 1,
130 1, 1
131 };
132
133 static const GLfloat white_color[] = {
134 1, 1, 1, 1,
135 1, 1, 1, 1,
136 1, 1, 1, 1,
137 1, 1, 1, 1,
138 };
139
140 #define gl2_context_bind_hw_render(gl, enable) \
141 if (gl->shared_context_use) \
142 gl->ctx_driver->bind_hw_render(gl->ctx_data, enable)
143
144 #define MAX_FENCES 4
145
146 #if !defined(HAVE_PSGL)
147
148 #ifndef HAVE_GL_SYNC
149 #define HAVE_GL_SYNC
150 #endif
151
152 #endif
153
154 #ifdef HAVE_GL_SYNC
155 #if defined(HAVE_OPENGLES2)
156 typedef struct __GLsync *GLsync;
157 #endif
158 #endif
159
160 typedef struct gl2_renderchain_data
161 {
162 int fbo_pass;
163
164 #ifdef HAVE_GL_SYNC
165 GLsync fences[MAX_FENCES];
166 #endif
167
168 GLuint vao;
169 GLuint fbo[GFX_MAX_SHADERS];
170 GLuint fbo_texture[GFX_MAX_SHADERS];
171 GLuint hw_render_depth[GFX_MAX_TEXTURES];
172
173 unsigned fence_count;
174
175 struct gfx_fbo_scale fbo_scale[GFX_MAX_SHADERS];
176
177 bool egl_images;
178 bool has_fp_fbo;
179 bool has_srgb_fbo_gles3;
180 bool has_srgb_fbo;
181 bool hw_render_depth_init;
182 } gl2_renderchain_data_t;
183
184 #if (!defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3))
185 #ifdef GL_PIXEL_PACK_BUFFER
186 #define HAVE_GL_ASYNC_READBACK
187 #endif
188 #endif
189
190 #if defined(HAVE_PSGL)
191 #define gl2_fb_texture_2d(a, b, c, d, e) glFramebufferTexture2DOES(a, b, c, d, e)
192 #define gl2_check_fb_status(target) glCheckFramebufferStatusOES(target)
193 #define gl2_gen_fb(n, ids) glGenFramebuffersOES(n, ids)
194 #define gl2_delete_fb(n, fb) glDeleteFramebuffersOES(n, fb)
195 #define gl2_bind_fb(id) glBindFramebufferOES(RARCH_GL_FRAMEBUFFER, id)
196 #define gl2_gen_rb glGenRenderbuffersOES
197 #define gl2_bind_rb glBindRenderbufferOES
198 #define gl2_fb_rb glFramebufferRenderbufferOES
199 #define gl2_rb_storage glRenderbufferStorageOES
200 #define gl2_delete_rb glDeleteRenderbuffersOES
201
202 #elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
203 #define gl2_fb_texture_2d(a, b, c, d, e) glFramebufferTexture2DEXT(a, b, c, d, e)
204 #define gl2_check_fb_status(target) glCheckFramebufferStatusEXT(target)
205 #define gl2_gen_fb(n, ids) glGenFramebuffersEXT(n, ids)
206 #define gl2_delete_fb(n, fb) glDeleteFramebuffersEXT(n, fb)
207 #define gl2_bind_fb(id) glBindFramebufferEXT(RARCH_GL_FRAMEBUFFER, id)
208 #define gl2_gen_rb glGenRenderbuffersEXT
209 #define gl2_bind_rb glBindRenderbufferEXT
210 #define gl2_fb_rb glFramebufferRenderbufferEXT
211 #define gl2_rb_storage glRenderbufferStorageEXT
212 #define gl2_delete_rb glDeleteRenderbuffersEXT
213
214 #else
215
216 #define gl2_fb_texture_2d(a, b, c, d, e) glFramebufferTexture2D(a, b, c, d, e)
217 #define gl2_check_fb_status(target) glCheckFramebufferStatus(target)
218 #define gl2_gen_fb(n, ids) glGenFramebuffers(n, ids)
219 #define gl2_delete_fb(n, fb) glDeleteFramebuffers(n, fb)
220 #define gl2_bind_fb(id) glBindFramebuffer(RARCH_GL_FRAMEBUFFER, id)
221 #define gl2_gen_rb glGenRenderbuffers
222 #define gl2_bind_rb glBindRenderbuffer
223 #define gl2_fb_rb glFramebufferRenderbuffer
224 #define gl2_rb_storage glRenderbufferStorage
225 #define gl2_delete_rb glDeleteRenderbuffers
226
227 #endif
228
229 #ifndef GL_SYNC_GPU_COMMANDS_COMPLETE
230 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
231 #endif
232
233 #ifndef GL_SYNC_FLUSH_COMMANDS_BIT
234 #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
235 #endif
236
237 /* Prototypes */
238 #ifdef IOS
239 /* There is no default frame buffer on iOS. */
240 void glkitview_bind_fbo(void);
241 #define gl2_renderchain_bind_backbuffer() glkitview_bind_fbo()
242 #else
243 #define gl2_renderchain_bind_backbuffer() gl2_bind_fb(0)
244 #endif
245
gl2_get_alignment(unsigned pitch)246 static unsigned gl2_get_alignment(unsigned pitch)
247 {
248 if (pitch & 1)
249 return 1;
250 if (pitch & 2)
251 return 2;
252 if (pitch & 4)
253 return 4;
254 return 8;
255 }
256
gl2_shader_info(gl_t * gl,video_shader_ctx_info_t * shader_info)257 static bool gl2_shader_info(gl_t *gl,
258 video_shader_ctx_info_t *shader_info)
259 {
260 if (!shader_info)
261 return false;
262
263 shader_info->num = gl->shader->num_shaders(gl->shader_data);
264
265 return true;
266 }
267
gl2_shader_scale(gl_t * gl,video_shader_ctx_scale_t * scaler)268 static bool gl2_shader_scale(gl_t *gl,
269 video_shader_ctx_scale_t *scaler)
270 {
271 if (!scaler || !scaler->scale)
272 return false;
273
274 scaler->scale->valid = false;
275
276 gl->shader->shader_scale(gl->shader_data,
277 scaler->idx, scaler->scale);
278 return true;
279 }
280
gl2_size_format(GLint * internalFormat)281 static void gl2_size_format(GLint* internalFormat)
282 {
283 #ifndef HAVE_PSGL
284 switch (*internalFormat)
285 {
286 case GL_RGB:
287 /* FIXME: PS3 does not support this, neither does it have GL_RGB565_OES. */
288 *internalFormat = GL_RGB565;
289 break;
290 case GL_RGBA:
291 #ifdef HAVE_OPENGLES2
292 *internalFormat = GL_RGBA8_OES;
293 #else
294 *internalFormat = GL_RGBA8;
295 #endif
296 break;
297 }
298 #endif
299 }
300
301 /* This function should only be used without mipmaps
302 and when data == NULL */
gl2_load_texture_image(GLenum target,GLint level,GLint internalFormat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid * data)303 static void gl2_load_texture_image(GLenum target,
304 GLint level,
305 GLint internalFormat,
306 GLsizei width,
307 GLsizei height,
308 GLint border,
309 GLenum format,
310 GLenum type,
311 const GLvoid * data)
312 {
313 #if !defined(HAVE_PSGL) && !defined(ORBIS) && !defined(VITA)
314 #ifdef HAVE_OPENGLES2
315 enum gl_capability_enum cap = GL_CAPS_TEX_STORAGE_EXT;
316 #else
317 enum gl_capability_enum cap = GL_CAPS_TEX_STORAGE;
318 #endif
319
320 if (gl_check_capability(cap) && internalFormat != GL_BGRA_EXT)
321 {
322 gl2_size_format(&internalFormat);
323 #ifdef HAVE_OPENGLES2
324 glTexStorage2DEXT(target, 1, internalFormat, width, height);
325 #else
326 glTexStorage2D (target, 1, internalFormat, width, height);
327 #endif
328 }
329 else
330 #endif
331 {
332 #ifdef HAVE_OPENGLES
333 if (gl_check_capability(GL_CAPS_GLES3_SUPPORTED))
334 #endif
335 gl2_size_format(&internalFormat);
336 glTexImage2D(target, level, internalFormat, width,
337 height, border, format, type, data);
338 }
339 }
340
gl2_recreate_fbo(struct video_fbo_rect * fbo_rect,GLuint fbo,GLuint * texture)341 static bool gl2_recreate_fbo(
342 struct video_fbo_rect *fbo_rect,
343 GLuint fbo,
344 GLuint* texture
345 )
346 {
347 gl2_bind_fb(fbo);
348 glDeleteTextures(1, texture);
349 glGenTextures(1, texture);
350 glBindTexture(GL_TEXTURE_2D, *texture);
351 gl2_load_texture_image(GL_TEXTURE_2D,
352 0, RARCH_GL_INTERNAL_FORMAT32,
353 fbo_rect->width,
354 fbo_rect->height,
355 0, RARCH_GL_TEXTURE_TYPE32,
356 RARCH_GL_FORMAT32, NULL);
357
358 gl2_fb_texture_2d(RARCH_GL_FRAMEBUFFER,
359 RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
360 *texture, 0);
361
362 if (gl2_check_fb_status(RARCH_GL_FRAMEBUFFER)
363 == RARCH_GL_FRAMEBUFFER_COMPLETE)
364 return true;
365
366 RARCH_WARN("[GL]: Failed to reinitialize FBO texture.\n");
367 return false;
368 }
369
gl2_set_projection(gl_t * gl,struct video_ortho * ortho,bool allow_rotate)370 static void gl2_set_projection(gl_t *gl,
371 struct video_ortho *ortho, bool allow_rotate)
372 {
373 math_matrix_4x4 rot;
374
375 /* Calculate projection. */
376 matrix_4x4_ortho(gl->mvp_no_rot, ortho->left, ortho->right,
377 ortho->bottom, ortho->top, ortho->znear, ortho->zfar);
378
379 if (!allow_rotate)
380 {
381 gl->mvp = gl->mvp_no_rot;
382 return;
383 }
384
385 matrix_4x4_rotate_z(rot, M_PI * gl->rotation / 180.0f);
386 matrix_4x4_multiply(gl->mvp, rot, gl->mvp_no_rot);
387 }
388
gl2_set_viewport(gl_t * gl,unsigned viewport_width,unsigned viewport_height,bool force_full,bool allow_rotate)389 static void gl2_set_viewport(gl_t *gl,
390 unsigned viewport_width,
391 unsigned viewport_height,
392 bool force_full, bool allow_rotate)
393 {
394 settings_t *settings = config_get_ptr();
395 unsigned height = gl->video_height;
396 int x = 0;
397 int y = 0;
398 float device_aspect = (float)viewport_width / viewport_height;
399
400 if (gl->ctx_driver->translate_aspect)
401 device_aspect = gl->ctx_driver->translate_aspect(
402 gl->ctx_data, viewport_width, viewport_height);
403
404 if (settings->bools.video_scale_integer && !force_full)
405 {
406 video_viewport_get_scaled_integer(&gl->vp,
407 viewport_width, viewport_height,
408 video_driver_get_aspect_ratio(), gl->keep_aspect);
409 viewport_width = gl->vp.width;
410 viewport_height = gl->vp.height;
411 }
412 else if (gl->keep_aspect && !force_full)
413 {
414 float desired_aspect = video_driver_get_aspect_ratio();
415
416 #if defined(HAVE_MENU)
417 if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
418 {
419 const struct video_viewport *custom = video_viewport_get_custom();
420 /* GL has bottom-left origin viewport. */
421 x = custom->x;
422 y = height - custom->y - custom->height;
423 viewport_width = custom->width;
424 viewport_height = custom->height;
425 }
426 else
427 #endif
428 {
429 float delta;
430
431 if (fabsf(device_aspect - desired_aspect) < 0.0001f)
432 {
433 /* If the aspect ratios of screen and desired aspect
434 * ratio are sufficiently equal (floating point stuff),
435 * assume they are actually equal.
436 */
437 }
438 else if (device_aspect > desired_aspect)
439 {
440 delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
441 x = (int)roundf(viewport_width * (0.5f - delta));
442 viewport_width = (unsigned)roundf(2.0f * viewport_width * delta);
443 }
444 else
445 {
446 delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
447 y = (int)roundf(viewport_height * (0.5f - delta));
448 viewport_height = (unsigned)roundf(2.0f * viewport_height * delta);
449 }
450 }
451
452 gl->vp.x = x;
453 gl->vp.y = y;
454 gl->vp.width = viewport_width;
455 gl->vp.height = viewport_height;
456 }
457 else
458 {
459 gl->vp.x = gl->vp.y = 0;
460 gl->vp.width = viewport_width;
461 gl->vp.height = viewport_height;
462 }
463
464 #if defined(RARCH_MOBILE)
465 /* In portrait mode, we want viewport to gravitate to top of screen. */
466 if (device_aspect < 1.0f)
467 gl->vp.y *= 2;
468 #endif
469
470 glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
471 gl2_set_projection(gl, &default_ortho, allow_rotate);
472
473 /* Set last backbuffer viewport. */
474 if (!force_full)
475 {
476 gl->vp_out_width = viewport_width;
477 gl->vp_out_height = viewport_height;
478 }
479
480 #if 0
481 RARCH_LOG("Setting viewport @ %ux%u\n", viewport_width, viewport_height);
482 #endif
483 }
484
gl2_renderchain_render(gl_t * gl,gl2_renderchain_data_t * chain,uint64_t frame_count,const struct video_tex_info * tex_info,const struct video_tex_info * feedback_info)485 static void gl2_renderchain_render(
486 gl_t *gl,
487 gl2_renderchain_data_t *chain,
488 uint64_t frame_count,
489 const struct video_tex_info *tex_info,
490 const struct video_tex_info *feedback_info)
491 {
492 int i;
493 video_shader_ctx_params_t params;
494 static GLfloat fbo_tex_coords[8] = {0.0f};
495 struct video_tex_info fbo_tex_info[GFX_MAX_SHADERS];
496 struct video_tex_info *fbo_info = NULL;
497 const struct video_fbo_rect *prev_rect = NULL;
498 GLfloat xamt = 0.0f;
499 GLfloat yamt = 0.0f;
500 unsigned mip_level = 0;
501 unsigned fbo_tex_info_cnt = 0;
502 unsigned width = gl->video_width;
503 unsigned height = gl->video_height;
504
505 /* Render the rest of our passes. */
506 gl->coords.tex_coord = fbo_tex_coords;
507
508 /* Calculate viewports, texture coordinates etc,
509 * and render all passes from FBOs, to another FBO. */
510 for (i = 1; i < chain->fbo_pass; i++)
511 {
512 const struct video_fbo_rect *rect = &gl->fbo_rect[i];
513
514 prev_rect = &gl->fbo_rect[i - 1];
515 fbo_info = &fbo_tex_info[i - 1];
516
517 xamt = (GLfloat)prev_rect->img_width / prev_rect->width;
518 yamt = (GLfloat)prev_rect->img_height / prev_rect->height;
519
520 SET_TEXTURE_COORDS(fbo_tex_coords, xamt, yamt);
521
522 fbo_info->tex = chain->fbo_texture[i - 1];
523 fbo_info->input_size[0] = prev_rect->img_width;
524 fbo_info->input_size[1] = prev_rect->img_height;
525 fbo_info->tex_size[0] = prev_rect->width;
526 fbo_info->tex_size[1] = prev_rect->height;
527 memcpy(fbo_info->coord, fbo_tex_coords, sizeof(fbo_tex_coords));
528 fbo_tex_info_cnt++;
529
530 gl2_bind_fb(chain->fbo[i]);
531
532 gl->shader->use(gl, gl->shader_data,
533 i + 1, true);
534
535 glBindTexture(GL_TEXTURE_2D, chain->fbo_texture[i - 1]);
536
537 mip_level = i + 1;
538
539 if (gl->shader->mipmap_input(gl->shader_data, mip_level)
540 && gl->have_mipmap)
541 glGenerateMipmap(GL_TEXTURE_2D);
542
543 glClear(GL_COLOR_BUFFER_BIT);
544
545 /* Render to FBO with certain size. */
546 gl2_set_viewport(gl,
547 rect->img_width, rect->img_height, true, false);
548
549 params.data = gl;
550 params.width = prev_rect->img_width;
551 params.height = prev_rect->img_height;
552 params.tex_width = prev_rect->width;
553 params.tex_height = prev_rect->height;
554 params.out_width = gl->vp.width;
555 params.out_height = gl->vp.height;
556 params.frame_counter = (unsigned int)frame_count;
557 params.info = tex_info;
558 params.prev_info = gl->prev_info;
559 params.feedback_info = feedback_info;
560 params.fbo_info = fbo_tex_info;
561 params.fbo_info_cnt = fbo_tex_info_cnt;
562
563 gl->shader->set_params(¶ms, gl->shader_data);
564
565 gl->coords.vertices = 4;
566
567 gl->shader->set_coords(gl->shader_data, &gl->coords);
568 gl->shader->set_mvp(gl->shader_data, &gl->mvp);
569
570 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
571 }
572
573 #if defined(GL_FRAMEBUFFER_SRGB) && !defined(HAVE_OPENGLES)
574 if (chain->has_srgb_fbo)
575 glDisable(GL_FRAMEBUFFER_SRGB);
576 #endif
577
578 /* Render our last FBO texture directly to screen. */
579 prev_rect = &gl->fbo_rect[chain->fbo_pass - 1];
580 xamt = (GLfloat)prev_rect->img_width / prev_rect->width;
581 yamt = (GLfloat)prev_rect->img_height / prev_rect->height;
582
583 SET_TEXTURE_COORDS(fbo_tex_coords, xamt, yamt);
584
585 /* Push final FBO to list. */
586 fbo_info = &fbo_tex_info[chain->fbo_pass - 1];
587
588 fbo_info->tex = chain->fbo_texture[chain->fbo_pass - 1];
589 fbo_info->input_size[0] = prev_rect->img_width;
590 fbo_info->input_size[1] = prev_rect->img_height;
591 fbo_info->tex_size[0] = prev_rect->width;
592 fbo_info->tex_size[1] = prev_rect->height;
593 memcpy(fbo_info->coord, fbo_tex_coords, sizeof(fbo_tex_coords));
594 fbo_tex_info_cnt++;
595
596 /* Render our FBO texture to back buffer. */
597 gl2_renderchain_bind_backbuffer();
598
599 gl->shader->use(gl, gl->shader_data,
600 chain->fbo_pass + 1, true);
601
602 glBindTexture(GL_TEXTURE_2D, chain->fbo_texture[chain->fbo_pass - 1]);
603
604 mip_level = chain->fbo_pass + 1;
605
606 if (
607 gl->shader->mipmap_input(gl->shader_data, mip_level) &&
608 gl->have_mipmap)
609 glGenerateMipmap(GL_TEXTURE_2D);
610
611 glClear(GL_COLOR_BUFFER_BIT);
612 gl2_set_viewport(gl,
613 width, height, false, true);
614
615 params.data = gl;
616 params.width = prev_rect->img_width;
617 params.height = prev_rect->img_height;
618 params.tex_width = prev_rect->width;
619 params.tex_height = prev_rect->height;
620 params.out_width = gl->vp.width;
621 params.out_height = gl->vp.height;
622 params.frame_counter = (unsigned int)frame_count;
623 params.info = tex_info;
624 params.prev_info = gl->prev_info;
625 params.feedback_info = feedback_info;
626 params.fbo_info = fbo_tex_info;
627 params.fbo_info_cnt = fbo_tex_info_cnt;
628
629 gl->shader->set_params(¶ms, gl->shader_data);
630
631 gl->coords.vertex = gl->vertex_ptr;
632
633 gl->coords.vertices = 4;
634
635 gl->shader->set_coords(gl->shader_data, &gl->coords);
636 gl->shader->set_mvp(gl->shader_data, &gl->mvp);
637
638 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
639
640 gl->coords.tex_coord = gl->tex_info.coord;
641 }
642
gl2_renderchain_deinit_fbo(gl_t * gl,gl2_renderchain_data_t * chain)643 static void gl2_renderchain_deinit_fbo(gl_t *gl,
644 gl2_renderchain_data_t *chain)
645 {
646 if (gl)
647 {
648 if (gl->fbo_feedback)
649 gl2_delete_fb(1, &gl->fbo_feedback);
650 if (gl->fbo_feedback_texture)
651 glDeleteTextures(1, &gl->fbo_feedback_texture);
652
653 gl->fbo_inited = false;
654 gl->fbo_feedback_enable = false;
655 gl->fbo_feedback_pass = 0;
656 gl->fbo_feedback_texture = 0;
657 gl->fbo_feedback = 0;
658 }
659
660 if (chain)
661 {
662 gl2_delete_fb(chain->fbo_pass, chain->fbo);
663 glDeleteTextures(chain->fbo_pass, chain->fbo_texture);
664
665 memset(chain->fbo_texture, 0, sizeof(chain->fbo_texture));
666 memset(chain->fbo, 0, sizeof(chain->fbo));
667
668 chain->fbo_pass = 0;
669 }
670 }
671
gl2_renderchain_deinit_hw_render(gl_t * gl,gl2_renderchain_data_t * chain)672 static void gl2_renderchain_deinit_hw_render(
673 gl_t *gl,
674 gl2_renderchain_data_t *chain)
675 {
676 if (!gl)
677 return;
678
679 gl2_context_bind_hw_render(gl, true);
680
681 if (gl->hw_render_fbo_init)
682 gl2_delete_fb(gl->textures, gl->hw_render_fbo);
683 if (chain->hw_render_depth_init)
684 gl2_delete_rb(gl->textures, chain->hw_render_depth);
685 gl->hw_render_fbo_init = false;
686
687 gl2_context_bind_hw_render(gl, false);
688 }
689
gl2_create_fbo_targets(gl_t * gl,gl2_renderchain_data_t * chain)690 static bool gl2_create_fbo_targets(gl_t *gl, gl2_renderchain_data_t *chain)
691 {
692 unsigned i;
693
694 glBindTexture(GL_TEXTURE_2D, 0);
695 gl2_gen_fb(chain->fbo_pass, chain->fbo);
696
697 for (i = 0; i < (unsigned)chain->fbo_pass; i++)
698 {
699 GLenum status;
700
701 gl2_bind_fb(chain->fbo[i]);
702 gl2_fb_texture_2d(RARCH_GL_FRAMEBUFFER,
703 RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, chain->fbo_texture[i], 0);
704
705 status = gl2_check_fb_status(RARCH_GL_FRAMEBUFFER);
706 if (status != RARCH_GL_FRAMEBUFFER_COMPLETE)
707 goto error;
708 }
709
710 if (gl->fbo_feedback_texture)
711 {
712 GLenum status;
713
714 gl2_gen_fb(1, &gl->fbo_feedback);
715 gl2_bind_fb(gl->fbo_feedback);
716 gl2_fb_texture_2d(RARCH_GL_FRAMEBUFFER,
717 RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
718 gl->fbo_feedback_texture, 0);
719
720 status = gl2_check_fb_status(RARCH_GL_FRAMEBUFFER);
721 if (status != RARCH_GL_FRAMEBUFFER_COMPLETE)
722 goto error;
723
724 /* Make sure the feedback textures are cleared
725 * so we don't feedback noise. */
726 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
727 glClear(GL_COLOR_BUFFER_BIT);
728 }
729
730 return true;
731
732 error:
733 gl2_delete_fb(chain->fbo_pass, chain->fbo);
734 if (gl->fbo_feedback)
735 gl2_delete_fb(1, &gl->fbo_feedback);
736 RARCH_ERR("[GL]: Failed to set up frame buffer objects. Multi-pass shading will not work.\n");
737 return false;
738 }
739
gl2_wrap_type_to_enum(enum gfx_wrap_type type)740 static unsigned gl2_wrap_type_to_enum(enum gfx_wrap_type type)
741 {
742 switch (type)
743 {
744 #ifndef HAVE_OPENGLES
745 case RARCH_WRAP_BORDER: /* GL_CLAMP_TO_BORDER: Available since GL 1.3 */
746 return GL_CLAMP_TO_BORDER;
747 #else
748 case RARCH_WRAP_BORDER:
749 #endif
750 case RARCH_WRAP_EDGE:
751 return GL_CLAMP_TO_EDGE;
752 case RARCH_WRAP_REPEAT:
753 return GL_REPEAT;
754 case RARCH_WRAP_MIRRORED_REPEAT:
755 return GL_MIRRORED_REPEAT;
756 default:
757 break;
758 }
759
760 return 0;
761 }
762
gl2_min_filter_to_mag(GLenum type)763 static GLenum gl2_min_filter_to_mag(GLenum type)
764 {
765 switch (type)
766 {
767 case GL_LINEAR_MIPMAP_LINEAR:
768 return GL_LINEAR;
769 case GL_NEAREST_MIPMAP_NEAREST:
770 return GL_NEAREST;
771 default:
772 break;
773 }
774
775 return type;
776 }
777
gl2_create_fbo_texture(gl_t * gl,gl2_renderchain_data_t * chain,unsigned i,GLuint texture)778 static void gl2_create_fbo_texture(gl_t *gl,
779 gl2_renderchain_data_t *chain,
780 unsigned i, GLuint texture)
781 {
782 GLenum mag_filter, wrap_enum;
783 enum gfx_wrap_type wrap_type;
784 bool fp_fbo = false;
785 bool smooth = false;
786 settings_t *settings = config_get_ptr();
787 bool video_smooth = settings->bools.video_smooth;
788 #if HAVE_ODROIDGO2
789 bool video_ctx_scaling = settings->bools.video_ctx_scaling;
790 if (video_ctx_scaling)
791 video_smooth = false;
792 #endif
793 #ifndef HAVE_OPENGLES
794 bool force_srgb_disable = settings->bools.video_force_srgb_disable;
795 #endif
796 GLuint base_filt = video_smooth ? GL_LINEAR : GL_NEAREST;
797 GLuint base_mip_filt = video_smooth ?
798 GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST;
799 unsigned mip_level = i + 2;
800 bool mipmapped = gl->shader->mipmap_input(gl->shader_data, mip_level);
801 GLenum min_filter = mipmapped ? base_mip_filt : base_filt;
802
803 if (gl->shader->filter_type(gl->shader_data,
804 i + 2, &smooth))
805 {
806 min_filter = mipmapped ? (smooth ?
807 GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST)
808 : (smooth ? GL_LINEAR : GL_NEAREST);
809 }
810
811 mag_filter = gl2_min_filter_to_mag(min_filter);
812
813 wrap_type = gl->shader->wrap_type(gl->shader_data, i + 2);
814
815 wrap_enum = gl2_wrap_type_to_enum(wrap_type);
816
817 GL_BIND_TEXTURE(texture, wrap_enum, mag_filter, min_filter);
818
819 fp_fbo = chain->fbo_scale[i].fp_fbo;
820
821 if (fp_fbo)
822 {
823 if (!chain->has_fp_fbo)
824 RARCH_ERR("[GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.!\n");
825 }
826
827 #if !defined(HAVE_OPENGLES2)
828 if (fp_fbo && chain->has_fp_fbo)
829 {
830 RARCH_LOG("[GL]: FBO pass #%d is floating-point.\n", i);
831 gl2_load_texture_image(GL_TEXTURE_2D, 0, GL_RGBA32F,
832 gl->fbo_rect[i].width, gl->fbo_rect[i].height,
833 0, GL_RGBA, GL_FLOAT, NULL);
834 }
835 else
836 #endif
837 {
838 #ifndef HAVE_OPENGLES
839 bool srgb_fbo = chain->fbo_scale[i].srgb_fbo;
840
841 if (!fp_fbo && srgb_fbo)
842 {
843 if (!chain->has_srgb_fbo)
844 RARCH_ERR("[GL]: sRGB FBO was requested, but it is not supported. Falling back to UNORM. Result may have banding!\n");
845 }
846
847 if (force_srgb_disable)
848 srgb_fbo = false;
849
850 if (srgb_fbo && chain->has_srgb_fbo)
851 {
852 RARCH_LOG("[GL]: FBO pass #%d is sRGB.\n", i);
853 #ifdef HAVE_OPENGLES2
854 /* EXT defines are same as core GLES3 defines,
855 * but GLES3 variant requires different arguments. */
856 glTexImage2D(GL_TEXTURE_2D,
857 0, GL_SRGB_ALPHA_EXT,
858 gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
859 chain->has_srgb_fbo_gles3 ? GL_RGBA : GL_SRGB_ALPHA_EXT,
860 GL_UNSIGNED_BYTE, NULL);
861 #else
862 gl2_load_texture_image(GL_TEXTURE_2D,
863 0, GL_SRGB8_ALPHA8,
864 gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
865 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
866 #endif
867 }
868 else
869 #endif
870 {
871 #if defined(HAVE_OPENGLES2)
872 glTexImage2D(GL_TEXTURE_2D,
873 0, GL_RGBA,
874 gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
875 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
876 #elif defined(HAVE_PSGL)
877 glTexImage2D(GL_TEXTURE_2D,
878 0, GL_ARGB_SCE,
879 gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
880 GL_ARGB_SCE, GL_UNSIGNED_BYTE, NULL);
881 #else
882 /* Avoid potential performance
883 * reductions on particular platforms. */
884 gl2_load_texture_image(GL_TEXTURE_2D,
885 0, RARCH_GL_INTERNAL_FORMAT32,
886 gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
887 RARCH_GL_TEXTURE_TYPE32, RARCH_GL_FORMAT32, NULL);
888 #endif
889 }
890 }
891 }
892
gl2_create_fbo_textures(gl_t * gl,gl2_renderchain_data_t * chain)893 static void gl2_create_fbo_textures(gl_t *gl,
894 gl2_renderchain_data_t *chain)
895 {
896 int i;
897
898 glGenTextures(chain->fbo_pass, chain->fbo_texture);
899
900 for (i = 0; i < chain->fbo_pass; i++)
901 gl2_create_fbo_texture(gl,
902 (gl2_renderchain_data_t*)gl->renderchain_data,
903 i, chain->fbo_texture[i]);
904
905 if (gl->fbo_feedback_enable)
906 {
907 glGenTextures(1, &gl->fbo_feedback_texture);
908 gl2_create_fbo_texture(gl,
909 (gl2_renderchain_data_t*)gl->renderchain_data,
910 gl->fbo_feedback_pass, gl->fbo_feedback_texture);
911 }
912
913 glBindTexture(GL_TEXTURE_2D, 0);
914 }
915
916 /* Compute FBO geometry.
917 * When width/height changes or window sizes change,
918 * we have to recalculate geometry of our FBO. */
919
gl2_renderchain_recompute_pass_sizes(gl_t * gl,gl2_renderchain_data_t * chain,unsigned width,unsigned height,unsigned vp_width,unsigned vp_height)920 static void gl2_renderchain_recompute_pass_sizes(
921 gl_t *gl,
922 gl2_renderchain_data_t *chain,
923 unsigned width, unsigned height,
924 unsigned vp_width, unsigned vp_height)
925 {
926 unsigned i;
927 bool size_modified = false;
928 GLint max_size = 0;
929 unsigned last_width = width;
930 unsigned last_height = height;
931 unsigned last_max_width = gl->tex_w;
932 unsigned last_max_height = gl->tex_h;
933
934 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
935
936 /* Calculate viewports for FBOs. */
937 for (i = 0; i < (unsigned)chain->fbo_pass; i++)
938 {
939 struct video_fbo_rect *fbo_rect = &gl->fbo_rect[i];
940 struct gfx_fbo_scale *fbo_scale = &chain->fbo_scale[i];
941
942 switch (fbo_scale->type_x)
943 {
944 case RARCH_SCALE_INPUT:
945 fbo_rect->img_width = fbo_scale->scale_x * last_width;
946 fbo_rect->max_img_width = last_max_width * fbo_scale->scale_x;
947 break;
948
949 case RARCH_SCALE_ABSOLUTE:
950 fbo_rect->img_width = fbo_rect->max_img_width =
951 fbo_scale->abs_x;
952 break;
953
954 case RARCH_SCALE_VIEWPORT:
955 if (gl->rotation % 180 == 90)
956 {
957 fbo_rect->img_width = fbo_rect->max_img_width =
958 fbo_scale->scale_x * vp_height;
959 } else {
960 fbo_rect->img_width = fbo_rect->max_img_width =
961 fbo_scale->scale_x * vp_width;
962 }
963 break;
964 }
965
966 switch (fbo_scale->type_y)
967 {
968 case RARCH_SCALE_INPUT:
969 fbo_rect->img_height = last_height * fbo_scale->scale_y;
970 fbo_rect->max_img_height = last_max_height * fbo_scale->scale_y;
971 break;
972
973 case RARCH_SCALE_ABSOLUTE:
974 fbo_rect->img_height = fbo_scale->abs_y;
975 fbo_rect->max_img_height = fbo_scale->abs_y;
976 break;
977
978 case RARCH_SCALE_VIEWPORT:
979 if (gl->rotation % 180 == 90)
980 {
981 fbo_rect->img_height = fbo_rect->max_img_height =
982 fbo_scale->scale_y * vp_width;
983 } else {
984 fbo_rect->img_height = fbo_rect->max_img_height =
985 fbo_scale->scale_y * vp_height;
986 }
987 break;
988 }
989
990 if (fbo_rect->img_width > (unsigned)max_size)
991 {
992 size_modified = true;
993 fbo_rect->img_width = max_size;
994 }
995
996 if (fbo_rect->img_height > (unsigned)max_size)
997 {
998 size_modified = true;
999 fbo_rect->img_height = max_size;
1000 }
1001
1002 if (fbo_rect->max_img_width > (unsigned)max_size)
1003 {
1004 size_modified = true;
1005 fbo_rect->max_img_width = max_size;
1006 }
1007
1008 if (fbo_rect->max_img_height > (unsigned)max_size)
1009 {
1010 size_modified = true;
1011 fbo_rect->max_img_height = max_size;
1012 }
1013
1014 if (size_modified)
1015 RARCH_WARN("[GL]: FBO textures exceeded maximum size of GPU (%dx%d). Resizing to fit.\n", max_size, max_size);
1016
1017 last_width = fbo_rect->img_width;
1018 last_height = fbo_rect->img_height;
1019 last_max_width = fbo_rect->max_img_width;
1020 last_max_height = fbo_rect->max_img_height;
1021 }
1022 }
1023
gl2_renderchain_start_render(gl_t * gl,gl2_renderchain_data_t * chain)1024 static void gl2_renderchain_start_render(
1025 gl_t *gl,
1026 gl2_renderchain_data_t *chain)
1027 {
1028 /* Used when rendering to an FBO.
1029 * Texture coords have to be aligned
1030 * with vertex coordinates. */
1031 static const GLfloat fbo_vertexes[] = {
1032 0, 0,
1033 1, 0,
1034 0, 1,
1035 1, 1
1036 };
1037 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
1038 gl2_bind_fb(chain->fbo[0]);
1039
1040 gl2_set_viewport(gl,
1041 gl->fbo_rect[0].img_width,
1042 gl->fbo_rect[0].img_height, true, false);
1043
1044 /* Need to preserve the "flipped" state when in FBO
1045 * as well to have consistent texture coordinates.
1046 *
1047 * We will "flip" it in place on last pass. */
1048 gl->coords.vertex = fbo_vertexes;
1049
1050 #if defined(GL_FRAMEBUFFER_SRGB) && !defined(HAVE_OPENGLES)
1051 if (chain->has_srgb_fbo)
1052 glEnable(GL_FRAMEBUFFER_SRGB);
1053 #endif
1054 }
1055
1056 /* Set up render to texture. */
gl2_renderchain_init(gl_t * gl,gl2_renderchain_data_t * chain,unsigned fbo_width,unsigned fbo_height)1057 static void gl2_renderchain_init(
1058 gl_t *gl,
1059 gl2_renderchain_data_t *chain,
1060 unsigned fbo_width, unsigned fbo_height)
1061 {
1062 int i;
1063 unsigned width, height;
1064 video_shader_ctx_scale_t scaler;
1065 video_shader_ctx_info_t shader_info;
1066 struct gfx_fbo_scale scale, scale_last;
1067
1068 if (!gl2_shader_info(gl, &shader_info))
1069 return;
1070
1071 if (!gl || shader_info.num == 0)
1072 return;
1073
1074 width = gl->video_width;
1075 height = gl->video_height;
1076
1077 scaler.idx = 1;
1078 scaler.scale = &scale;
1079
1080 gl2_shader_scale(gl, &scaler);
1081
1082 scaler.idx = shader_info.num;
1083 scaler.scale = &scale_last;
1084
1085 gl2_shader_scale(gl, &scaler);
1086
1087 /* we always want FBO to be at least initialized on startup for consoles */
1088 if (shader_info.num == 1 && !scale.valid)
1089 return;
1090
1091 if (!gl->has_fbo)
1092 {
1093 RARCH_ERR("[GL]: Failed to locate FBO functions. Won't be able to use render-to-texture.\n");
1094 return;
1095 }
1096
1097 chain->fbo_pass = shader_info.num - 1;
1098 if (scale_last.valid)
1099 chain->fbo_pass++;
1100
1101 if (!scale.valid)
1102 {
1103 scale.scale_x = 1.0f;
1104 scale.scale_y = 1.0f;
1105 scale.type_x = scale.type_y = RARCH_SCALE_INPUT;
1106 scale.valid = true;
1107 }
1108
1109 chain->fbo_scale[0] = scale;
1110
1111 for (i = 1; i < chain->fbo_pass; i++)
1112 {
1113 scaler.idx = i + 1;
1114 scaler.scale = &chain->fbo_scale[i];
1115
1116 gl2_shader_scale(gl, &scaler);
1117
1118 if (!chain->fbo_scale[i].valid)
1119 {
1120 chain->fbo_scale[i].scale_x = chain->fbo_scale[i].scale_y = 1.0f;
1121 chain->fbo_scale[i].type_x = chain->fbo_scale[i].type_y =
1122 RARCH_SCALE_INPUT;
1123 chain->fbo_scale[i].valid = true;
1124 }
1125 }
1126
1127 gl2_renderchain_recompute_pass_sizes(gl,
1128 chain, fbo_width, fbo_height, width, height);
1129
1130 for (i = 0; i < chain->fbo_pass; i++)
1131 {
1132 gl->fbo_rect[i].width = next_pow2(gl->fbo_rect[i].img_width);
1133 gl->fbo_rect[i].height = next_pow2(gl->fbo_rect[i].img_height);
1134 RARCH_LOG("[GL]: Creating FBO %d @ %ux%u\n", i,
1135 gl->fbo_rect[i].width, gl->fbo_rect[i].height);
1136 }
1137
1138 gl->fbo_feedback_enable = gl->shader->get_feedback_pass(gl->shader_data,
1139 &gl->fbo_feedback_pass);
1140
1141 if (gl->fbo_feedback_enable && gl->fbo_feedback_pass
1142 < (unsigned)chain->fbo_pass)
1143 {
1144 RARCH_LOG("[GL]: Creating feedback FBO %d @ %ux%u\n", i,
1145 gl->fbo_rect[gl->fbo_feedback_pass].width,
1146 gl->fbo_rect[gl->fbo_feedback_pass].height);
1147 }
1148 else if (gl->fbo_feedback_enable)
1149 {
1150 RARCH_WARN("[GL]: Tried to create feedback FBO of pass #%u, but there are only %d FBO passes. Will use input texture as feedback texture.\n",
1151 gl->fbo_feedback_pass, chain->fbo_pass);
1152 gl->fbo_feedback_enable = false;
1153 }
1154
1155 gl2_create_fbo_textures(gl, chain);
1156 if (!gl || !gl2_create_fbo_targets(gl, chain))
1157 {
1158 glDeleteTextures(chain->fbo_pass, chain->fbo_texture);
1159 RARCH_ERR("[GL]: Failed to create FBO targets. Will continue without FBO.\n");
1160 return;
1161 }
1162
1163 gl->fbo_inited = true;
1164 }
1165
gl2_renderchain_init_hw_render(gl_t * gl,gl2_renderchain_data_t * chain,unsigned width,unsigned height)1166 static bool gl2_renderchain_init_hw_render(
1167 gl_t *gl,
1168 gl2_renderchain_data_t *chain,
1169 unsigned width, unsigned height)
1170 {
1171 GLenum status;
1172 unsigned i;
1173 bool depth = false;
1174 bool stencil = false;
1175 GLint max_fbo_size = 0;
1176 GLint max_renderbuffer_size = 0;
1177 struct retro_hw_render_callback *hwr =
1178 video_driver_get_hw_context();
1179
1180 /* We can only share texture objects through contexts.
1181 * FBOs are "abstract" objects and are not shared. */
1182 gl2_context_bind_hw_render(gl, true);
1183
1184 RARCH_LOG("[GL]: Initializing HW render (%u x %u).\n", width, height);
1185 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_fbo_size);
1186 glGetIntegerv(RARCH_GL_MAX_RENDERBUFFER_SIZE, &max_renderbuffer_size);
1187 RARCH_LOG("[GL]: Max texture size: %d px, renderbuffer size: %d px.\n",
1188 max_fbo_size, max_renderbuffer_size);
1189
1190 if (!gl->has_fbo)
1191 return false;
1192
1193 RARCH_LOG("[GL]: Supports FBO (render-to-texture).\n");
1194
1195 glBindTexture(GL_TEXTURE_2D, 0);
1196 gl2_gen_fb(gl->textures, gl->hw_render_fbo);
1197
1198 depth = hwr->depth;
1199 stencil = hwr->stencil;
1200
1201 if (depth)
1202 {
1203 gl2_gen_rb(gl->textures, chain->hw_render_depth);
1204 chain->hw_render_depth_init = true;
1205 }
1206
1207 for (i = 0; i < gl->textures; i++)
1208 {
1209 gl2_bind_fb(gl->hw_render_fbo[i]);
1210 gl2_fb_texture_2d(RARCH_GL_FRAMEBUFFER,
1211 RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl->texture[i], 0);
1212
1213 if (depth)
1214 {
1215 gl2_bind_rb(RARCH_GL_RENDERBUFFER, chain->hw_render_depth[i]);
1216 gl2_rb_storage(RARCH_GL_RENDERBUFFER,
1217 stencil ? RARCH_GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT16,
1218 width, height);
1219 gl2_bind_rb(RARCH_GL_RENDERBUFFER, 0);
1220
1221 if (stencil)
1222 {
1223 #if defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES1) || ((defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))))
1224 /* GLES2 is a bit weird, as always.
1225 * There's no GL_DEPTH_STENCIL_ATTACHMENT like in desktop GL. */
1226 gl2_fb_rb(RARCH_GL_FRAMEBUFFER,
1227 RARCH_GL_DEPTH_ATTACHMENT,
1228 RARCH_GL_RENDERBUFFER,
1229 chain->hw_render_depth[i]);
1230 gl2_fb_rb(RARCH_GL_FRAMEBUFFER,
1231 RARCH_GL_STENCIL_ATTACHMENT,
1232 RARCH_GL_RENDERBUFFER,
1233 chain->hw_render_depth[i]);
1234 #else
1235 /* We use ARB FBO extensions, no need to check. */
1236 gl2_fb_rb(RARCH_GL_FRAMEBUFFER,
1237 GL_DEPTH_STENCIL_ATTACHMENT,
1238 RARCH_GL_RENDERBUFFER,
1239 chain->hw_render_depth[i]);
1240 #endif
1241 }
1242 else
1243 {
1244 gl2_fb_rb(RARCH_GL_FRAMEBUFFER,
1245 RARCH_GL_DEPTH_ATTACHMENT,
1246 RARCH_GL_RENDERBUFFER,
1247 chain->hw_render_depth[i]);
1248 }
1249 }
1250
1251 status = gl2_check_fb_status(RARCH_GL_FRAMEBUFFER);
1252 if (status != RARCH_GL_FRAMEBUFFER_COMPLETE)
1253 {
1254 RARCH_ERR("[GL]: Failed to create HW render FBO #%u, error: 0x%04x.\n",
1255 i, status);
1256 return false;
1257 }
1258 }
1259
1260 gl2_renderchain_bind_backbuffer();
1261 gl->hw_render_fbo_init = true;
1262
1263 gl2_context_bind_hw_render(gl, false);
1264 return true;
1265 }
1266
gl2_renderchain_bind_prev_texture(gl_t * gl,gl2_renderchain_data_t * chain,const struct video_tex_info * tex_info)1267 static void gl2_renderchain_bind_prev_texture(
1268 gl_t *gl,
1269 gl2_renderchain_data_t *chain,
1270 const struct video_tex_info *tex_info)
1271 {
1272 memmove(gl->prev_info + 1, gl->prev_info,
1273 sizeof(*tex_info) * (gl->textures - 1));
1274 memcpy(&gl->prev_info[0], tex_info,
1275 sizeof(*tex_info));
1276
1277 /* Implement feedback by swapping out FBO/textures
1278 * for FBO pass #N and feedbacks. */
1279 if (gl->fbo_feedback_enable)
1280 {
1281 GLuint tmp_fbo = gl->fbo_feedback;
1282 GLuint tmp_tex = gl->fbo_feedback_texture;
1283 gl->fbo_feedback = chain->fbo[gl->fbo_feedback_pass];
1284 gl->fbo_feedback_texture = chain->fbo_texture[gl->fbo_feedback_pass];
1285 chain->fbo[gl->fbo_feedback_pass] = tmp_fbo;
1286 chain->fbo_texture[gl->fbo_feedback_pass] = tmp_tex;
1287 }
1288 }
1289
gl2_renderchain_read_viewport(gl_t * gl,uint8_t * buffer,bool is_idle)1290 static bool gl2_renderchain_read_viewport(
1291 gl_t *gl,
1292 uint8_t *buffer, bool is_idle)
1293 {
1294 unsigned num_pixels = 0;
1295
1296 gl2_context_bind_hw_render(gl, false);
1297
1298 num_pixels = gl->vp.width * gl->vp.height;
1299
1300 #ifdef HAVE_GL_ASYNC_READBACK
1301 if (gl->pbo_readback_enable)
1302 {
1303 const uint8_t *ptr = NULL;
1304
1305 /* Don't readback if we're in menu mode.
1306 * We haven't buffered up enough frames yet, come back later. */
1307 if (!gl->pbo_readback_valid[gl->pbo_readback_index])
1308 goto error;
1309
1310 gl->pbo_readback_valid[gl->pbo_readback_index] = false;
1311 glBindBuffer(GL_PIXEL_PACK_BUFFER,
1312 gl->pbo_readback[gl->pbo_readback_index]);
1313
1314 #ifdef HAVE_OPENGLES3
1315 /* Slower path, but should work on all implementations at least. */
1316 ptr = (const uint8_t*)glMapBufferRange(GL_PIXEL_PACK_BUFFER,
1317 0, num_pixels * sizeof(uint32_t), GL_MAP_READ_BIT);
1318
1319 if (ptr)
1320 {
1321 unsigned y;
1322 for (y = 0; y < gl->vp.height; y++)
1323 {
1324 video_frame_convert_rgba_to_bgr(
1325 (const void*)ptr,
1326 buffer,
1327 gl->vp.width);
1328 }
1329 }
1330 #else
1331 ptr = (const uint8_t*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
1332 if (ptr)
1333 {
1334 struct scaler_ctx *ctx = &gl->pbo_readback_scaler;
1335 scaler_ctx_scale_direct(ctx, buffer, ptr);
1336 }
1337 #endif
1338
1339 if (!ptr)
1340 {
1341 RARCH_ERR("[GL]: Failed to map pixel unpack buffer.\n");
1342 goto error;
1343 }
1344
1345 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
1346 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1347 }
1348 else
1349 #endif
1350 {
1351 /* Use slow synchronous readbacks. Use this with plain screenshots
1352 as we don't really care about performance in this case. */
1353
1354 /* GLES2 only guarantees GL_RGBA/GL_UNSIGNED_BYTE
1355 * readbacks so do just that.
1356 * GLES2 also doesn't support reading back data
1357 * from front buffer, so render a cached frame
1358 * and have gl_frame() do the readback while it's
1359 * in the back buffer.
1360 *
1361 * Keep codepath similar for GLES and desktop GL.
1362 */
1363 gl->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t));
1364
1365 if (!gl->readback_buffer_screenshot)
1366 goto error;
1367
1368 if (!is_idle)
1369 video_driver_cached_frame();
1370
1371 video_frame_convert_rgba_to_bgr(
1372 (const void*)gl->readback_buffer_screenshot,
1373 buffer,
1374 num_pixels);
1375
1376 free(gl->readback_buffer_screenshot);
1377 gl->readback_buffer_screenshot = NULL;
1378 }
1379
1380 gl2_context_bind_hw_render(gl, true);
1381 return true;
1382
1383 error:
1384 gl2_context_bind_hw_render(gl, true);
1385
1386 return false;
1387 }
1388
1389 #ifdef HAVE_OPENGLES
1390 #define gl2_renderchain_restore_default_state(gl) \
1391 glDisable(GL_DEPTH_TEST); \
1392 glDisable(GL_CULL_FACE); \
1393 glDisable(GL_DITHER)
1394 #else
1395 #define gl2_renderchain_restore_default_state(gl) \
1396 if (!gl->core_context_in_use) \
1397 glEnable(GL_TEXTURE_2D); \
1398 glDisable(GL_DEPTH_TEST); \
1399 glDisable(GL_CULL_FACE); \
1400 glDisable(GL_DITHER)
1401 #endif
1402
gl2_renderchain_copy_frame(gl_t * gl,gl2_renderchain_data_t * chain,bool use_rgba,const void * frame,unsigned width,unsigned height,unsigned pitch)1403 static void gl2_renderchain_copy_frame(
1404 gl_t *gl,
1405 gl2_renderchain_data_t *chain,
1406 bool use_rgba,
1407 const void *frame,
1408 unsigned width, unsigned height, unsigned pitch)
1409 {
1410 #if defined(HAVE_PSGL)
1411 {
1412 unsigned h;
1413 size_t buffer_addr = gl->tex_w * gl->tex_h *
1414 gl->tex_index * gl->base_size;
1415 size_t buffer_stride = gl->tex_w * gl->base_size;
1416 const uint8_t *frame_copy = frame;
1417 size_t frame_copy_size = width * gl->base_size;
1418 uint8_t *buffer = (uint8_t*)glMapBuffer(
1419 GL_TEXTURE_REFERENCE_BUFFER_SCE, GL_READ_WRITE) + buffer_addr;
1420 for (h = 0; h < height; h++, buffer += buffer_stride, frame_copy += pitch)
1421 memcpy(buffer, frame_copy, frame_copy_size);
1422
1423 glUnmapBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE);
1424 }
1425 #elif defined(HAVE_OPENGLES)
1426 #if defined(HAVE_EGL)
1427 if (chain->egl_images)
1428 {
1429 bool new_egl = false;
1430 EGLImageKHR img = 0;
1431
1432 if (gl->ctx_driver->image_buffer_write)
1433 new_egl = gl->ctx_driver->image_buffer_write(
1434 gl->ctx_data,
1435 frame, width, height, pitch,
1436 (gl->base_size == 4),
1437 gl->tex_index,
1438 &img);
1439
1440 if (img == EGL_NO_IMAGE_KHR)
1441 {
1442 RARCH_ERR("[GL]: Failed to create EGL image.\n");
1443 return;
1444 }
1445
1446 if (new_egl)
1447 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)img);
1448 }
1449 else
1450 #endif
1451 {
1452 glPixelStorei(GL_UNPACK_ALIGNMENT,
1453 gl2_get_alignment(width * gl->base_size));
1454
1455 /* Fallback for GLES devices without GL_BGRA_EXT. */
1456 if (gl->base_size == 4 && use_rgba)
1457 {
1458 video_frame_convert_argb8888_to_abgr8888(
1459 &gl->scaler,
1460 gl->conv_buffer,
1461 frame, width, height, pitch);
1462 glTexSubImage2D(GL_TEXTURE_2D,
1463 0, 0, 0, width, height, gl->texture_type,
1464 gl->texture_fmt, gl->conv_buffer);
1465 }
1466 else if (gl->support_unpack_row_length)
1467 {
1468 glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size);
1469 glTexSubImage2D(GL_TEXTURE_2D,
1470 0, 0, 0, width, height, gl->texture_type,
1471 gl->texture_fmt, frame);
1472
1473 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1474 }
1475 else
1476 {
1477 /* No GL_UNPACK_ROW_LENGTH. */
1478
1479 const GLvoid *data_buf = frame;
1480 unsigned pitch_width = pitch / gl->base_size;
1481
1482 if (width != pitch_width)
1483 {
1484 /* Slow path - conv_buffer is preallocated
1485 * just in case we hit this path. */
1486
1487 unsigned h;
1488 const unsigned line_bytes = width * gl->base_size;
1489 uint8_t *dst = (uint8_t*)gl->conv_buffer;
1490 const uint8_t *src = (const uint8_t*)frame;
1491
1492 for (h = 0; h < height; h++, src += pitch, dst += line_bytes)
1493 memcpy(dst, src, line_bytes);
1494
1495 data_buf = gl->conv_buffer;
1496 }
1497
1498 glTexSubImage2D(GL_TEXTURE_2D,
1499 0, 0, 0, width, height, gl->texture_type,
1500 gl->texture_fmt, data_buf);
1501 }
1502 }
1503 #else
1504 {
1505 const GLvoid *data_buf = frame;
1506 glPixelStorei(GL_UNPACK_ALIGNMENT, gl2_get_alignment(pitch));
1507
1508 if (gl->base_size == 2 && !gl->have_es2_compat)
1509 {
1510 /* Convert to 32-bit textures on desktop GL.
1511 *
1512 * It is *much* faster (order of magnitude on my setup)
1513 * to use a custom SIMD-optimized conversion routine
1514 * than letting GL do it. */
1515 video_frame_convert_rgb16_to_rgb32(
1516 &gl->scaler,
1517 gl->conv_buffer,
1518 frame,
1519 width,
1520 height,
1521 pitch);
1522 data_buf = gl->conv_buffer;
1523 }
1524 else
1525 glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size);
1526
1527 glTexSubImage2D(GL_TEXTURE_2D,
1528 0, 0, 0, width, height, gl->texture_type,
1529 gl->texture_fmt, data_buf);
1530
1531 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1532 }
1533 #endif
1534 }
1535
1536 #if !defined(HAVE_OPENGLES2) && !defined(HAVE_PSGL)
1537 #define gl2_renderchain_bind_pbo(idx) glBindBuffer(GL_PIXEL_PACK_BUFFER, (GLuint)idx)
1538 #define gl2_renderchain_unbind_pbo() glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)
1539 #define gl2_renderchain_init_pbo(size, data) glBufferData(GL_PIXEL_PACK_BUFFER, size, (const GLvoid*)data, GL_STREAM_READ)
1540 #else
1541 #define gl2_renderchain_bind_pbo(idx)
1542 #define gl2_renderchain_unbind_pbo()
1543 #define gl2_renderchain_init_pbo(size, data)
1544 #endif
1545
gl2_renderchain_readback(gl_t * gl,void * chain_data,unsigned alignment,unsigned fmt,unsigned type,void * src)1546 static void gl2_renderchain_readback(
1547 gl_t *gl,
1548 void *chain_data,
1549 unsigned alignment,
1550 unsigned fmt, unsigned type,
1551 void *src)
1552 {
1553 glPixelStorei(GL_PACK_ALIGNMENT, alignment);
1554 #ifndef HAVE_OPENGLES
1555 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1556 glReadBuffer(GL_BACK);
1557 #endif
1558
1559 glReadPixels(gl->vp.x, gl->vp.y,
1560 gl->vp.width, gl->vp.height,
1561 (GLenum)fmt, (GLenum)type, (GLvoid*)src);
1562 }
1563
gl2_renderchain_fence_iterate(void * data,gl2_renderchain_data_t * chain,unsigned hard_sync_frames)1564 static void gl2_renderchain_fence_iterate(
1565 void *data,
1566 gl2_renderchain_data_t *chain,
1567 unsigned hard_sync_frames)
1568 {
1569 #ifndef HAVE_OPENGLES
1570 #ifdef HAVE_GL_SYNC
1571 chain->fences[chain->fence_count++] =
1572 glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1573
1574 while (chain->fence_count > hard_sync_frames)
1575 {
1576 glClientWaitSync(chain->fences[0],
1577 GL_SYNC_FLUSH_COMMANDS_BIT, 1000000000);
1578 glDeleteSync(chain->fences[0]);
1579
1580 chain->fence_count--;
1581 memmove(chain->fences, chain->fences + 1,
1582 chain->fence_count * sizeof(void*));
1583 }
1584 #endif
1585 #endif
1586 }
1587
gl2_renderchain_fence_free(void * data,gl2_renderchain_data_t * chain)1588 static void gl2_renderchain_fence_free(void *data,
1589 gl2_renderchain_data_t *chain)
1590 {
1591 #ifndef HAVE_OPENGLES
1592 #ifdef HAVE_GL_SYNC
1593 unsigned i;
1594
1595 for (i = 0; i < chain->fence_count; i++)
1596 {
1597 glClientWaitSync(chain->fences[i],
1598 GL_SYNC_FLUSH_COMMANDS_BIT, 1000000000);
1599 glDeleteSync(chain->fences[i]);
1600 }
1601 chain->fence_count = 0;
1602 #endif
1603 #endif
1604 }
1605
gl2_renderchain_init_texture_reference(gl_t * gl,gl2_renderchain_data_t * chain,unsigned i,unsigned internal_fmt,unsigned texture_fmt,unsigned texture_type)1606 static void gl2_renderchain_init_texture_reference(
1607 gl_t *gl,
1608 gl2_renderchain_data_t *chain,
1609 unsigned i,
1610 unsigned internal_fmt, unsigned texture_fmt,
1611 unsigned texture_type)
1612 {
1613 #ifdef HAVE_PSGL
1614 glTextureReferenceSCE(GL_TEXTURE_2D, 1,
1615 gl->tex_w, gl->tex_h, 0,
1616 (GLenum)internal_fmt,
1617 gl->tex_w * gl->base_size,
1618 gl->tex_w * gl->tex_h * i * gl->base_size);
1619 #else
1620 if (chain->egl_images)
1621 return;
1622
1623 gl2_load_texture_image(GL_TEXTURE_2D,
1624 0,
1625 (GLenum)internal_fmt,
1626 gl->tex_w, gl->tex_h, 0,
1627 (GLenum)texture_type,
1628 (GLenum)texture_fmt,
1629 gl->empty_buf ? gl->empty_buf : NULL);
1630 #endif
1631 }
1632
gl2_renderchain_resolve_extensions(gl_t * gl,gl2_renderchain_data_t * chain,const char * context_ident,const video_info_t * video)1633 static void gl2_renderchain_resolve_extensions(gl_t *gl,
1634 gl2_renderchain_data_t *chain,
1635 const char *context_ident,
1636 const video_info_t *video)
1637 {
1638 settings_t *settings = config_get_ptr();
1639 bool force_srgb_disable = settings->bools.video_force_srgb_disable;
1640
1641 if (!chain)
1642 return;
1643
1644 chain->has_srgb_fbo = false;
1645 chain->has_fp_fbo = gl_check_capability(GL_CAPS_FP_FBO);
1646 /* GLES3 has unpack_subimage and sRGB in core. */
1647 chain->has_srgb_fbo_gles3 = gl_check_capability(GL_CAPS_SRGB_FBO_ES3);
1648
1649 if (!force_srgb_disable)
1650 chain->has_srgb_fbo = gl_check_capability(GL_CAPS_SRGB_FBO);
1651
1652 /* Use regular textures if we use HW render. */
1653 chain->egl_images = !gl->hw_render_use
1654 && gl_check_capability(GL_CAPS_EGLIMAGE)
1655 && gl->ctx_driver->image_buffer_init
1656 && gl->ctx_driver->image_buffer_init(gl->ctx_data, video);
1657 }
1658
gl_load_texture_data(GLuint id,enum gfx_wrap_type wrap_type,enum texture_filter_type filter_type,unsigned alignment,unsigned width,unsigned height,const void * frame,unsigned base_size)1659 static void gl_load_texture_data(
1660 GLuint id,
1661 enum gfx_wrap_type wrap_type,
1662 enum texture_filter_type filter_type,
1663 unsigned alignment,
1664 unsigned width, unsigned height,
1665 const void *frame, unsigned base_size)
1666 {
1667 GLint mag_filter, min_filter;
1668 bool want_mipmap = false;
1669 bool use_rgba = video_driver_supports_rgba();
1670 bool rgb32 = (base_size == (sizeof(uint32_t)));
1671 GLenum wrap = gl2_wrap_type_to_enum(wrap_type);
1672 bool have_mipmap = gl_check_capability(GL_CAPS_MIPMAP);
1673
1674 if (!have_mipmap)
1675 {
1676 /* Assume no mipmapping support. */
1677 switch (filter_type)
1678 {
1679 case TEXTURE_FILTER_MIPMAP_LINEAR:
1680 filter_type = TEXTURE_FILTER_LINEAR;
1681 break;
1682 case TEXTURE_FILTER_MIPMAP_NEAREST:
1683 filter_type = TEXTURE_FILTER_NEAREST;
1684 break;
1685 default:
1686 break;
1687 }
1688 }
1689
1690 switch (filter_type)
1691 {
1692 case TEXTURE_FILTER_MIPMAP_LINEAR:
1693 min_filter = GL_LINEAR_MIPMAP_NEAREST;
1694 mag_filter = GL_LINEAR;
1695 want_mipmap = true;
1696 break;
1697 case TEXTURE_FILTER_MIPMAP_NEAREST:
1698 min_filter = GL_NEAREST_MIPMAP_NEAREST;
1699 mag_filter = GL_NEAREST;
1700 want_mipmap = true;
1701 break;
1702 case TEXTURE_FILTER_NEAREST:
1703 min_filter = GL_NEAREST;
1704 mag_filter = GL_NEAREST;
1705 break;
1706 case TEXTURE_FILTER_LINEAR:
1707 default:
1708 min_filter = GL_LINEAR;
1709 mag_filter = GL_LINEAR;
1710 break;
1711 }
1712
1713 GL_BIND_TEXTURE(id, wrap, mag_filter, min_filter);
1714
1715 glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
1716 glTexImage2D(GL_TEXTURE_2D,
1717 0,
1718 (use_rgba || !rgb32) ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
1719 width, height, 0,
1720 (use_rgba || !rgb32) ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
1721 (rgb32) ? RARCH_GL_FORMAT32 : GL_UNSIGNED_SHORT_4_4_4_4, frame);
1722
1723 if (want_mipmap && have_mipmap)
1724 glGenerateMipmap(GL_TEXTURE_2D);
1725 }
1726
gl2_add_lut(const char * lut_path,bool lut_mipmap,unsigned lut_filter,enum gfx_wrap_type lut_wrap_type,unsigned i,GLuint * textures_lut)1727 static bool gl2_add_lut(
1728 const char *lut_path,
1729 bool lut_mipmap,
1730 unsigned lut_filter,
1731 enum gfx_wrap_type lut_wrap_type,
1732 unsigned i, GLuint *textures_lut)
1733 {
1734 struct texture_image img;
1735 enum texture_filter_type filter_type = TEXTURE_FILTER_LINEAR;
1736
1737 img.width = 0;
1738 img.height = 0;
1739 img.pixels = NULL;
1740 img.supports_rgba = video_driver_supports_rgba();
1741
1742 if (!image_texture_load(&img, lut_path))
1743 {
1744 RARCH_ERR("[GL]: Failed to load texture image from: \"%s\"\n",
1745 lut_path);
1746 return false;
1747 }
1748
1749 RARCH_LOG("[GL]: Loaded texture image from: \"%s\" ...\n",
1750 lut_path);
1751
1752 if (lut_filter == RARCH_FILTER_NEAREST)
1753 filter_type = TEXTURE_FILTER_NEAREST;
1754
1755 if (lut_mipmap)
1756 {
1757 if (filter_type == TEXTURE_FILTER_NEAREST)
1758 filter_type = TEXTURE_FILTER_MIPMAP_NEAREST;
1759 else
1760 filter_type = TEXTURE_FILTER_MIPMAP_LINEAR;
1761 }
1762
1763 gl_load_texture_data(
1764 textures_lut[i],
1765 lut_wrap_type,
1766 filter_type, 4,
1767 img.width, img.height,
1768 img.pixels, sizeof(uint32_t));
1769 image_texture_free(&img);
1770
1771 return true;
1772 }
1773
gl_load_luts(const void * shader_data,GLuint * textures_lut)1774 bool gl_load_luts(
1775 const void *shader_data,
1776 GLuint *textures_lut)
1777 {
1778 unsigned i;
1779 const struct video_shader *shader =
1780 (const struct video_shader*)shader_data;
1781 unsigned num_luts = MIN(shader->luts, GFX_MAX_TEXTURES);
1782
1783 if (!shader->luts)
1784 return true;
1785
1786 glGenTextures(num_luts, textures_lut);
1787
1788 for (i = 0; i < num_luts; i++)
1789 {
1790 if (!gl2_add_lut(
1791 shader->lut[i].path,
1792 shader->lut[i].mipmap,
1793 shader->lut[i].filter,
1794 shader->lut[i].wrap,
1795 i, textures_lut))
1796 return false;
1797 }
1798
1799 glBindTexture(GL_TEXTURE_2D, 0);
1800 return true;
1801 }
1802
1803 #ifdef HAVE_OVERLAY
gl2_free_overlay(gl_t * gl)1804 static void gl2_free_overlay(gl_t *gl)
1805 {
1806 glDeleteTextures(gl->overlays, gl->overlay_tex);
1807
1808 free(gl->overlay_tex);
1809 free(gl->overlay_vertex_coord);
1810 free(gl->overlay_tex_coord);
1811 free(gl->overlay_color_coord);
1812 gl->overlay_tex = NULL;
1813 gl->overlay_vertex_coord = NULL;
1814 gl->overlay_tex_coord = NULL;
1815 gl->overlay_color_coord = NULL;
1816 gl->overlays = 0;
1817 }
1818
gl2_overlay_vertex_geom(void * data,unsigned image,float x,float y,float w,float h)1819 static void gl2_overlay_vertex_geom(void *data,
1820 unsigned image,
1821 float x, float y,
1822 float w, float h)
1823 {
1824 GLfloat *vertex = NULL;
1825 gl_t *gl = (gl_t*)data;
1826
1827 if (!gl)
1828 return;
1829
1830 if (image > gl->overlays)
1831 {
1832 RARCH_ERR("[GL]: Invalid overlay id: %u\n", image);
1833 return;
1834 }
1835
1836 vertex = (GLfloat*)&gl->overlay_vertex_coord[image * 8];
1837
1838 /* Flipped, so we preserve top-down semantics. */
1839 y = 1.0f - y;
1840 h = -h;
1841
1842 vertex[0] = x;
1843 vertex[1] = y;
1844 vertex[2] = x + w;
1845 vertex[3] = y;
1846 vertex[4] = x;
1847 vertex[5] = y + h;
1848 vertex[6] = x + w;
1849 vertex[7] = y + h;
1850 }
1851
gl2_overlay_tex_geom(void * data,unsigned image,GLfloat x,GLfloat y,GLfloat w,GLfloat h)1852 static void gl2_overlay_tex_geom(void *data,
1853 unsigned image,
1854 GLfloat x, GLfloat y,
1855 GLfloat w, GLfloat h)
1856 {
1857 GLfloat *tex = NULL;
1858 gl_t *gl = (gl_t*)data;
1859
1860 if (!gl)
1861 return;
1862
1863 tex = (GLfloat*)&gl->overlay_tex_coord[image * 8];
1864
1865 tex[0] = x;
1866 tex[1] = y;
1867 tex[2] = x + w;
1868 tex[3] = y;
1869 tex[4] = x;
1870 tex[5] = y + h;
1871 tex[6] = x + w;
1872 tex[7] = y + h;
1873 }
1874
gl2_render_overlay(gl_t * gl)1875 static void gl2_render_overlay(gl_t *gl)
1876 {
1877 unsigned i;
1878 unsigned width = gl->video_width;
1879 unsigned height = gl->video_height;
1880
1881 glEnable(GL_BLEND);
1882
1883 if (gl->overlay_full_screen)
1884 glViewport(0, 0, width, height);
1885
1886 /* Ensure that we reset the attrib array. */
1887 gl->shader->use(gl, gl->shader_data,
1888 VIDEO_SHADER_STOCK_BLEND, true);
1889
1890 gl->coords.vertex = gl->overlay_vertex_coord;
1891 gl->coords.tex_coord = gl->overlay_tex_coord;
1892 gl->coords.color = gl->overlay_color_coord;
1893 gl->coords.vertices = 4 * gl->overlays;
1894
1895 gl->shader->set_coords(gl->shader_data, &gl->coords);
1896 gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot);
1897
1898 for (i = 0; i < gl->overlays; i++)
1899 {
1900 glBindTexture(GL_TEXTURE_2D, gl->overlay_tex[i]);
1901 glDrawArrays(GL_TRIANGLE_STRIP, 4 * i, 4);
1902 }
1903
1904 glDisable(GL_BLEND);
1905 gl->coords.vertex = gl->vertex_ptr;
1906 gl->coords.tex_coord = gl->tex_info.coord;
1907 gl->coords.color = gl->white_color_ptr;
1908 gl->coords.vertices = 4;
1909 if (gl->overlay_full_screen)
1910 glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
1911 }
1912 #endif
1913
gl2_set_viewport_wrapper(void * data,unsigned viewport_width,unsigned viewport_height,bool force_full,bool allow_rotate)1914 static void gl2_set_viewport_wrapper(void *data, unsigned viewport_width,
1915 unsigned viewport_height, bool force_full, bool allow_rotate)
1916 {
1917 gl_t *gl = (gl_t*)data;
1918 gl2_set_viewport(gl,
1919 viewport_width, viewport_height, force_full, allow_rotate);
1920 }
1921
1922 /* Shaders */
1923
1924 /**
1925 * gl2_get_fallback_shader_type:
1926 * @type : shader type which should be used if possible
1927 *
1928 * Returns a supported fallback shader type in case the given one is not supported.
1929 * For gl2, shader support is completely defined by the context driver shader flags.
1930 *
1931 * gl2_get_fallback_shader_type(RARCH_SHADER_NONE) returns a default shader type.
1932 * if gl2_get_fallback_shader_type(type) != type, type was not supported.
1933 *
1934 * Returns: A supported shader type.
1935 * If RARCH_SHADER_NONE is returned, no shader backend is supported.
1936 **/
gl2_get_fallback_shader_type(enum rarch_shader_type type)1937 static enum rarch_shader_type gl2_get_fallback_shader_type(enum rarch_shader_type type)
1938 {
1939 #if defined(HAVE_GLSL) || defined(HAVE_CG)
1940 unsigned i;
1941
1942 if (type != RARCH_SHADER_CG && type != RARCH_SHADER_GLSL)
1943 {
1944 type = DEFAULT_SHADER_TYPE;
1945
1946 if (type != RARCH_SHADER_CG && type != RARCH_SHADER_GLSL)
1947 type = RARCH_SHADER_GLSL;
1948 }
1949
1950 for (i = 0; i < 2; i++)
1951 {
1952 switch (type)
1953 {
1954 case RARCH_SHADER_CG:
1955 #ifdef HAVE_CG
1956 if (video_shader_is_supported(type))
1957 return type;
1958 #endif
1959 type = RARCH_SHADER_GLSL;
1960 break;
1961
1962 case RARCH_SHADER_GLSL:
1963 #ifdef HAVE_GLSL
1964 if (video_shader_is_supported(type))
1965 return type;
1966 #endif
1967 type = RARCH_SHADER_CG;
1968 break;
1969
1970 default:
1971 return RARCH_SHADER_NONE;
1972 }
1973 }
1974 #endif
1975 return RARCH_SHADER_NONE;
1976 }
1977
gl_shader_driver_set_backend(enum rarch_shader_type type)1978 static const shader_backend_t *gl_shader_driver_set_backend(
1979 enum rarch_shader_type type)
1980 {
1981 enum rarch_shader_type fallback = gl2_get_fallback_shader_type(type);
1982 if (fallback != type)
1983 RARCH_ERR("[Shader driver]: Shader backend %d not supported, falling back to %d.", type, fallback);
1984
1985 switch (fallback)
1986 {
1987 #ifdef HAVE_CG
1988 case RARCH_SHADER_CG:
1989 RARCH_LOG("[Shader driver]: Using Cg shader backend.\n");
1990 return &gl_cg_backend;
1991 #endif
1992 #ifdef HAVE_GLSL
1993 case RARCH_SHADER_GLSL:
1994 RARCH_LOG("[Shader driver]: Using GLSL shader backend.\n");
1995 return &gl_glsl_backend;
1996 #endif
1997 default:
1998 RARCH_LOG("[Shader driver]: No supported shader backend.\n");
1999 return NULL;
2000 }
2001 }
2002
gl_shader_driver_init(video_shader_ctx_init_t * init)2003 static bool gl_shader_driver_init(video_shader_ctx_init_t *init)
2004 {
2005 void *tmp = NULL;
2006 settings_t *settings = config_get_ptr();
2007
2008 if (!init->shader || !init->shader->init)
2009 {
2010 init->shader = gl_shader_driver_set_backend(init->shader_type);
2011
2012 if (!init->shader)
2013 return false;
2014 }
2015
2016 tmp = init->shader->init(init->data, init->path);
2017
2018 if (!tmp)
2019 return false;
2020
2021 if (string_is_equal(settings->arrays.menu_driver, "xmb")
2022 && init->shader->init_menu_shaders)
2023 {
2024 RARCH_LOG("Setting up menu pipeline shaders for XMB ... \n");
2025 init->shader->init_menu_shaders(tmp);
2026 }
2027
2028 init->shader_data = tmp;
2029
2030 return true;
2031 }
2032
gl2_shader_init(gl_t * gl,const gfx_ctx_driver_t * ctx_driver,struct retro_hw_render_callback * hwr)2033 static bool gl2_shader_init(gl_t *gl, const gfx_ctx_driver_t *ctx_driver,
2034 struct retro_hw_render_callback *hwr
2035 )
2036 {
2037 video_shader_ctx_init_t init_data;
2038 bool ret = false;
2039 const char *shader_path = retroarch_get_shader_preset();
2040 enum rarch_shader_type parse_type = video_shader_parse_type(shader_path);
2041 enum rarch_shader_type type;
2042
2043 type = gl2_get_fallback_shader_type(parse_type);
2044
2045 if (type == RARCH_SHADER_NONE)
2046 {
2047 RARCH_ERR("[GL]: Couldn't find any supported shader backend! Continuing without shaders.\n");
2048 return true;
2049 }
2050
2051 if (type != parse_type)
2052 {
2053 if (!string_is_empty(shader_path))
2054 RARCH_WARN("[GL]: Shader preset %s is using unsupported shader type %s, falling back to stock %s.\n",
2055 shader_path, video_shader_type_to_str(parse_type), video_shader_type_to_str(type));
2056
2057 shader_path = NULL;
2058 }
2059
2060 #ifdef HAVE_GLSL
2061 if (type == RARCH_SHADER_GLSL)
2062 gl_glsl_set_context_type(gl->core_context_in_use,
2063 hwr->version_major, hwr->version_minor);
2064 #endif
2065
2066 init_data.gl.core_context_enabled = gl->core_context_in_use;
2067 init_data.shader_type = type;
2068 init_data.shader = NULL;
2069 init_data.shader_data = NULL;
2070 init_data.data = gl;
2071 init_data.path = shader_path;
2072
2073 if (gl_shader_driver_init(&init_data))
2074 {
2075 gl->shader = init_data.shader;
2076 gl->shader_data = init_data.shader_data;
2077 return true;
2078 }
2079
2080 RARCH_ERR("[GL]: Failed to initialize shader, falling back to stock.\n");
2081
2082 init_data.shader = NULL;
2083 init_data.shader_data = NULL;
2084 init_data.path = NULL;
2085
2086 ret = gl_shader_driver_init(&init_data);
2087
2088 gl->shader = init_data.shader;
2089 gl->shader_data = init_data.shader_data;
2090
2091 return ret;
2092 }
2093
gl2_get_current_framebuffer(void * data)2094 static uintptr_t gl2_get_current_framebuffer(void *data)
2095 {
2096 gl_t *gl = (gl_t*)data;
2097 if (!gl || !gl->has_fbo)
2098 return 0;
2099 return gl->hw_render_fbo[(gl->tex_index + 1) % gl->textures];
2100 }
2101
gl2_set_rotation(void * data,unsigned rotation)2102 static void gl2_set_rotation(void *data, unsigned rotation)
2103 {
2104 gl_t *gl = (gl_t*)data;
2105
2106 if (!gl)
2107 return;
2108
2109 gl->rotation = 90 * rotation;
2110 gl2_set_projection(gl, &default_ortho, true);
2111 }
2112
gl2_set_video_mode(void * data,unsigned width,unsigned height,bool fullscreen)2113 static void gl2_set_video_mode(void *data, unsigned width, unsigned height,
2114 bool fullscreen)
2115 {
2116 gl_t *gl = (gl_t*)data;
2117 if (gl->ctx_driver->set_video_mode)
2118 gl->ctx_driver->set_video_mode(gl->ctx_data,
2119 width, height, fullscreen);
2120 }
2121
gl2_update_input_size(gl_t * gl,unsigned width,unsigned height,unsigned pitch,bool clear)2122 static void gl2_update_input_size(gl_t *gl, unsigned width,
2123 unsigned height, unsigned pitch, bool clear)
2124 {
2125 float xamt, yamt;
2126
2127 if ((width != gl->last_width[gl->tex_index] ||
2128 height != gl->last_height[gl->tex_index]) && gl->empty_buf)
2129 {
2130 /* Resolution change. Need to clear out texture. */
2131
2132 gl->last_width[gl->tex_index] = width;
2133 gl->last_height[gl->tex_index] = height;
2134
2135 if (clear)
2136 {
2137 glPixelStorei(GL_UNPACK_ALIGNMENT,
2138 gl2_get_alignment(width * sizeof(uint32_t)));
2139 #if defined(HAVE_PSGL)
2140 glBufferSubData(GL_TEXTURE_REFERENCE_BUFFER_SCE,
2141 gl->tex_w * gl->tex_h * gl->tex_index * gl->base_size,
2142 gl->tex_w * gl->tex_h * gl->base_size,
2143 gl->empty_buf);
2144 #else
2145 glTexSubImage2D(GL_TEXTURE_2D,
2146 0, 0, 0, gl->tex_w, gl->tex_h, gl->texture_type,
2147 gl->texture_fmt, gl->empty_buf);
2148 #endif
2149 }
2150 }
2151 /* We might have used different texture coordinates
2152 * last frame. Edge case if resolution changes very rapidly. */
2153 else if ((width !=
2154 gl->last_width[(gl->tex_index + gl->textures - 1) % gl->textures]) ||
2155 (height !=
2156 gl->last_height[(gl->tex_index + gl->textures - 1) % gl->textures])) { }
2157 else
2158 return;
2159
2160 xamt = (float)width / gl->tex_w;
2161 yamt = (float)height / gl->tex_h;
2162 SET_TEXTURE_COORDS(gl->tex_info.coord, xamt, yamt);
2163 }
2164
gl2_init_textures_data(gl_t * gl)2165 static void gl2_init_textures_data(gl_t *gl)
2166 {
2167 unsigned i;
2168
2169 for (i = 0; i < gl->textures; i++)
2170 {
2171 gl->last_width[i] = gl->tex_w;
2172 gl->last_height[i] = gl->tex_h;
2173 }
2174
2175 for (i = 0; i < gl->textures; i++)
2176 {
2177 gl->prev_info[i].tex = gl->texture[0];
2178 gl->prev_info[i].input_size[0] = gl->tex_w;
2179 gl->prev_info[i].tex_size[0] = gl->tex_w;
2180 gl->prev_info[i].input_size[1] = gl->tex_h;
2181 gl->prev_info[i].tex_size[1] = gl->tex_h;
2182 memcpy(gl->prev_info[i].coord, tex_coords, sizeof(tex_coords));
2183 }
2184 }
2185
gl2_init_textures(gl_t * gl)2186 static void gl2_init_textures(gl_t *gl)
2187 {
2188 unsigned i;
2189 GLenum internal_fmt = gl->internal_fmt;
2190 GLenum texture_type = gl->texture_type;
2191 GLenum texture_fmt = gl->texture_fmt;
2192
2193 #ifdef HAVE_PSGL
2194 if (!gl->pbo)
2195 glGenBuffers(1, &gl->pbo);
2196
2197 glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, gl->pbo);
2198 glBufferData(GL_TEXTURE_REFERENCE_BUFFER_SCE,
2199 gl->tex_w * gl->tex_h * gl->base_size * gl->textures,
2200 NULL, GL_STREAM_DRAW);
2201 #endif
2202
2203 #if defined(HAVE_OPENGLES) && !defined(HAVE_PSGL)
2204 /* GLES is picky about which format we use here.
2205 * Without extensions, we can *only* render to 16-bit FBOs. */
2206
2207 if (gl->hw_render_use && gl->base_size == sizeof(uint32_t))
2208 {
2209 if (gl_check_capability(GL_CAPS_ARGB8))
2210 {
2211 internal_fmt = GL_RGBA;
2212 texture_type = GL_RGBA;
2213 texture_fmt = GL_UNSIGNED_BYTE;
2214 }
2215 else
2216 {
2217 RARCH_WARN("[GL]: 32-bit FBO not supported. Falling back to 16-bit.\n");
2218 internal_fmt = GL_RGB;
2219 texture_type = GL_RGB;
2220 texture_fmt = GL_UNSIGNED_SHORT_5_6_5;
2221 }
2222 }
2223 #endif
2224
2225 glGenTextures(gl->textures, gl->texture);
2226
2227 for (i = 0; i < gl->textures; i++)
2228 {
2229 GL_BIND_TEXTURE(gl->texture[i], gl->wrap_mode, gl->tex_mag_filter,
2230 gl->tex_min_filter);
2231
2232 gl2_renderchain_init_texture_reference(
2233 gl, (gl2_renderchain_data_t*)gl->renderchain_data,
2234 i, internal_fmt,
2235 texture_fmt, texture_type);
2236 }
2237
2238 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
2239 }
2240
gl2_set_shader_viewports(gl_t * gl)2241 static INLINE void gl2_set_shader_viewports(gl_t *gl)
2242 {
2243 unsigned i;
2244 unsigned width = gl->video_width;
2245 unsigned height = gl->video_height;
2246
2247 for (i = 0; i < 2; i++)
2248 {
2249 gl->shader->use(gl, gl->shader_data, i, true);
2250 gl2_set_viewport(gl, width, height, false, true);
2251 }
2252 }
2253
gl2_set_texture_frame(void * data,const void * frame,bool rgb32,unsigned width,unsigned height,float alpha)2254 static void gl2_set_texture_frame(void *data,
2255 const void *frame, bool rgb32, unsigned width, unsigned height,
2256 float alpha)
2257 {
2258 settings_t *settings = config_get_ptr();
2259 enum texture_filter_type
2260 menu_filter = settings->bools.menu_linear_filter
2261 ? TEXTURE_FILTER_LINEAR
2262 : TEXTURE_FILTER_NEAREST;
2263 unsigned base_size = rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
2264 gl_t *gl = (gl_t*)data;
2265 if (!gl)
2266 return;
2267
2268 gl2_context_bind_hw_render(gl, false);
2269
2270 if (!gl->menu_texture)
2271 glGenTextures(1, &gl->menu_texture);
2272
2273 gl_load_texture_data(gl->menu_texture,
2274 RARCH_WRAP_EDGE, menu_filter,
2275 gl2_get_alignment(width * base_size),
2276 width, height, frame,
2277 base_size);
2278
2279 gl->menu_texture_alpha = alpha;
2280 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
2281
2282 gl2_context_bind_hw_render(gl, true);
2283 }
2284
gl2_set_texture_enable(void * data,bool state,bool full_screen)2285 static void gl2_set_texture_enable(void *data, bool state, bool full_screen)
2286 {
2287 gl_t *gl = (gl_t*)data;
2288
2289 if (!gl)
2290 return;
2291
2292 gl->menu_texture_enable = state;
2293 gl->menu_texture_full_screen = full_screen;
2294 }
2295
gl2_render_osd_background(gl_t * gl,const char * msg)2296 static void gl2_render_osd_background(gl_t *gl, const char *msg)
2297 {
2298 video_coords_t coords;
2299 struct uniform_info uniform_param;
2300 float colors[4];
2301 const unsigned
2302 vertices_total = 6;
2303 float *dummy = (float*)calloc(4 * vertices_total, sizeof(float));
2304 float *verts = (float*)malloc(2 * vertices_total * sizeof(float));
2305 settings_t *settings = config_get_ptr();
2306 float video_font_size = settings->floats.video_font_size;
2307 int msg_width =
2308 font_driver_get_message_width(NULL, msg, (unsigned)strlen(msg), 1.0f);
2309
2310 /* shader driver expects vertex coords as 0..1 */
2311 float x = settings->floats.video_msg_pos_x;
2312 float y = settings->floats.video_msg_pos_y;
2313 float width = msg_width / (float)gl->video_width;
2314 float height = video_font_size / (float)gl->video_height;
2315 float x2 = 0.005f; /* extend background around text */
2316 float y2 = 0.005f;
2317
2318 x -= x2;
2319 y -= y2;
2320 width += x2;
2321 height += y2;
2322
2323 colors[0] = settings->uints.video_msg_bgcolor_red / 255.0f;
2324 colors[1] = settings->uints.video_msg_bgcolor_green / 255.0f;
2325 colors[2] = settings->uints.video_msg_bgcolor_blue / 255.0f;
2326 colors[3] = settings->floats.video_msg_bgcolor_opacity;
2327
2328 /* triangle 1 */
2329 verts[0] = x;
2330 verts[1] = y; /* bottom-left */
2331
2332 verts[2] = x;
2333 verts[3] = y + height; /* top-left */
2334
2335 verts[4] = x + width;
2336 verts[5] = y + height; /* top-right */
2337
2338 /* triangle 2 */
2339 verts[6] = x;
2340 verts[7] = y; /* bottom-left */
2341
2342 verts[8] = x + width;
2343 verts[9] = y + height; /* top-right */
2344
2345 verts[10] = x + width;
2346 verts[11] = y; /* bottom-right */
2347
2348 coords.color = dummy;
2349 coords.vertex = verts;
2350 coords.tex_coord = dummy;
2351 coords.lut_tex_coord = dummy;
2352 coords.vertices = vertices_total;
2353
2354 gl2_set_viewport(gl,
2355 gl->video_width,
2356 gl->video_height, true, false);
2357
2358 gl->shader->use(gl, gl->shader_data,
2359 VIDEO_SHADER_STOCK_BLEND, true);
2360
2361 gl->shader->set_coords(gl->shader_data, &coords);
2362
2363 glEnable(GL_BLEND);
2364 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2365 glBlendEquation(GL_FUNC_ADD);
2366
2367 gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot);
2368
2369 uniform_param.type = UNIFORM_4F;
2370 uniform_param.enabled = true;
2371 uniform_param.location = 0;
2372 uniform_param.count = 0;
2373
2374 uniform_param.lookup.type = SHADER_PROGRAM_FRAGMENT;
2375 uniform_param.lookup.ident = "bgcolor";
2376 uniform_param.lookup.idx = VIDEO_SHADER_STOCK_BLEND;
2377 uniform_param.lookup.add_prefix = true;
2378 uniform_param.lookup.enable = true;
2379
2380 uniform_param.result.f.v0 = colors[0];
2381 uniform_param.result.f.v1 = colors[1];
2382 uniform_param.result.f.v2 = colors[2];
2383 uniform_param.result.f.v3 = colors[3];
2384
2385 gl->shader->set_uniform_parameter(gl->shader_data,
2386 &uniform_param, NULL);
2387
2388 glDrawArrays(GL_TRIANGLES, 0, coords.vertices);
2389
2390 /* reset uniform back to zero so it is not used for anything else */
2391 uniform_param.result.f.v0 = 0.0f;
2392 uniform_param.result.f.v1 = 0.0f;
2393 uniform_param.result.f.v2 = 0.0f;
2394 uniform_param.result.f.v3 = 0.0f;
2395
2396 gl->shader->set_uniform_parameter(gl->shader_data,
2397 &uniform_param, NULL);
2398
2399 free(dummy);
2400 free(verts);
2401
2402 gl2_set_viewport(gl,
2403 gl->video_width,
2404 gl->video_height, false, true);
2405 }
2406
gl2_show_mouse(void * data,bool state)2407 static void gl2_show_mouse(void *data, bool state)
2408 {
2409 gl_t *gl = (gl_t*)data;
2410
2411 if (gl && gl->ctx_driver->show_mouse)
2412 gl->ctx_driver->show_mouse(gl->ctx_data, state);
2413 }
2414
gl2_get_current_shader(void * data)2415 static struct video_shader *gl2_get_current_shader(void *data)
2416 {
2417 gl_t *gl = (gl_t*)data;
2418
2419 if (!gl)
2420 return NULL;
2421
2422 return gl->shader->get_current_shader(gl->shader_data);
2423 }
2424
2425 #if defined(HAVE_MENU)
gl2_draw_texture(gl_t * gl)2426 static INLINE void gl2_draw_texture(gl_t *gl)
2427 {
2428 GLfloat color[16];
2429 unsigned width = gl->video_width;
2430 unsigned height = gl->video_height;
2431
2432 color[ 0] = 1.0f;
2433 color[ 1] = 1.0f;
2434 color[ 2] = 1.0f;
2435 color[ 3] = gl->menu_texture_alpha;
2436 color[ 4] = 1.0f;
2437 color[ 5] = 1.0f;
2438 color[ 6] = 1.0f;
2439 color[ 7] = gl->menu_texture_alpha;
2440 color[ 8] = 1.0f;
2441 color[ 9] = 1.0f;
2442 color[10] = 1.0f;
2443 color[11] = gl->menu_texture_alpha;
2444 color[12] = 1.0f;
2445 color[13] = 1.0f;
2446 color[14] = 1.0f;
2447 color[15] = gl->menu_texture_alpha;
2448
2449 gl->coords.vertex = vertexes_flipped;
2450 gl->coords.tex_coord = tex_coords;
2451 gl->coords.color = color;
2452
2453 glBindTexture(GL_TEXTURE_2D, gl->menu_texture);
2454
2455 gl->shader->use(gl,
2456 gl->shader_data, VIDEO_SHADER_STOCK_BLEND, true);
2457
2458 gl->coords.vertices = 4;
2459
2460 gl->shader->set_coords(gl->shader_data, &gl->coords);
2461 gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot);
2462
2463 glEnable(GL_BLEND);
2464
2465 if (gl->menu_texture_full_screen)
2466 {
2467 glViewport(0, 0, width, height);
2468 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2469 glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
2470 }
2471 else
2472 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2473
2474 glDisable(GL_BLEND);
2475
2476 gl->coords.vertex = gl->vertex_ptr;
2477 gl->coords.tex_coord = gl->tex_info.coord;
2478 gl->coords.color = gl->white_color_ptr;
2479 }
2480 #endif
2481
gl2_pbo_async_readback(gl_t * gl)2482 static void gl2_pbo_async_readback(gl_t *gl)
2483 {
2484 #ifdef HAVE_OPENGLES
2485 GLenum fmt = GL_RGBA;
2486 GLenum type = GL_UNSIGNED_BYTE;
2487 #else
2488 GLenum fmt = GL_BGRA;
2489 GLenum type = GL_UNSIGNED_INT_8_8_8_8_REV;
2490 #endif
2491
2492 gl2_renderchain_bind_pbo(
2493 gl->pbo_readback[gl->pbo_readback_index++]);
2494 gl->pbo_readback_index &= 3;
2495
2496 /* 4 frames back, we can readback. */
2497 gl->pbo_readback_valid[gl->pbo_readback_index] = true;
2498
2499 gl2_renderchain_readback(gl, gl->renderchain_data,
2500 gl2_get_alignment(gl->vp.width * sizeof(uint32_t)),
2501 fmt, type, NULL);
2502 gl2_renderchain_unbind_pbo();
2503 }
2504
2505 #ifdef HAVE_VIDEO_LAYOUT
2506 static float video_layout_layer_tex_coord[] = {
2507 0.0f, 1.0f,
2508 1.0f, 1.0f,
2509 0.0f, 0.0f,
2510 1.0f, 0.0f,
2511 };
2512
gl2_video_layout_fbo_init(gl_t * gl,unsigned width,unsigned height)2513 static void gl2_video_layout_fbo_init(gl_t *gl, unsigned width, unsigned height)
2514 {
2515 glGenTextures(1, &gl->video_layout_fbo_texture);
2516 glBindTexture(GL_TEXTURE_2D, gl->video_layout_fbo_texture);
2517
2518 gl2_load_texture_image(GL_TEXTURE_2D, 0, RARCH_GL_INTERNAL_FORMAT32,
2519 width, height, 0, GL_RGBA, GL_FLOAT, NULL);
2520
2521 gl2_gen_fb(1, &gl->video_layout_fbo);
2522 gl2_bind_fb(gl->video_layout_fbo);
2523
2524 gl2_fb_texture_2d(RARCH_GL_FRAMEBUFFER, RARCH_GL_COLOR_ATTACHMENT0,
2525 GL_TEXTURE_2D, gl->video_layout_fbo_texture, 0);
2526
2527 if (gl2_check_fb_status(RARCH_GL_FRAMEBUFFER) !=
2528 RARCH_GL_FRAMEBUFFER_COMPLETE)
2529 RARCH_LOG("[GL]: Unable to create FBO for video_layout\n");
2530
2531 gl2_bind_fb(0);
2532 }
2533
gl2_video_layout_fbo_free(gl_t * gl)2534 static void gl2_video_layout_fbo_free(gl_t *gl)
2535 {
2536 if (gl->video_layout_fbo)
2537 {
2538 gl2_delete_fb(1, &gl->video_layout_fbo);
2539 gl->video_layout_fbo = 0;
2540 }
2541
2542 if (gl->video_layout_fbo_texture)
2543 {
2544 glDeleteTextures(1, &gl->video_layout_fbo_texture);
2545 gl->video_layout_fbo_texture = 0;
2546 }
2547 }
2548
gl2_video_layout_viewport(gl_t * gl)2549 static void gl2_video_layout_viewport(gl_t *gl)
2550 {
2551 if (!video_layout_valid())
2552 return;
2553
2554 if (gl->video_layout_resize)
2555 {
2556 if (gl->video_layout_fbo)
2557 gl2_video_layout_fbo_free(gl);
2558
2559 gl2_video_layout_fbo_init(gl, gl->video_width, gl->video_height);
2560
2561 video_layout_view_change();
2562
2563 gl->video_layout_resize = false;
2564 }
2565
2566 if (video_layout_view_on_change())
2567 {
2568 video_layout_bounds_t b;
2569 b.x = 0.0f;
2570 b.y = 0.0f;
2571 b.w = (float)gl->video_width;
2572 b.h = (float)gl->video_height;
2573 video_layout_view_fit_bounds(b);
2574 }
2575
2576 if (video_layout_screen_count())
2577 {
2578 const video_layout_bounds_t *bounds;
2579 bounds = video_layout_screen(0);
2580
2581 glViewport(
2582 bounds->x, gl->video_height - bounds->y - bounds->h,
2583 bounds->w, bounds->h
2584 );
2585 }
2586 }
2587
gl2_video_layout_render(gl_t * gl)2588 static void gl2_video_layout_render(gl_t *gl)
2589 {
2590 int i;
2591
2592 if (!video_layout_valid())
2593 return;
2594
2595 glViewport(0, 0, gl->video_width, gl->video_height);
2596 glEnable(GL_BLEND);
2597
2598 for (i = 0; i < video_layout_layer_count(); ++i)
2599 video_layout_layer_render(i);
2600
2601 glDisable(GL_BLEND);
2602 }
2603
gl2_video_layout_init(gl_t * gl)2604 static void gl2_video_layout_init(gl_t *gl)
2605 {
2606 uint32_t px;
2607
2608 gl->video_layout_resize = true;
2609
2610 /* white 1px texture for drawing solid colors */
2611 px = 0xFFFFFFFF;
2612
2613 glGenTextures(1, &gl->video_layout_white_texture);
2614 gl_load_texture_data(gl->video_layout_white_texture,
2615 RARCH_WRAP_EDGE, TEXTURE_FILTER_NEAREST,
2616 sizeof(uint32_t), 1, 1, &px, sizeof(uint32_t));
2617 }
2618
gl2_video_layout_free(gl_t * gl)2619 static void gl2_video_layout_free(gl_t *gl)
2620 {
2621 gl2_video_layout_fbo_free(gl);
2622
2623 if (gl->video_layout_white_texture)
2624 {
2625 glDeleteTextures(1, &gl->video_layout_white_texture);
2626 gl->video_layout_white_texture = 0;
2627 }
2628 }
2629
gl2_video_layout_take_image(void * video_driver_data,struct texture_image image)2630 static void *gl2_video_layout_take_image(void *video_driver_data, struct texture_image image)
2631 {
2632 GLuint tex = 0;
2633 unsigned alignment = gl2_get_alignment(image.width * sizeof(uint32_t));
2634
2635 glGenTextures(1, &tex);
2636
2637 gl_load_texture_data(tex,
2638 RARCH_WRAP_EDGE, TEXTURE_FILTER_MIPMAP_LINEAR,
2639 alignment, image.width, image.height, image.pixels, sizeof(uint32_t));
2640
2641 free(image.pixels);
2642
2643 return (void*)(uintptr_t)tex;
2644 }
2645
gl2_video_layout_free_image(void * video_driver_data,void * image)2646 static void gl2_video_layout_free_image(void *video_driver_data, void *image)
2647 {
2648 GLuint tex;
2649 tex = (GLuint)(uintptr_t)image;
2650 glDeleteTextures(1, &tex);
2651 }
2652
gl2_video_layout_layer_begin(const video_layout_render_info_t * info)2653 static void gl2_video_layout_layer_begin(const video_layout_render_info_t *info)
2654 {
2655 gl_t *gl;
2656 gl = (gl_t*)info->video_driver_data;
2657
2658 gl2_bind_fb(gl->video_layout_fbo);
2659
2660 glClearColor(0, 0, 0, 0);
2661 glClear(GL_COLOR_BUFFER_BIT);
2662
2663 gl->shader->use(gl, gl->shader_data,
2664 VIDEO_SHADER_STOCK_BLEND, true);
2665
2666 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2667 }
2668
gl2_video_layout_image(const video_layout_render_info_t * info,void * image_handle,void * alpha_handle)2669 static void gl2_video_layout_image(
2670 const video_layout_render_info_t *info,
2671 void *image_handle, void *alpha_handle)
2672 {
2673 /* TODO alpha_handle */
2674 int i;
2675 float coord[8];
2676 float color[16];
2677 gl_t *gl = (gl_t*)info->video_driver_data;
2678 video_layout_bounds_t b = info->bounds;
2679
2680 b.x /= gl->video_width;
2681 b.y /= gl->video_height;
2682 b.w /= gl->video_width;
2683 b.h /= gl->video_height;
2684
2685 coord[0] = b.x;
2686 coord[1] = 1.f - b.y;
2687 coord[2] = b.x + b.w;
2688 coord[3] = 1.f - b.y;
2689 coord[4] = b.x;
2690 coord[5] = 1.f - (b.y + b.h);
2691 coord[6] = b.x + b.w;
2692 coord[7] = 1.f - (b.y + b.h);
2693
2694 i = 0;
2695 while (i < 16)
2696 {
2697 color[i++] = info->color.r;
2698 color[i++] = info->color.g;
2699 color[i++] = info->color.b;
2700 color[i++] = info->color.a;
2701 }
2702
2703 gl->coords.vertex = coord;
2704 gl->coords.tex_coord = tex_coords;
2705 gl->coords.color = color;
2706 gl->coords.vertices = 4;
2707
2708 gl->shader->set_coords(gl->shader_data, &gl->coords);
2709 gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot);
2710
2711 glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr_t)image_handle);
2712 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2713 }
2714
gl2_video_layout_text(const video_layout_render_info_t * info,const char * str)2715 static void gl2_video_layout_text(const video_layout_render_info_t *info, const char *str)
2716 {
2717 /* TODO */
2718 }
2719
gl2_video_layout_counter(const video_layout_render_info_t * info,int value)2720 static void gl2_video_layout_counter(const video_layout_render_info_t *info, int value)
2721 {
2722 /* TODO */
2723 }
2724
gl2_video_layout_rect(const video_layout_render_info_t * info)2725 static void gl2_video_layout_rect(const video_layout_render_info_t *info)
2726 {
2727 gl_t *gl;
2728 gl = (gl_t*)info->video_driver_data;
2729
2730 gl2_video_layout_image(info, (void*)(uintptr_t)gl->video_layout_white_texture, NULL);
2731 }
2732
gl2_video_layout_screen(const video_layout_render_info_t * info,int screen_index)2733 static void gl2_video_layout_screen(const video_layout_render_info_t *info, int screen_index)
2734 {
2735 gl2_video_layout_rect(info);
2736 }
2737
gl2_video_layout_ellipse(const video_layout_render_info_t * info)2738 static void gl2_video_layout_ellipse(const video_layout_render_info_t *info)
2739 {
2740 /* TODO */
2741 }
2742
gl2_video_layout_led_dot(const video_layout_render_info_t * info,int dot_count,int dot_mask)2743 static void gl2_video_layout_led_dot(const video_layout_render_info_t *info, int dot_count, int dot_mask)
2744 {
2745 /* TODO */
2746 }
2747
gl2_video_layout_led_seg(const video_layout_render_info_t * info,video_layout_led_t seg_layout,int seg_mask)2748 static void gl2_video_layout_led_seg(const video_layout_render_info_t *info, video_layout_led_t seg_layout, int seg_mask)
2749 {
2750 /* TODO */
2751 }
2752
gl2_video_layout_layer_end(const video_layout_render_info_t * info,video_layout_blend_t blend_type)2753 static void gl2_video_layout_layer_end(const video_layout_render_info_t *info, video_layout_blend_t blend_type)
2754 {
2755 gl_t *gl;
2756 gl = (gl_t*)info->video_driver_data;
2757
2758 switch (blend_type)
2759 {
2760 case VIDEO_LAYOUT_BLEND_ALPHA:
2761 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2762 break;
2763 case VIDEO_LAYOUT_BLEND_ADD:
2764 glBlendFunc(GL_ONE, GL_ONE);
2765 break;
2766 case VIDEO_LAYOUT_BLEND_MOD:
2767 glBlendFunc(GL_DST_COLOR, GL_ZERO);
2768 break;
2769 }
2770
2771 gl2_bind_fb(0);
2772
2773 gl->coords.vertex = gl->vertex_ptr;
2774 gl->coords.tex_coord = video_layout_layer_tex_coord;
2775 gl->coords.color = gl->white_color_ptr;
2776 gl->coords.vertices = 4;
2777
2778 gl->shader->set_coords(gl->shader_data, &gl->coords);
2779 gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot);
2780
2781 glBindTexture(GL_TEXTURE_2D, gl->video_layout_fbo_texture);
2782 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2783
2784 gl->coords.tex_coord = gl->tex_info.coord;
2785 }
2786
2787 static video_layout_render_interface_t gl2_video_layout_render_interface =
2788 {
2789 gl2_video_layout_take_image,
2790 gl2_video_layout_free_image,
2791 gl2_video_layout_layer_begin,
2792 gl2_video_layout_screen,
2793 gl2_video_layout_image,
2794 gl2_video_layout_text,
2795 gl2_video_layout_counter,
2796 gl2_video_layout_rect,
2797 gl2_video_layout_ellipse,
2798 gl2_video_layout_led_dot,
2799 gl2_video_layout_led_seg,
2800 gl2_video_layout_layer_end
2801 };
2802
gl2_get_video_layout_render_interface(void * data)2803 static const video_layout_render_interface_t *gl2_get_video_layout_render_interface(void *data)
2804 {
2805 return &gl2_video_layout_render_interface;
2806 }
2807 #endif /* HAVE_VIDEO_LAYOUT */
2808
gl2_frame(void * data,const void * frame,unsigned frame_width,unsigned frame_height,uint64_t frame_count,unsigned pitch,const char * msg,video_frame_info_t * video_info)2809 static bool gl2_frame(void *data, const void *frame,
2810 unsigned frame_width, unsigned frame_height,
2811 uint64_t frame_count,
2812 unsigned pitch, const char *msg,
2813 video_frame_info_t *video_info)
2814 {
2815 video_shader_ctx_params_t params;
2816 struct video_tex_info feedback_info;
2817 gl_t *gl = (gl_t*)data;
2818 gl2_renderchain_data_t *chain = (gl2_renderchain_data_t*)gl->renderchain_data;
2819 unsigned width = gl->video_width;
2820 unsigned height = gl->video_height;
2821 bool use_rgba = video_info->use_rgba;
2822 bool statistics_show = video_info->statistics_show;
2823 bool msg_bgcolor_enable = video_info->msg_bgcolor_enable;
2824 #ifndef EMSCRIPTEN
2825 unsigned black_frame_insertion = video_info->black_frame_insertion;
2826 #endif
2827 bool input_driver_nonblock_state = video_info->input_driver_nonblock_state;
2828 bool hard_sync = video_info->hard_sync;
2829 unsigned hard_sync_frames = video_info->hard_sync_frames;
2830 struct font_params *osd_params = (struct font_params*)
2831 &video_info->osd_stat_params;
2832 const char *stat_text = video_info->stat_text;
2833 #ifdef HAVE_MENU
2834 bool menu_is_alive = video_info->menu_is_alive;
2835 #endif
2836 #ifdef HAVE_GFX_WIDGETS
2837 bool widgets_active = video_info->widgets_active;
2838 #endif
2839 #ifndef EMSCRIPTEN
2840 bool runloop_is_slowmotion = video_info->runloop_is_slowmotion;
2841 bool runloop_is_paused = video_info->runloop_is_paused;
2842 #endif
2843
2844 if (!gl)
2845 return false;
2846
2847 gl2_context_bind_hw_render(gl, false);
2848
2849 #ifndef HAVE_OPENGLES
2850 if (gl->core_context_in_use)
2851 glBindVertexArray(chain->vao);
2852 #endif
2853
2854 gl->shader->use(gl, gl->shader_data, 1, true);
2855
2856 #ifdef IOS
2857 /* Apparently the viewport is lost each frame, thanks Apple. */
2858 gl2_set_viewport(gl, width, height, false, true);
2859 #endif
2860
2861 /* Render to texture in first pass. */
2862 if (gl->fbo_inited)
2863 {
2864 gl2_renderchain_recompute_pass_sizes(
2865 gl, chain,
2866 frame_width, frame_height,
2867 gl->vp_out_width, gl->vp_out_height);
2868
2869 gl2_renderchain_start_render(gl, chain);
2870 }
2871
2872 if (gl->should_resize)
2873 {
2874 if (gl->ctx_driver->set_resize)
2875 gl->ctx_driver->set_resize(gl->ctx_data,
2876 width, height);
2877 gl->should_resize = false;
2878
2879 if (gl->fbo_inited)
2880 {
2881 /* On resize, we might have to recreate our FBOs
2882 * due to "Viewport" scale, and set a new viewport. */
2883 unsigned i;
2884
2885 /* Check if we have to recreate our FBO textures. */
2886 for (i = 0; i < (unsigned)chain->fbo_pass; i++)
2887 {
2888 struct video_fbo_rect *fbo_rect = &gl->fbo_rect[i];
2889 if (fbo_rect)
2890 {
2891 unsigned img_width = fbo_rect->max_img_width;
2892 unsigned img_height = fbo_rect->max_img_height;
2893
2894 if ((img_width > fbo_rect->width) ||
2895 (img_height > fbo_rect->height))
2896 {
2897 /* Check proactively since we might suddently
2898 * get sizes of tex_w width or tex_h height. */
2899 unsigned max = img_width > img_height ? img_width : img_height;
2900 unsigned pow2_size = next_pow2(max);
2901 bool update_feedback = gl->fbo_feedback_enable
2902 && (unsigned)i == gl->fbo_feedback_pass;
2903
2904 fbo_rect->width = pow2_size;
2905 fbo_rect->height = pow2_size;
2906
2907 gl2_recreate_fbo(fbo_rect, chain->fbo[i], &chain->fbo_texture[i]);
2908
2909 /* Update feedback texture in-place so we avoid having to
2910 * juggle two different fbo_rect structs since they get updated here. */
2911 if (update_feedback)
2912 {
2913 if (gl2_recreate_fbo(fbo_rect, gl->fbo_feedback,
2914 &gl->fbo_feedback_texture))
2915 {
2916 /* Make sure the feedback textures are cleared
2917 * so we don't feedback noise. */
2918 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2919 glClear(GL_COLOR_BUFFER_BIT);
2920 }
2921 }
2922
2923 RARCH_LOG("[GL]: Recreating FBO texture #%d: %ux%u\n",
2924 i, fbo_rect->width, fbo_rect->height);
2925 }
2926 }
2927 }
2928
2929 /* Go back to what we're supposed to do,
2930 * render to FBO #0. */
2931 gl2_renderchain_start_render(gl, chain);
2932 }
2933 else
2934 gl2_set_viewport(gl, width, height, false, true);
2935
2936 #ifdef HAVE_VIDEO_LAYOUT
2937 gl->video_layout_resize = true;
2938 #endif
2939 }
2940
2941 #ifdef HAVE_VIDEO_LAYOUT
2942 gl2_video_layout_viewport(gl);
2943 #endif
2944
2945 if (frame)
2946 gl->tex_index = ((gl->tex_index + 1) % gl->textures);
2947
2948 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
2949
2950 /* Can be NULL for frame dupe / NULL render. */
2951 if (frame)
2952 {
2953 if (!gl->hw_render_fbo_init)
2954 {
2955 gl2_update_input_size(gl, frame_width, frame_height, pitch, true);
2956
2957 gl2_renderchain_copy_frame(gl, chain, use_rgba,
2958 frame, frame_width, frame_height, pitch);
2959 }
2960
2961 /* No point regenerating mipmaps
2962 * if there are no new frames. */
2963 if (gl->tex_mipmap && gl->have_mipmap)
2964 glGenerateMipmap(GL_TEXTURE_2D);
2965 }
2966
2967 /* Have to reset rendering state which libretro core
2968 * could easily have overridden. */
2969 if (gl->hw_render_fbo_init)
2970 {
2971 gl2_update_input_size(gl, frame_width, frame_height, pitch, false);
2972 if (!gl->fbo_inited)
2973 {
2974 gl2_renderchain_bind_backbuffer();
2975 gl2_set_viewport(gl, width, height, false, true);
2976 }
2977
2978 gl2_renderchain_restore_default_state(gl);
2979
2980 glDisable(GL_STENCIL_TEST);
2981 glDisable(GL_BLEND);
2982 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2983 glBlendEquation(GL_FUNC_ADD);
2984 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
2985 }
2986
2987 gl->tex_info.tex = gl->texture[gl->tex_index];
2988 gl->tex_info.input_size[0] = frame_width;
2989 gl->tex_info.input_size[1] = frame_height;
2990 gl->tex_info.tex_size[0] = gl->tex_w;
2991 gl->tex_info.tex_size[1] = gl->tex_h;
2992
2993 feedback_info = gl->tex_info;
2994
2995 if (gl->fbo_feedback_enable)
2996 {
2997 const struct video_fbo_rect
2998 *rect = &gl->fbo_rect[gl->fbo_feedback_pass];
2999 GLfloat xamt = (GLfloat)rect->img_width / rect->width;
3000 GLfloat yamt = (GLfloat)rect->img_height / rect->height;
3001
3002 feedback_info.tex = gl->fbo_feedback_texture;
3003 feedback_info.input_size[0] = rect->img_width;
3004 feedback_info.input_size[1] = rect->img_height;
3005 feedback_info.tex_size[0] = rect->width;
3006 feedback_info.tex_size[1] = rect->height;
3007
3008 SET_TEXTURE_COORDS(feedback_info.coord, xamt, yamt);
3009 }
3010
3011 glClear(GL_COLOR_BUFFER_BIT);
3012
3013 params.data = gl;
3014 params.width = frame_width;
3015 params.height = frame_height;
3016 params.tex_width = gl->tex_w;
3017 params.tex_height = gl->tex_h;
3018 params.out_width = gl->vp.width;
3019 params.out_height = gl->vp.height;
3020 params.frame_counter = (unsigned int)frame_count;
3021 params.info = &gl->tex_info;
3022 params.prev_info = gl->prev_info;
3023 params.feedback_info = &feedback_info;
3024 params.fbo_info = NULL;
3025 params.fbo_info_cnt = 0;
3026
3027 gl->shader->set_params(¶ms, gl->shader_data);
3028
3029 gl->coords.vertices = 4;
3030
3031 gl->shader->set_coords(gl->shader_data, &gl->coords);
3032 gl->shader->set_mvp(gl->shader_data, &gl->mvp);
3033
3034 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3035
3036 if (gl->fbo_inited)
3037 gl2_renderchain_render(gl,
3038 chain,
3039 frame_count, &gl->tex_info, &feedback_info);
3040
3041 /* Set prev textures. */
3042 gl2_renderchain_bind_prev_texture(gl,
3043 chain, &gl->tex_info);
3044
3045 #ifdef HAVE_VIDEO_LAYOUT
3046 gl2_video_layout_render(gl);
3047 #endif
3048 #if defined(HAVE_MENU)
3049 if (gl->menu_texture_enable)
3050 {
3051 menu_driver_frame(menu_is_alive, video_info);
3052
3053 if (gl->menu_texture)
3054 gl2_draw_texture(gl);
3055 }
3056 else if (statistics_show)
3057 {
3058 if (osd_params)
3059 font_driver_render_msg(gl, stat_text,
3060 (const struct font_params*)osd_params, NULL);
3061 }
3062 #endif
3063
3064 #ifdef HAVE_OVERLAY
3065 if (gl->overlay_enable)
3066 gl2_render_overlay(gl);
3067 #endif
3068
3069 #ifdef HAVE_GFX_WIDGETS
3070 if (widgets_active)
3071 gfx_widgets_frame(video_info);
3072 #endif
3073
3074 if (!string_is_empty(msg))
3075 {
3076 if (msg_bgcolor_enable)
3077 gl2_render_osd_background(gl, msg);
3078 font_driver_render_msg(gl, msg, NULL, NULL);
3079 }
3080
3081 if (gl->ctx_driver->update_window_title)
3082 gl->ctx_driver->update_window_title(gl->ctx_data);
3083
3084 /* Reset state which could easily mess up libretro core. */
3085 if (gl->hw_render_fbo_init)
3086 {
3087 gl->shader->use(gl, gl->shader_data, 0, true);
3088 glBindTexture(GL_TEXTURE_2D, 0);
3089 }
3090
3091 /* Screenshots. */
3092 if (gl->readback_buffer_screenshot)
3093 gl2_renderchain_readback(gl,
3094 chain,
3095 4, GL_RGBA, GL_UNSIGNED_BYTE,
3096 gl->readback_buffer_screenshot);
3097
3098 /* Don't readback if we're in menu mode. */
3099 else if (gl->pbo_readback_enable)
3100 #ifdef HAVE_MENU
3101 /* Don't readback if we're in menu mode. */
3102 if (!gl->menu_texture_enable)
3103 #endif
3104 gl2_pbo_async_readback(gl);
3105
3106 if (gl->ctx_driver->swap_buffers)
3107 gl->ctx_driver->swap_buffers(gl->ctx_data);
3108
3109 /* Emscripten has to do black frame insertion in its main loop */
3110 #ifndef EMSCRIPTEN
3111 /* Disable BFI during fast forward, slow-motion,
3112 * and pause to prevent flicker. */
3113 if (
3114 black_frame_insertion
3115 && !input_driver_nonblock_state
3116 && !runloop_is_slowmotion
3117 && !runloop_is_paused
3118 && !gl->menu_texture_enable)
3119 {
3120 unsigned n;
3121 for (n = 0; n < black_frame_insertion; ++n)
3122 {
3123 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3124 glClear(GL_COLOR_BUFFER_BIT);
3125
3126 if (gl->ctx_driver->swap_buffers)
3127 gl->ctx_driver->swap_buffers(gl->ctx_data);
3128 }
3129 }
3130 #endif
3131
3132 /* check if we are fast forwarding or in menu,
3133 * if we are ignore hard sync */
3134 if ( gl->have_sync
3135 && hard_sync
3136 && !input_driver_nonblock_state
3137 && !gl->menu_texture_enable)
3138 {
3139 glClear(GL_COLOR_BUFFER_BIT);
3140
3141 gl2_renderchain_fence_iterate(gl, chain,
3142 hard_sync_frames);
3143 }
3144
3145 #ifndef HAVE_OPENGLES
3146 if (gl->core_context_in_use)
3147 glBindVertexArray(0);
3148 #endif
3149 gl2_context_bind_hw_render(gl, true);
3150 return true;
3151 }
3152
gl2_destroy_resources(gl_t * gl)3153 static void gl2_destroy_resources(gl_t *gl)
3154 {
3155 if (gl)
3156 {
3157 if (gl->empty_buf)
3158 free(gl->empty_buf);
3159 if (gl->conv_buffer)
3160 free(gl->conv_buffer);
3161 free(gl);
3162 }
3163
3164 gl_query_core_context_unset();
3165 }
3166
gl2_deinit_chain(gl_t * gl)3167 static void gl2_deinit_chain(gl_t *gl)
3168 {
3169 if (!gl)
3170 return;
3171
3172 if (gl->renderchain_data)
3173 free(gl->renderchain_data);
3174 gl->renderchain_data = NULL;
3175 }
3176
gl2_free(void * data)3177 static void gl2_free(void *data)
3178 {
3179 gl_t *gl = (gl_t*)data;
3180 if (!gl)
3181 return;
3182
3183 #ifdef HAVE_VIDEO_LAYOUT
3184 gl2_video_layout_free(gl);
3185 #endif
3186
3187 gl2_context_bind_hw_render(gl, false);
3188
3189 if (gl->have_sync)
3190 gl2_renderchain_fence_free(gl,
3191 (gl2_renderchain_data_t*)
3192 gl->renderchain_data);
3193
3194 font_driver_free_osd();
3195
3196 gl->shader->deinit(gl->shader_data);
3197
3198 glDeleteTextures(gl->textures, gl->texture);
3199
3200 #if defined(HAVE_MENU)
3201 if (gl->menu_texture)
3202 glDeleteTextures(1, &gl->menu_texture);
3203 #endif
3204
3205 #ifdef HAVE_OVERLAY
3206 gl2_free_overlay(gl);
3207 #endif
3208
3209 #if defined(HAVE_PSGL)
3210 glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0);
3211 glDeleteBuffers(1, &gl->pbo);
3212 #endif
3213
3214 scaler_ctx_gen_reset(&gl->scaler);
3215
3216 if (gl->pbo_readback_enable)
3217 {
3218 glDeleteBuffers(4, gl->pbo_readback);
3219 scaler_ctx_gen_reset(&gl->pbo_readback_scaler);
3220 }
3221
3222 #ifndef HAVE_OPENGLES
3223 if (gl->core_context_in_use)
3224 {
3225 gl2_renderchain_data_t *chain = (gl2_renderchain_data_t*)
3226 gl->renderchain_data;
3227
3228 glBindVertexArray(0);
3229 glDeleteVertexArrays(1, &chain->vao);
3230 }
3231 #endif
3232
3233 gl2_renderchain_deinit_fbo(gl, (gl2_renderchain_data_t*)gl->renderchain_data);
3234 gl2_renderchain_deinit_hw_render(gl, (gl2_renderchain_data_t*)gl->renderchain_data);
3235 gl2_deinit_chain(gl);
3236
3237 if (gl->ctx_driver && gl->ctx_driver->destroy)
3238 gl->ctx_driver->destroy(gl->ctx_data);
3239 video_context_driver_free();
3240
3241 gl2_destroy_resources(gl);
3242 }
3243
gl2_set_nonblock_state(void * data,bool state,bool adaptive_vsync_enabled,unsigned swap_interval)3244 static void gl2_set_nonblock_state(
3245 void *data, bool state,
3246 bool adaptive_vsync_enabled,
3247 unsigned swap_interval)
3248 {
3249 int interval = 0;
3250 gl_t *gl = (gl_t*)data;
3251
3252 if (!gl)
3253 return;
3254
3255 gl2_context_bind_hw_render(gl, false);
3256
3257 if (!state)
3258 interval = swap_interval;
3259
3260 if (gl->ctx_driver->swap_interval)
3261 {
3262 if (adaptive_vsync_enabled && interval == 1)
3263 interval = -1;
3264 gl->ctx_driver->swap_interval(gl->ctx_data, interval);
3265 }
3266 gl2_context_bind_hw_render(gl, true);
3267 }
3268
gl2_resolve_extensions(gl_t * gl,const char * context_ident,const video_info_t * video)3269 static bool gl2_resolve_extensions(gl_t *gl, const char *context_ident, const video_info_t *video)
3270 {
3271 settings_t *settings = config_get_ptr();
3272 bool video_hard_sync = settings->bools.video_hard_sync;
3273
3274 /* have_es2_compat - GL_RGB565 internal format support.
3275 * Even though ES2 support is claimed, the format
3276 * is not supported on older ATI catalyst drivers.
3277 *
3278 * The speed gain from using GL_RGB565 is worth
3279 * adding some workarounds for.
3280 *
3281 * have_sync - Use ARB_sync to reduce latency.
3282 */
3283 gl->have_full_npot_support = gl_check_capability(GL_CAPS_FULL_NPOT_SUPPORT);
3284 gl->have_mipmap = gl_check_capability(GL_CAPS_MIPMAP);
3285 gl->have_es2_compat = gl_check_capability(GL_CAPS_ES2_COMPAT);
3286 gl->support_unpack_row_length = gl_check_capability(GL_CAPS_UNPACK_ROW_LENGTH);
3287 gl->have_sync = gl_check_capability(GL_CAPS_SYNC);
3288
3289 if (gl->have_sync && video_hard_sync)
3290 RARCH_LOG("[GL]: Using ARB_sync to reduce latency.\n");
3291
3292 video_driver_unset_rgba();
3293
3294 gl2_renderchain_resolve_extensions(gl,
3295 (gl2_renderchain_data_t*)gl->renderchain_data,
3296 context_ident, video);
3297
3298 #if defined(HAVE_OPENGLES) && !defined(HAVE_PSGL)
3299 if (!gl_check_capability(GL_CAPS_BGRA8888))
3300 {
3301 video_driver_set_rgba();
3302 RARCH_WARN("[GL]: GLES implementation does not have BGRA8888 extension.\n"
3303 "[GL]: 32-bit path will require conversion.\n");
3304 }
3305 /* TODO/FIXME - No extensions for float FBO currently. */
3306 #endif
3307
3308 #ifdef GL_DEBUG
3309 /* Useful for debugging, but kinda obnoxious otherwise. */
3310 RARCH_LOG("[GL]: Supported extensions:\n");
3311
3312 if (gl->core_context_in_use)
3313 {
3314 #ifdef GL_NUM_EXTENSIONS
3315 GLint exts = 0;
3316 glGetIntegerv(GL_NUM_EXTENSIONS, &exts);
3317 for (GLint i = 0; i < exts; i++)
3318 {
3319 const char *ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
3320 if (ext)
3321 RARCH_LOG("\t%s\n", ext);
3322 }
3323 #endif
3324 }
3325 else
3326 {
3327 const char *ext = (const char*)glGetString(GL_EXTENSIONS);
3328
3329 if (ext)
3330 {
3331 size_t i;
3332 struct string_list list = {0};
3333
3334 string_list_initialize(&list);
3335 string_split_noalloc(&list, ext, " ");
3336
3337 for (i = 0; i < list.size; i++)
3338 RARCH_LOG("\t%s\n", list.elems[i].data);
3339 string_list_deinitialize(&list);
3340 }
3341 }
3342 #endif
3343
3344 return true;
3345 }
3346
gl2_set_texture_fmts(gl_t * gl,bool rgb32)3347 static INLINE void gl2_set_texture_fmts(gl_t *gl, bool rgb32)
3348 {
3349 gl->internal_fmt = RARCH_GL_INTERNAL_FORMAT16;
3350 gl->texture_type = RARCH_GL_TEXTURE_TYPE16;
3351 gl->texture_fmt = RARCH_GL_FORMAT16;
3352 gl->base_size = sizeof(uint16_t);
3353
3354 if (rgb32)
3355 {
3356 bool use_rgba = video_driver_supports_rgba();
3357
3358 gl->internal_fmt = RARCH_GL_INTERNAL_FORMAT32;
3359 gl->texture_type = RARCH_GL_TEXTURE_TYPE32;
3360 gl->texture_fmt = RARCH_GL_FORMAT32;
3361 gl->base_size = sizeof(uint32_t);
3362
3363 if (use_rgba)
3364 {
3365 gl->internal_fmt = GL_RGBA;
3366 gl->texture_type = GL_RGBA;
3367 }
3368 }
3369 #ifndef HAVE_OPENGLES
3370 else if (gl->have_es2_compat)
3371 {
3372 RARCH_LOG("[GL]: Using GL_RGB565 for texture uploads.\n");
3373 gl->internal_fmt = RARCH_GL_INTERNAL_FORMAT16_565;
3374 gl->texture_type = RARCH_GL_TEXTURE_TYPE16_565;
3375 gl->texture_fmt = RARCH_GL_FORMAT16_565;
3376 }
3377 #endif
3378 }
3379
gl2_init_pbo_readback(gl_t * gl)3380 static bool gl2_init_pbo_readback(gl_t *gl)
3381 {
3382 #if !defined(HAVE_OPENGLES2) && !defined(HAVE_PSGL)
3383 unsigned i;
3384
3385 glGenBuffers(4, gl->pbo_readback);
3386
3387 for (i = 0; i < 4; i++)
3388 {
3389 gl2_renderchain_bind_pbo(gl->pbo_readback[i]);
3390 gl2_renderchain_init_pbo(gl->vp.width *
3391 gl->vp.height * sizeof(uint32_t), NULL);
3392 }
3393 gl2_renderchain_unbind_pbo();
3394
3395 #ifndef HAVE_OPENGLES3
3396 {
3397 struct scaler_ctx *scaler = &gl->pbo_readback_scaler;
3398 scaler->in_width = gl->vp.width;
3399 scaler->in_height = gl->vp.height;
3400 scaler->out_width = gl->vp.width;
3401 scaler->out_height = gl->vp.height;
3402 scaler->in_stride = gl->vp.width * sizeof(uint32_t);
3403 scaler->out_stride = gl->vp.width * 3;
3404 scaler->in_fmt = SCALER_FMT_ARGB8888;
3405 scaler->out_fmt = SCALER_FMT_BGR24;
3406 scaler->scaler_type = SCALER_TYPE_POINT;
3407
3408 if (!scaler_ctx_gen_filter(scaler))
3409 {
3410 gl->pbo_readback_enable = false;
3411 RARCH_ERR("[GL]: Failed to initialize pixel conversion for PBO.\n");
3412 glDeleteBuffers(4, gl->pbo_readback);
3413 return false;
3414 }
3415 }
3416 #endif
3417
3418 return true;
3419 #else
3420 /* If none of these are bound, we have to assume
3421 * we are not going to use PBOs */
3422 return false;
3423 #endif
3424 }
3425
gl2_get_context(gl_t * gl)3426 static const gfx_ctx_driver_t *gl2_get_context(gl_t *gl)
3427 {
3428 const gfx_ctx_driver_t *gfx_ctx = NULL;
3429 void *ctx_data = NULL;
3430 settings_t *settings = config_get_ptr();
3431 struct retro_hw_render_callback *hwr = video_driver_get_hw_context();
3432 unsigned major = hwr->version_major;
3433 unsigned minor = hwr->version_minor;
3434 bool video_shared_context = settings->bools.video_shared_context;
3435 #ifdef HAVE_OPENGLES
3436 enum gfx_ctx_api api = GFX_CTX_OPENGL_ES_API;
3437 if (hwr->context_type == RETRO_HW_CONTEXT_OPENGLES3)
3438 {
3439 major = 3;
3440 minor = 0;
3441 }
3442 #else
3443 enum gfx_ctx_api api = GFX_CTX_OPENGL_API;
3444 #endif
3445 gl->shared_context_use = video_shared_context
3446 && hwr->context_type != RETRO_HW_CONTEXT_NONE;
3447
3448 if ( (libretro_get_shared_context())
3449 && (hwr->context_type != RETRO_HW_CONTEXT_NONE))
3450 gl->shared_context_use = true;
3451
3452 gfx_ctx = video_context_driver_init_first(gl,
3453 settings->arrays.video_context_driver,
3454 api, major, minor, gl->shared_context_use, &ctx_data);
3455
3456 if (ctx_data)
3457 gl->ctx_data = ctx_data;
3458
3459 return gfx_ctx;
3460 }
3461
3462 #ifdef GL_DEBUG
3463 #ifdef HAVE_GL_DEBUG_ES
3464 #define DEBUG_CALLBACK_TYPE GL_APIENTRY
3465
3466 #define GL_DEBUG_SOURCE_API GL_DEBUG_SOURCE_API_KHR
3467 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR
3468 #define GL_DEBUG_SOURCE_SHADER_COMPILER GL_DEBUG_SOURCE_SHADER_COMPILER_KHR
3469 #define GL_DEBUG_SOURCE_THIRD_PARTY GL_DEBUG_SOURCE_THIRD_PARTY_KHR
3470 #define GL_DEBUG_SOURCE_APPLICATION GL_DEBUG_SOURCE_APPLICATION_KHR
3471 #define GL_DEBUG_SOURCE_OTHER GL_DEBUG_SOURCE_OTHER_KHR
3472 #define GL_DEBUG_TYPE_ERROR GL_DEBUG_TYPE_ERROR_KHR
3473 #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR
3474 #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR
3475 #define GL_DEBUG_TYPE_PORTABILITY GL_DEBUG_TYPE_PORTABILITY_KHR
3476 #define GL_DEBUG_TYPE_PERFORMANCE GL_DEBUG_TYPE_PERFORMANCE_KHR
3477 #define GL_DEBUG_TYPE_MARKER GL_DEBUG_TYPE_MARKER_KHR
3478 #define GL_DEBUG_TYPE_PUSH_GROUP GL_DEBUG_TYPE_PUSH_GROUP_KHR
3479 #define GL_DEBUG_TYPE_POP_GROUP GL_DEBUG_TYPE_POP_GROUP_KHR
3480 #define GL_DEBUG_TYPE_OTHER GL_DEBUG_TYPE_OTHER_KHR
3481 #define GL_DEBUG_SEVERITY_HIGH GL_DEBUG_SEVERITY_HIGH_KHR
3482 #define GL_DEBUG_SEVERITY_MEDIUM GL_DEBUG_SEVERITY_MEDIUM_KHR
3483 #define GL_DEBUG_SEVERITY_LOW GL_DEBUG_SEVERITY_LOW_KHR
3484 #else
3485 #define DEBUG_CALLBACK_TYPE APIENTRY
3486 #endif
3487
gl2_debug_cb(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,void * userParam)3488 static void DEBUG_CALLBACK_TYPE gl2_debug_cb(GLenum source, GLenum type,
3489 GLuint id, GLenum severity, GLsizei length,
3490 const GLchar *message, void *userParam)
3491 {
3492 const char *src = NULL;
3493 const char *typestr = NULL;
3494
3495 switch (source)
3496 {
3497 case GL_DEBUG_SOURCE_API:
3498 src = "API";
3499 break;
3500 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
3501 src = "Window system";
3502 break;
3503 case GL_DEBUG_SOURCE_SHADER_COMPILER:
3504 src = "Shader compiler";
3505 break;
3506 case GL_DEBUG_SOURCE_THIRD_PARTY:
3507 src = "3rd party";
3508 break;
3509 case GL_DEBUG_SOURCE_APPLICATION:
3510 src = "Application";
3511 break;
3512 case GL_DEBUG_SOURCE_OTHER:
3513 src = "Other";
3514 break;
3515 default:
3516 src = "Unknown";
3517 break;
3518 }
3519
3520 switch (type)
3521 {
3522 case GL_DEBUG_TYPE_ERROR:
3523 typestr = "Error";
3524 break;
3525 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
3526 typestr = "Deprecated behavior";
3527 break;
3528 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
3529 typestr = "Undefined behavior";
3530 break;
3531 case GL_DEBUG_TYPE_PORTABILITY:
3532 typestr = "Portability";
3533 break;
3534 case GL_DEBUG_TYPE_PERFORMANCE:
3535 typestr = "Performance";
3536 break;
3537 case GL_DEBUG_TYPE_MARKER:
3538 typestr = "Marker";
3539 break;
3540 case GL_DEBUG_TYPE_PUSH_GROUP:
3541 typestr = "Push group";
3542 break;
3543 case GL_DEBUG_TYPE_POP_GROUP:
3544 typestr = "Pop group";
3545 break;
3546 case GL_DEBUG_TYPE_OTHER:
3547 typestr = "Other";
3548 break;
3549 default:
3550 typestr = "Unknown";
3551 break;
3552 }
3553
3554 switch (severity)
3555 {
3556 case GL_DEBUG_SEVERITY_HIGH:
3557 RARCH_ERR("[GL debug (High, %s, %s)]: %s\n", src, typestr, message);
3558 break;
3559 case GL_DEBUG_SEVERITY_MEDIUM:
3560 RARCH_WARN("[GL debug (Medium, %s, %s)]: %s\n", src, typestr, message);
3561 break;
3562 case GL_DEBUG_SEVERITY_LOW:
3563 RARCH_LOG("[GL debug (Low, %s, %s)]: %s\n", src, typestr, message);
3564 break;
3565 }
3566 }
3567
gl2_begin_debug(gl_t * gl)3568 static void gl2_begin_debug(gl_t *gl)
3569 {
3570 if (gl_check_capability(GL_CAPS_DEBUG))
3571 {
3572 #ifdef HAVE_GL_DEBUG_ES
3573 glDebugMessageCallbackKHR(gl2_debug_cb, gl);
3574 glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
3575 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
3576 #else
3577 glDebugMessageCallback(gl2_debug_cb, gl);
3578 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
3579 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
3580 #endif
3581 }
3582 else
3583 RARCH_ERR("[GL]: Neither GL_KHR_debug nor GL_ARB_debug_output are implemented. Cannot start GL debugging.\n");
3584 }
3585 #endif
3586
renderchain_gl2_init_first(void ** renderchain_handle)3587 static bool renderchain_gl2_init_first(void **renderchain_handle)
3588 {
3589 gl2_renderchain_data_t *data = (gl2_renderchain_data_t *)calloc(1, sizeof(*data));
3590
3591 if (!data)
3592 return false;
3593
3594 *renderchain_handle = data;
3595 return true;
3596 }
3597
gl2_init(const video_info_t * video,input_driver_t ** input,void ** input_data)3598 static void *gl2_init(const video_info_t *video,
3599 input_driver_t **input, void **input_data)
3600 {
3601 enum gfx_wrap_type wrap_type;
3602 unsigned full_x, full_y;
3603 video_shader_ctx_info_t shader_info;
3604 settings_t *settings = config_get_ptr();
3605 bool video_gpu_record = settings->bools.video_gpu_record;
3606 int interval = 0;
3607 unsigned mip_level = 0;
3608 unsigned mode_width = 0;
3609 unsigned mode_height = 0;
3610 unsigned win_width = 0;
3611 unsigned win_height = 0;
3612 unsigned temp_width = 0;
3613 unsigned temp_height = 0;
3614 bool force_smooth = false;
3615 const char *vendor = NULL;
3616 const char *renderer = NULL;
3617 const char *version = NULL;
3618 struct retro_hw_render_callback *hwr = NULL;
3619 char *error_string = NULL;
3620 gl_t *gl = (gl_t*)calloc(1, sizeof(gl_t));
3621 const gfx_ctx_driver_t *ctx_driver = gl2_get_context(gl);
3622
3623 if (!gl || !ctx_driver)
3624 goto error;
3625
3626 video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver);
3627
3628 gl->ctx_driver = ctx_driver;
3629 gl->video_info = *video;
3630
3631 RARCH_LOG("[GL]: Found GL context: %s\n", ctx_driver->ident);
3632
3633 if (gl->ctx_driver->get_video_size)
3634 gl->ctx_driver->get_video_size(gl->ctx_data,
3635 &mode_width, &mode_height);
3636
3637 #if defined(DINGUX)
3638 mode_width = 320;
3639 mode_height = 240;
3640 #endif
3641 full_x = mode_width;
3642 full_y = mode_height;
3643 interval = 0;
3644
3645 RARCH_LOG("[GL]: Detecting screen resolution %ux%u.\n", full_x, full_y);
3646
3647 if (video->vsync)
3648 interval = video->swap_interval;
3649
3650 if (gl->ctx_driver->swap_interval)
3651 {
3652 bool adaptive_vsync_enabled = video_driver_test_all_flags(
3653 GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && video->adaptive_vsync;
3654 if (adaptive_vsync_enabled && interval == 1)
3655 interval = -1;
3656 gl->ctx_driver->swap_interval(gl->ctx_data, interval);
3657 }
3658
3659 win_width = video->width;
3660 win_height = video->height;
3661
3662 if (video->fullscreen && (win_width == 0) && (win_height == 0))
3663 {
3664 win_width = full_x;
3665 win_height = full_y;
3666 }
3667
3668 if ( !gl->ctx_driver->set_video_mode
3669 || !gl->ctx_driver->set_video_mode(gl->ctx_data,
3670 win_width, win_height, video->fullscreen))
3671 goto error;
3672 #if defined(__APPLE__) && !defined(IOS)
3673 /* This is a hack for now to work around a very annoying
3674 * issue that currently eludes us. */
3675 if ( !gl->ctx_driver->set_video_mode
3676 || !gl->ctx_driver->set_video_mode(gl->ctx_data,
3677 win_width, win_height, video->fullscreen))
3678 goto error;
3679 #endif
3680
3681 #if !defined(RARCH_CONSOLE) || defined(HAVE_LIBNX)
3682 rglgen_resolve_symbols(ctx_driver->get_proc_address);
3683 #endif
3684
3685 /* Clear out potential error flags in case we use cached context. */
3686 glGetError();
3687
3688 vendor = (const char*)glGetString(GL_VENDOR);
3689 renderer = (const char*)glGetString(GL_RENDERER);
3690 version = (const char*)glGetString(GL_VERSION);
3691
3692 RARCH_LOG("[GL]: Vendor: %s, Renderer: %s.\n", vendor, renderer);
3693 RARCH_LOG("[GL]: Version: %s.\n", version);
3694
3695 if (string_is_equal(ctx_driver->ident, "null"))
3696 goto error;
3697
3698 if (!string_is_empty(version))
3699 sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor);
3700
3701 {
3702 char device_str[128];
3703
3704 device_str[0] = '\0';
3705
3706 if (!string_is_empty(vendor))
3707 {
3708 strlcpy(device_str, vendor, sizeof(device_str));
3709 strlcat(device_str, " ", sizeof(device_str));
3710 }
3711
3712 if (!string_is_empty(renderer))
3713 strlcat(device_str, renderer, sizeof(device_str));
3714
3715 video_driver_set_gpu_device_string(device_str);
3716
3717 if (!string_is_empty(version))
3718 video_driver_set_gpu_api_version_string(version);
3719 }
3720
3721 #ifdef _WIN32
3722 if (string_is_equal(vendor, "Microsoft Corporation"))
3723 if (string_is_equal(renderer, "GDI Generic"))
3724 #ifdef HAVE_OPENGL1
3725 retroarch_force_video_driver_fallback("gl1");
3726 #else
3727 retroarch_force_video_driver_fallback("gdi");
3728 #endif
3729 #endif
3730
3731 hwr = video_driver_get_hw_context();
3732
3733 if (hwr->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
3734 {
3735 gl_query_core_context_set(true);
3736 gl->core_context_in_use = true;
3737
3738 if (hwr->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
3739 {
3740 /* Ensure that the rest of the frontend knows we have a core context */
3741 gfx_ctx_flags_t flags;
3742 flags.flags = 0;
3743 BIT32_SET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
3744
3745 video_context_driver_set_flags(&flags);
3746 }
3747
3748 RARCH_LOG("[GL]: Using Core GL context, setting up VAO...\n");
3749 if (!gl_check_capability(GL_CAPS_VAO))
3750 {
3751 RARCH_ERR("[GL]: Failed to initialize VAOs.\n");
3752 goto error;
3753 }
3754 }
3755
3756 if (!renderchain_gl2_init_first(&gl->renderchain_data))
3757 {
3758 RARCH_ERR("[GL]: Renderchain could not be initialized.\n");
3759 goto error;
3760 }
3761
3762 gl2_renderchain_restore_default_state(gl);
3763
3764 #ifndef HAVE_OPENGLES
3765 if (hwr->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
3766 {
3767 gl2_renderchain_data_t *chain = (gl2_renderchain_data_t*)
3768 gl->renderchain_data;
3769
3770 glGenVertexArrays(1, &chain->vao);
3771 }
3772 #endif
3773
3774 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3775 glBlendEquation(GL_FUNC_ADD);
3776
3777 gl->hw_render_use = false;
3778 gl->has_fbo = gl_check_capability(GL_CAPS_FBO);
3779
3780 if (gl->has_fbo && hwr->context_type != RETRO_HW_CONTEXT_NONE)
3781 gl->hw_render_use = true;
3782
3783 if (!gl2_resolve_extensions(gl, ctx_driver->ident, video))
3784 goto error;
3785
3786 #ifdef GL_DEBUG
3787 gl2_begin_debug(gl);
3788 #endif
3789
3790 gl->vsync = video->vsync;
3791 gl->fullscreen = video->fullscreen;
3792
3793 mode_width = 0;
3794 mode_height = 0;
3795
3796 if (gl->ctx_driver->get_video_size)
3797 gl->ctx_driver->get_video_size(gl->ctx_data,
3798 &mode_width, &mode_height);
3799
3800 #if defined(DINGUX)
3801 mode_width = 320;
3802 mode_height = 240;
3803 #endif
3804 temp_width = mode_width;
3805 temp_height = mode_height;
3806
3807 /* Get real known video size, which might have been altered by context. */
3808
3809 if (temp_width != 0 && temp_height != 0)
3810 video_driver_set_size(temp_width, temp_height);
3811
3812 video_driver_get_size(&temp_width, &temp_height);
3813 gl->video_width = temp_width;
3814 gl->video_height = temp_height;
3815
3816 RARCH_LOG("[GL]: Using resolution %ux%u\n", temp_width, temp_height);
3817
3818 gl->vertex_ptr = hwr->bottom_left_origin
3819 ? vertexes : vertexes_flipped;
3820
3821 /* Better pipelining with GPU due to synchronous glSubTexImage.
3822 * Multiple async PBOs would be an alternative,
3823 * but still need multiple textures with PREV.
3824 */
3825 gl->textures = 4;
3826
3827 if (gl->hw_render_use)
3828 {
3829 /* All on GPU, no need to excessively
3830 * create textures. */
3831 gl->textures = 1;
3832 #ifdef GL_DEBUG
3833 gl2_context_bind_hw_render(gl, true);
3834 gl2_begin_debug(gl);
3835 gl2_context_bind_hw_render(gl, false);
3836 #endif
3837 }
3838
3839 gl->white_color_ptr = white_color;
3840
3841 gl->shader = (shader_backend_t*)gl2_shader_ctx_drivers[0];
3842
3843 if (!gl->shader)
3844 {
3845 RARCH_ERR("[GL:]: Shader driver initialization failed.\n");
3846 goto error;
3847 }
3848
3849 RARCH_LOG("[GL]: Default shader backend found: %s.\n", gl->shader->ident);
3850
3851 if (!gl2_shader_init(gl, ctx_driver, hwr))
3852 {
3853 RARCH_ERR("[GL]: Shader initialization failed.\n");
3854 goto error;
3855 }
3856
3857 {
3858 unsigned texture_info_id = gl->shader->get_prev_textures(gl->shader_data);
3859 unsigned minimum = texture_info_id;
3860 gl->textures = MAX(minimum + 1, gl->textures);
3861 }
3862
3863 if (!gl2_shader_info(gl, &shader_info))
3864 {
3865 RARCH_ERR("[GL]: Shader driver info check failed.\n");
3866 goto error;
3867 }
3868
3869 RARCH_LOG("[GL]: Using %u textures.\n", gl->textures);
3870 RARCH_LOG("[GL]: Loaded %u program(s).\n",
3871 shader_info.num);
3872
3873 gl->tex_w = gl->tex_h = (RARCH_SCALE_BASE * video->input_scale);
3874 gl->keep_aspect = video->force_aspect;
3875
3876 #if defined(HAVE_ODROIDGO2)
3877 if (settings->bools.video_ctx_scaling)
3878 gl->keep_aspect = false;
3879 else
3880 #endif
3881
3882 /* Apparently need to set viewport for passes
3883 * when we aren't using FBOs. */
3884 gl2_set_shader_viewports(gl);
3885
3886 mip_level = 1;
3887 gl->tex_mipmap = gl->shader->mipmap_input(gl->shader_data, mip_level);
3888
3889 if (gl->shader->filter_type(gl->shader_data,
3890 1, &force_smooth))
3891 gl->tex_min_filter = gl->tex_mipmap ? (force_smooth ?
3892 GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST)
3893 : (force_smooth ? GL_LINEAR : GL_NEAREST);
3894 else
3895 gl->tex_min_filter = gl->tex_mipmap ?
3896 (video->smooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST)
3897 : (video->smooth ? GL_LINEAR : GL_NEAREST);
3898
3899 gl->tex_mag_filter = gl2_min_filter_to_mag(gl->tex_min_filter);
3900
3901 wrap_type = gl->shader->wrap_type(
3902 gl->shader_data, 1);
3903
3904 gl->wrap_mode = gl2_wrap_type_to_enum(wrap_type);
3905
3906 gl2_set_texture_fmts(gl, video->rgb32);
3907
3908 memcpy(gl->tex_info.coord, tex_coords, sizeof(gl->tex_info.coord));
3909 gl->coords.vertex = gl->vertex_ptr;
3910 gl->coords.tex_coord = gl->tex_info.coord;
3911 gl->coords.color = gl->white_color_ptr;
3912 gl->coords.lut_tex_coord = tex_coords;
3913 gl->coords.vertices = 4;
3914
3915 /* Empty buffer that we use to clear out
3916 * the texture with on res change. */
3917 gl->empty_buf = calloc(sizeof(uint32_t), gl->tex_w * gl->tex_h);
3918
3919 gl->conv_buffer = calloc(sizeof(uint32_t), gl->tex_w * gl->tex_h);
3920
3921 if (!gl->conv_buffer)
3922 goto error;
3923
3924 gl2_init_textures(gl);
3925 gl2_init_textures_data(gl);
3926
3927 gl2_renderchain_init(gl,
3928 (gl2_renderchain_data_t*)gl->renderchain_data,
3929 gl->tex_w, gl->tex_h);
3930
3931 if (gl->has_fbo)
3932 {
3933 if (gl->hw_render_use &&
3934 !gl2_renderchain_init_hw_render(gl, (gl2_renderchain_data_t*)gl->renderchain_data, gl->tex_w, gl->tex_h))
3935 {
3936 RARCH_ERR("[GL]: Hardware rendering context initialization failed.\n");
3937 goto error;
3938 }
3939 }
3940
3941 if (gl->ctx_driver->input_driver)
3942 {
3943 const char *joypad_name = settings->arrays.input_joypad_driver;
3944 gl->ctx_driver->input_driver(
3945 gl->ctx_data, joypad_name,
3946 input, input_data);
3947 }
3948
3949 if (video->font_enable)
3950 font_driver_init_osd(gl, video,
3951 false,
3952 video->is_threaded,
3953 FONT_DRIVER_RENDER_OPENGL_API);
3954
3955 /* Only bother with PBO readback if we're doing GPU recording.
3956 * Check recording_is_enabled() and not
3957 * driver.recording_data, because recording is
3958 * not initialized yet.
3959 */
3960 gl->pbo_readback_enable = video_gpu_record
3961 && recording_is_enabled();
3962
3963 if (gl->pbo_readback_enable && gl2_init_pbo_readback(gl))
3964 {
3965 RARCH_LOG("[GL]: Async PBO readback enabled.\n");
3966 }
3967
3968 if (!gl_check_error(&error_string))
3969 {
3970 RARCH_ERR("[GL]: %s\n", error_string);
3971 free(error_string);
3972 goto error;
3973 }
3974
3975 #ifdef HAVE_VIDEO_LAYOUT
3976 gl2_video_layout_init(gl);
3977 #endif
3978
3979 gl2_context_bind_hw_render(gl, true);
3980
3981 return gl;
3982
3983 error:
3984 video_context_driver_destroy();
3985 gl2_destroy_resources(gl);
3986 return NULL;
3987 }
3988
gl2_alive(void * data)3989 static bool gl2_alive(void *data)
3990 {
3991 bool ret = false;
3992 bool quit = false;
3993 bool resize = false;
3994 gl_t *gl = (gl_t*)data;
3995 unsigned temp_width = gl->video_width;
3996 unsigned temp_height = gl->video_height;
3997
3998 gl->ctx_driver->check_window(gl->ctx_data,
3999 &quit, &resize, &temp_width, &temp_height);
4000
4001 if (quit)
4002 gl->quitting = true;
4003 else if (resize)
4004 gl->should_resize = true;
4005
4006 ret = !gl->quitting;
4007
4008 if (temp_width != 0 && temp_height != 0)
4009 {
4010 video_driver_set_size(temp_width, temp_height);
4011 gl->video_width = temp_width;
4012 gl->video_height = temp_height;
4013 }
4014
4015 return ret;
4016 }
4017
gl2_suppress_screensaver(void * data,bool enable)4018 static bool gl2_suppress_screensaver(void *data, bool enable)
4019 {
4020 bool enabled = enable;
4021 gl_t *gl = (gl_t*)data;
4022
4023 if (gl->ctx_data && gl->ctx_driver->suppress_screensaver)
4024 return gl->ctx_driver->suppress_screensaver(gl->ctx_data, enabled);
4025 return false;
4026 }
4027
gl2_update_tex_filter_frame(gl_t * gl)4028 static void gl2_update_tex_filter_frame(gl_t *gl)
4029 {
4030 unsigned i, mip_level;
4031 GLenum wrap_mode;
4032 GLuint new_filt;
4033 enum gfx_wrap_type wrap_type;
4034 bool smooth = false;
4035 settings_t *settings = config_get_ptr();
4036 bool video_smooth = settings->bools.video_smooth;
4037 #ifdef HAVE_ODROIDGO2
4038 bool video_ctx_scaling = settings->bools.video_ctx_scaling;
4039 if (video_ctx_scaling)
4040 video_smooth = false;
4041 #endif
4042
4043 gl2_context_bind_hw_render(gl, false);
4044
4045 if (!gl->shader->filter_type(gl->shader_data,
4046 1, &smooth))
4047 smooth = video_smooth;
4048
4049 mip_level = 1;
4050 wrap_type = gl->shader->wrap_type(gl->shader_data, 1);
4051 wrap_mode = gl2_wrap_type_to_enum(wrap_type);
4052 gl->tex_mipmap = gl->shader->mipmap_input(gl->shader_data, mip_level);
4053 gl->video_info.smooth = smooth;
4054 new_filt = gl->tex_mipmap ? (smooth ?
4055 GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST)
4056 : (smooth ? GL_LINEAR : GL_NEAREST);
4057
4058 if (new_filt == gl->tex_min_filter && wrap_mode == gl->wrap_mode)
4059 return;
4060
4061 gl->tex_min_filter = new_filt;
4062 gl->tex_mag_filter = gl2_min_filter_to_mag(gl->tex_min_filter);
4063 gl->wrap_mode = wrap_mode;
4064
4065 for (i = 0; i < gl->textures; i++)
4066 {
4067 if (!gl->texture[i])
4068 continue;
4069
4070 GL_BIND_TEXTURE(gl->texture[i], gl->wrap_mode, gl->tex_mag_filter,
4071 gl->tex_min_filter);
4072 }
4073
4074 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
4075 gl2_context_bind_hw_render(gl, true);
4076 }
4077
gl2_set_shader(void * data,enum rarch_shader_type type,const char * path)4078 static bool gl2_set_shader(void *data,
4079 enum rarch_shader_type type, const char *path)
4080 {
4081 #if defined(HAVE_GLSL) || defined(HAVE_CG)
4082 unsigned textures;
4083 video_shader_ctx_init_t init_data;
4084 enum rarch_shader_type fallback;
4085 gl_t *gl = (gl_t*)data;
4086
4087 if (!gl)
4088 return false;
4089
4090 gl2_context_bind_hw_render(gl, false);
4091
4092 fallback = gl2_get_fallback_shader_type(type);
4093
4094 if (fallback == RARCH_SHADER_NONE)
4095 {
4096 RARCH_ERR("[GL]: No supported shader backend found!\n");
4097 goto error;
4098 }
4099
4100 gl->shader->deinit(gl->shader_data);
4101 gl->shader_data = NULL;
4102
4103 if (type != fallback)
4104 {
4105 RARCH_ERR("[GL]: %s shader not supported, falling back to stock %s\n",
4106 video_shader_type_to_str(type), video_shader_type_to_str(fallback));
4107 path = NULL;
4108 }
4109
4110 if (gl->fbo_inited)
4111 {
4112 gl2_renderchain_deinit_fbo(gl,
4113 (gl2_renderchain_data_t*)gl->renderchain_data);
4114
4115 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
4116 }
4117
4118 init_data.shader_type = fallback;
4119 init_data.path = path;
4120 init_data.shader = NULL;
4121 init_data.data = gl;
4122 init_data.shader_data = NULL;
4123 init_data.gl.core_context_enabled = false;
4124
4125 if (!gl_shader_driver_init(&init_data))
4126 {
4127 init_data.path = NULL;
4128
4129 gl_shader_driver_init(&init_data);
4130
4131 gl->shader = init_data.shader;
4132 gl->shader_data = init_data.shader_data;
4133
4134 RARCH_WARN("[GL]: Failed to set multipass shader. Falling back to stock.\n");
4135
4136 goto error;
4137 }
4138
4139 gl->shader = init_data.shader;
4140 gl->shader_data = init_data.shader_data;
4141
4142 gl2_update_tex_filter_frame(gl);
4143
4144 {
4145 unsigned texture_info_id = gl->shader->get_prev_textures(gl->shader_data);
4146 textures = texture_info_id + 1;
4147 }
4148
4149 if (textures > gl->textures) /* Have to reinit a bit. */
4150 {
4151 if (gl->hw_render_use && gl->fbo_inited)
4152 gl2_renderchain_deinit_hw_render(gl, (gl2_renderchain_data_t*)
4153 gl->renderchain_data);
4154
4155 glDeleteTextures(gl->textures, gl->texture);
4156 #if defined(HAVE_PSGL)
4157 glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0);
4158 glDeleteBuffers(1, &gl->pbo);
4159 #endif
4160 gl->textures = textures;
4161 gl->tex_index = 0;
4162 RARCH_LOG("[GL]: Using %u textures.\n", gl->textures);
4163 gl2_init_textures(gl);
4164 gl2_init_textures_data(gl);
4165
4166 if (gl->hw_render_use)
4167 gl2_renderchain_init_hw_render(gl,
4168 (gl2_renderchain_data_t*)gl->renderchain_data,
4169 gl->tex_w, gl->tex_h);
4170 }
4171
4172 gl2_renderchain_init(gl,
4173 (gl2_renderchain_data_t*)gl->renderchain_data,
4174 gl->tex_w, gl->tex_h);
4175
4176 /* Apparently need to set viewport for passes when we aren't using FBOs. */
4177 gl2_set_shader_viewports(gl);
4178 gl2_context_bind_hw_render(gl, true);
4179
4180 return true;
4181
4182 error:
4183 gl2_context_bind_hw_render(gl, true);
4184 #endif
4185 return false;
4186 }
4187
gl2_viewport_info(void * data,struct video_viewport * vp)4188 static void gl2_viewport_info(void *data, struct video_viewport *vp)
4189 {
4190 unsigned top_y, top_dist;
4191 gl_t *gl = (gl_t*)data;
4192 unsigned width = gl->video_width;
4193 unsigned height = gl->video_height;
4194
4195 *vp = gl->vp;
4196 vp->full_width = width;
4197 vp->full_height = height;
4198
4199 /* Adjust as GL viewport is bottom-up. */
4200 top_y = vp->y + vp->height;
4201 top_dist = height - top_y;
4202 vp->y = top_dist;
4203 }
4204
gl2_read_viewport(void * data,uint8_t * buffer,bool is_idle)4205 static bool gl2_read_viewport(void *data, uint8_t *buffer, bool is_idle)
4206 {
4207 gl_t *gl = (gl_t*)data;
4208
4209 if (!gl)
4210 return false;
4211
4212 return gl2_renderchain_read_viewport(gl, buffer, is_idle);
4213 }
4214
4215 #if 0
4216 #define READ_RAW_GL_FRAME_TEST
4217 #endif
4218
4219 #if defined(READ_RAW_GL_FRAME_TEST)
gl2_read_frame_raw(void * data,unsigned * width_p,unsigned * height_p,size_t * pitch_p)4220 static void* gl2_read_frame_raw(void *data, unsigned *width_p,
4221 unsigned *height_p, size_t *pitch_p)
4222 {
4223 gl_t *gl = (gl_t*)data;
4224 unsigned width = gl->last_width[gl->tex_index];
4225 unsigned height = gl->last_height[gl->tex_index];
4226 size_t pitch = gl->tex_w * gl->base_size;
4227 void* buffer = NULL;
4228 void* buffer_texture = NULL;
4229
4230 if (gl->hw_render_use)
4231 {
4232 buffer = malloc(pitch * height);
4233 if (!buffer)
4234 return NULL;
4235 }
4236
4237 buffer_texture = malloc(pitch * gl->tex_h);
4238
4239 if (!buffer_texture)
4240 {
4241 if (buffer)
4242 free(buffer);
4243 return NULL;
4244 }
4245
4246 glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
4247 glGetTexImage(GL_TEXTURE_2D, 0,
4248 gl->texture_type, gl->texture_fmt, buffer_texture);
4249
4250 *width_p = width;
4251 *height_p = height;
4252 *pitch_p = pitch;
4253
4254 if (gl->hw_render_use)
4255 {
4256 unsigned i;
4257
4258 for (i = 0; i < height ; i++)
4259 memcpy((uint8_t*)buffer + i * pitch,
4260 (uint8_t*)buffer_texture + (height - 1 - i) * pitch, pitch);
4261
4262 free(buffer_texture);
4263 return buffer;
4264 }
4265
4266 return buffer_texture;
4267 }
4268 #endif
4269
4270 #ifdef HAVE_OVERLAY
gl2_overlay_load(void * data,const void * image_data,unsigned num_images)4271 static bool gl2_overlay_load(void *data,
4272 const void *image_data, unsigned num_images)
4273 {
4274 unsigned i, j;
4275 gl_t *gl = (gl_t*)data;
4276 const struct texture_image *images =
4277 (const struct texture_image*)image_data;
4278
4279 if (!gl)
4280 return false;
4281
4282 gl2_context_bind_hw_render(gl, false);
4283
4284 gl2_free_overlay(gl);
4285 gl->overlay_tex = (GLuint*)
4286 calloc(num_images, sizeof(*gl->overlay_tex));
4287
4288 if (!gl->overlay_tex)
4289 {
4290 gl2_context_bind_hw_render(gl, true);
4291 return false;
4292 }
4293
4294 gl->overlay_vertex_coord = (GLfloat*)
4295 calloc(2 * 4 * num_images, sizeof(GLfloat));
4296 gl->overlay_tex_coord = (GLfloat*)
4297 calloc(2 * 4 * num_images, sizeof(GLfloat));
4298 gl->overlay_color_coord = (GLfloat*)
4299 calloc(4 * 4 * num_images, sizeof(GLfloat));
4300
4301 if ( !gl->overlay_vertex_coord
4302 || !gl->overlay_tex_coord
4303 || !gl->overlay_color_coord)
4304 return false;
4305
4306 gl->overlays = num_images;
4307 glGenTextures(num_images, gl->overlay_tex);
4308
4309 for (i = 0; i < num_images; i++)
4310 {
4311 unsigned alignment = gl2_get_alignment(images[i].width
4312 * sizeof(uint32_t));
4313
4314 gl_load_texture_data(gl->overlay_tex[i],
4315 RARCH_WRAP_EDGE, TEXTURE_FILTER_LINEAR,
4316 alignment,
4317 images[i].width, images[i].height, images[i].pixels,
4318 sizeof(uint32_t));
4319
4320 /* Default. Stretch to whole screen. */
4321 gl2_overlay_tex_geom(gl, i, 0, 0, 1, 1);
4322 gl2_overlay_vertex_geom(gl, i, 0, 0, 1, 1);
4323
4324 for (j = 0; j < 16; j++)
4325 gl->overlay_color_coord[16 * i + j] = 1.0f;
4326 }
4327
4328 gl2_context_bind_hw_render(gl, true);
4329 return true;
4330 }
4331
gl2_overlay_enable(void * data,bool state)4332 static void gl2_overlay_enable(void *data, bool state)
4333 {
4334 gl_t *gl = (gl_t*)data;
4335
4336 if (!gl)
4337 return;
4338
4339 gl->overlay_enable = state;
4340
4341 if (gl->fullscreen && gl->ctx_driver->show_mouse)
4342 gl->ctx_driver->show_mouse(gl->ctx_data, state);
4343 }
4344
gl2_overlay_full_screen(void * data,bool enable)4345 static void gl2_overlay_full_screen(void *data, bool enable)
4346 {
4347 gl_t *gl = (gl_t*)data;
4348
4349 if (gl)
4350 gl->overlay_full_screen = enable;
4351 }
4352
gl2_overlay_set_alpha(void * data,unsigned image,float mod)4353 static void gl2_overlay_set_alpha(void *data, unsigned image, float mod)
4354 {
4355 GLfloat *color;
4356 gl_t *gl = (gl_t*)data;
4357
4358 if (!gl)
4359 return;
4360
4361 color = (GLfloat*)&gl->overlay_color_coord[image * 16];
4362
4363 color[ 0 + 3] = mod;
4364 color[ 4 + 3] = mod;
4365 color[ 8 + 3] = mod;
4366 color[12 + 3] = mod;
4367 }
4368
4369 static const video_overlay_interface_t gl2_overlay_interface = {
4370 gl2_overlay_enable,
4371 gl2_overlay_load,
4372 gl2_overlay_tex_geom,
4373 gl2_overlay_vertex_geom,
4374 gl2_overlay_full_screen,
4375 gl2_overlay_set_alpha,
4376 };
4377
gl2_get_overlay_interface(void * data,const video_overlay_interface_t ** iface)4378 static void gl2_get_overlay_interface(void *data,
4379 const video_overlay_interface_t **iface)
4380 {
4381 (void)data;
4382 *iface = &gl2_overlay_interface;
4383 }
4384 #endif
4385
gl2_get_proc_address(void * data,const char * sym)4386 static retro_proc_address_t gl2_get_proc_address(void *data, const char *sym)
4387 {
4388 gl_t *gl = (gl_t*)data;
4389
4390 if (gl && gl->ctx_driver->get_proc_address)
4391 return gl->ctx_driver->get_proc_address(sym);
4392
4393 return NULL;
4394 }
4395
gl2_set_aspect_ratio(void * data,unsigned aspect_ratio_idx)4396 static void gl2_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
4397 {
4398 gl_t *gl = (gl_t*)data;
4399
4400 if (!gl)
4401 return;
4402
4403 gl->keep_aspect = true;
4404 #if defined(HAVE_ODROIDGO2)
4405 if (config_get_ptr()->bools.video_ctx_scaling)
4406 gl->keep_aspect = false;
4407 #endif
4408 gl->should_resize = true;
4409 }
4410
gl2_apply_state_changes(void * data)4411 static void gl2_apply_state_changes(void *data)
4412 {
4413 gl_t *gl = (gl_t*)data;
4414
4415 if (gl)
4416 gl->should_resize = true;
4417 }
4418
gl2_get_video_output_size(void * data,unsigned * width,unsigned * height)4419 static void gl2_get_video_output_size(void *data,
4420 unsigned *width, unsigned *height)
4421 {
4422 gl_t *gl = (gl_t*)data;
4423 if (!gl || !gl->ctx_driver || !gl->ctx_driver->get_video_output_size)
4424 return;
4425 gl->ctx_driver->get_video_output_size(
4426 gl->ctx_data,
4427 width, height);
4428 }
4429
gl2_get_video_output_prev(void * data)4430 static void gl2_get_video_output_prev(void *data)
4431 {
4432 gl_t *gl = (gl_t*)data;
4433 if (!gl || !gl->ctx_driver || !gl->ctx_driver->get_video_output_prev)
4434 return;
4435 gl->ctx_driver->get_video_output_prev(gl->ctx_data);
4436 }
4437
gl2_get_video_output_next(void * data)4438 static void gl2_get_video_output_next(void *data)
4439 {
4440 gl_t *gl = (gl_t*)data;
4441 if (!gl || !gl->ctx_driver || !gl->ctx_driver->get_video_output_next)
4442 return;
4443 gl->ctx_driver->get_video_output_next(gl->ctx_data);
4444 }
4445
video_texture_load_gl2(struct texture_image * ti,enum texture_filter_type filter_type,uintptr_t * idptr)4446 static void video_texture_load_gl2(
4447 struct texture_image *ti,
4448 enum texture_filter_type filter_type,
4449 uintptr_t *idptr)
4450 {
4451 GLuint id;
4452 unsigned width = 0;
4453 unsigned height = 0;
4454 const void *pixels = NULL;
4455 /* Generate the OpenGL texture object */
4456 glGenTextures(1, &id);
4457 *idptr = id;
4458
4459 if (ti)
4460 {
4461 width = ti->width;
4462 height = ti->height;
4463 pixels = ti->pixels;
4464 }
4465
4466 gl_load_texture_data(id,
4467 RARCH_WRAP_EDGE, filter_type,
4468 4 /* TODO/FIXME - dehardcode */,
4469 width, height, pixels,
4470 sizeof(uint32_t) /* TODO/FIXME - dehardcode */
4471 );
4472 }
4473
4474 #ifdef HAVE_THREADS
video_texture_load_wrap_gl2_mipmap(void * data)4475 static int video_texture_load_wrap_gl2_mipmap(void *data)
4476 {
4477 uintptr_t id = 0;
4478
4479 if (!data)
4480 return 0;
4481 video_texture_load_gl2((struct texture_image*)data,
4482 TEXTURE_FILTER_MIPMAP_LINEAR, &id);
4483 return (int)id;
4484 }
4485
video_texture_load_wrap_gl2(void * data)4486 static int video_texture_load_wrap_gl2(void *data)
4487 {
4488 uintptr_t id = 0;
4489
4490 if (!data)
4491 return 0;
4492 video_texture_load_gl2((struct texture_image*)data,
4493 TEXTURE_FILTER_LINEAR, &id);
4494 return (int)id;
4495 }
4496 #endif
4497
gl2_load_texture(void * video_data,void * data,bool threaded,enum texture_filter_type filter_type)4498 static uintptr_t gl2_load_texture(void *video_data, void *data,
4499 bool threaded, enum texture_filter_type filter_type)
4500 {
4501 uintptr_t id = 0;
4502
4503 #ifdef HAVE_THREADS
4504 if (threaded)
4505 {
4506 gl_t *gl = (gl_t*)video_data;
4507 custom_command_method_t func = video_texture_load_wrap_gl2;
4508
4509 if (gl->ctx_driver->make_current)
4510 gl->ctx_driver->make_current(false);
4511
4512 switch (filter_type)
4513 {
4514 case TEXTURE_FILTER_MIPMAP_LINEAR:
4515 case TEXTURE_FILTER_MIPMAP_NEAREST:
4516 func = video_texture_load_wrap_gl2_mipmap;
4517 break;
4518 default:
4519 break;
4520 }
4521 return video_thread_texture_load(data, func);
4522 }
4523 #endif
4524
4525 video_texture_load_gl2((struct texture_image*)data, filter_type, &id);
4526 return id;
4527 }
4528
gl2_unload_texture(void * data,bool threaded,uintptr_t id)4529 static void gl2_unload_texture(void *data,
4530 bool threaded, uintptr_t id)
4531 {
4532 GLuint glid;
4533 if (!id)
4534 return;
4535
4536 #ifdef HAVE_THREADS
4537 if (threaded)
4538 {
4539 gl_t *gl = (gl_t*)data;
4540 if (gl && gl->ctx_driver)
4541 if (gl->ctx_driver->make_current)
4542 gl->ctx_driver->make_current(false);
4543 }
4544 #endif
4545
4546 glid = (GLuint)id;
4547 glDeleteTextures(1, &glid);
4548 }
4549
gl2_get_refresh_rate(void * data)4550 static float gl2_get_refresh_rate(void *data)
4551 {
4552 float refresh_rate = 0.0f;
4553 if (video_context_driver_get_refresh_rate(&refresh_rate))
4554 return refresh_rate;
4555 return 0.0f;
4556 }
4557
gl2_get_flags(void * data)4558 static uint32_t gl2_get_flags(void *data)
4559 {
4560 uint32_t flags = 0;
4561
4562 BIT32_SET(flags, GFX_CTX_FLAGS_HARD_SYNC);
4563 BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
4564 BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
4565 BIT32_SET(flags, GFX_CTX_FLAGS_SCREENSHOTS_SUPPORTED);
4566
4567 return flags;
4568 }
4569
4570 static const video_poke_interface_t gl2_poke_interface = {
4571 gl2_get_flags,
4572 gl2_load_texture,
4573 gl2_unload_texture,
4574 gl2_set_video_mode,
4575 gl2_get_refresh_rate,
4576 NULL,
4577 gl2_get_video_output_size,
4578 gl2_get_video_output_prev,
4579 gl2_get_video_output_next,
4580 gl2_get_current_framebuffer,
4581 gl2_get_proc_address,
4582 gl2_set_aspect_ratio,
4583 gl2_apply_state_changes,
4584 gl2_set_texture_frame,
4585 gl2_set_texture_enable,
4586 font_driver_render_msg,
4587 gl2_show_mouse,
4588 NULL,
4589 gl2_get_current_shader,
4590 NULL, /* get_current_software_framebuffer */
4591 NULL /* get_hw_render_interface */
4592 };
4593
gl2_get_poke_interface(void * data,const video_poke_interface_t ** iface)4594 static void gl2_get_poke_interface(void *data,
4595 const video_poke_interface_t **iface)
4596 {
4597 (void)data;
4598 *iface = &gl2_poke_interface;
4599 }
4600
4601 #ifdef HAVE_GFX_WIDGETS
gl2_gfx_widgets_enabled(void * data)4602 static bool gl2_gfx_widgets_enabled(void *data)
4603 {
4604 (void)data;
4605 return true;
4606 }
4607 #endif
4608
gl2_has_windowed(void * data)4609 static bool gl2_has_windowed(void *data)
4610 {
4611 gl_t *gl = (gl_t*)data;
4612 if (gl && gl->ctx_driver)
4613 return gl->ctx_driver->has_windowed;
4614 return false;
4615 }
4616
gl2_focus(void * data)4617 static bool gl2_focus(void *data)
4618 {
4619 gl_t *gl = (gl_t*)data;
4620 if (gl && gl->ctx_driver && gl->ctx_driver->has_focus)
4621 return gl->ctx_driver->has_focus(gl->ctx_data);
4622 return true;
4623 }
4624
4625 video_driver_t video_gl2 = {
4626 gl2_init,
4627 gl2_frame,
4628 gl2_set_nonblock_state,
4629 gl2_alive,
4630 gl2_focus,
4631 gl2_suppress_screensaver,
4632 gl2_has_windowed,
4633
4634 gl2_set_shader,
4635
4636 gl2_free,
4637 "gl",
4638
4639 gl2_set_viewport_wrapper,
4640 gl2_set_rotation,
4641
4642 gl2_viewport_info,
4643
4644 gl2_read_viewport,
4645 #if defined(READ_RAW_GL_FRAME_TEST)
4646 gl2_read_frame_raw,
4647 #else
4648 NULL,
4649 #endif
4650
4651 #ifdef HAVE_OVERLAY
4652 gl2_get_overlay_interface,
4653 #endif
4654 #ifdef HAVE_VIDEO_LAYOUT
4655 gl2_get_video_layout_render_interface,
4656 #endif
4657 gl2_get_poke_interface,
4658 gl2_wrap_type_to_enum,
4659 #ifdef HAVE_GFX_WIDGETS
4660 gl2_gfx_widgets_enabled
4661 #endif
4662 };
4663