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(&params, 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(&params, 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(&params, 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