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) 2016-2019 - Brad Parker
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 /* OpenGL driver.
19  *
20  * We are targeting a minimum of OpenGL 1.1 and the Microsoft "GDI Generic" software GL implementation.
21  * Any additional features added for later 1.x versions should only be enabled if they are detected at runtime. */
22 
23 #include <stddef.h>
24 #include <retro_miscellaneous.h>
25 #include <formats/image.h>
26 #include <string/stdstring.h>
27 #include <retro_math.h>
28 #include <gfx/video_frame.h>
29 #include <gfx/scaler/pixconv.h>
30 
31 #ifdef HAVE_CONFIG_H
32 #include "../../config.h"
33 #endif
34 
35 #ifdef HAVE_MENU
36 #include "../../menu/menu_driver.h"
37 #endif
38 #ifdef HAVE_GFX_WIDGETS
39 #include "../gfx_widgets.h"
40 #endif
41 
42 #include "../font_driver.h"
43 
44 #include "../../driver.h"
45 #include "../../configuration.h"
46 #include "../../retroarch.h"
47 #include "../../verbosity.h"
48 #include "../../frontend/frontend_driver.h"
49 #include "../common/gl1_common.h"
50 
51 #if defined(_WIN32) && !defined(_XBOX)
52 #include "../common/win32_common.h"
53 #endif
54 
55 #ifdef HAVE_THREADS
56 #include "../video_thread_wrapper.h"
57 #endif
58 
59 #ifdef VITA
60 #include <defines/psp_defines.h>
61 static bool vgl_inited = false;
62 #endif
63 
64 static struct video_ortho gl1_default_ortho = {0, 1, 0, 1, -1, 1};
65 
66 /* Used for the last pass when rendering to the back buffer. */
67 static const GLfloat gl1_vertexes_flipped[] = {
68    0, 1,
69    1, 1,
70    0, 0,
71    1, 0
72 };
73 
74 static const GLfloat gl1_vertexes[] = {
75    0, 0,
76    1, 0,
77    0, 1,
78    1, 1
79 };
80 
81 static const GLfloat gl1_tex_coords[] = {
82    0, 0,
83    1, 0,
84    0, 1,
85    1, 1
86 };
87 
88 static const GLfloat gl1_white_color[] = {
89    1, 1, 1, 1,
90    1, 1, 1, 1,
91    1, 1, 1, 1,
92    1, 1, 1, 1,
93 };
94 
95 #define gl1_context_bind_hw_render(gl1, enable) \
96    if (gl1->shared_context_use) \
97       gl1->ctx_driver->bind_hw_render(gl1->ctx_data, enable)
98 
99 #ifdef HAVE_OVERLAY
gl1_render_overlay(gl1_t * gl,unsigned width,unsigned height)100 static void gl1_render_overlay(gl1_t *gl,
101       unsigned width,
102       unsigned height)
103 {
104    unsigned i;
105 
106    glEnable(GL_BLEND);
107 
108    if (gl->overlay_full_screen)
109       glViewport(0, 0, width, height);
110 
111    gl->coords.vertex    = gl->overlay_vertex_coord;
112    gl->coords.tex_coord = gl->overlay_tex_coord;
113    gl->coords.color     = gl->overlay_color_coord;
114    gl->coords.vertices  = 4 * gl->overlays;
115 
116    glMatrixMode(GL_PROJECTION);
117    glPushMatrix();
118    glLoadIdentity();
119 
120    for (i = 0; i < gl->overlays; i++)
121    {
122       glBindTexture(GL_TEXTURE_2D, gl->overlay_tex[i]);
123       glDrawArrays(GL_TRIANGLE_STRIP, 4 * i, 4);
124    }
125 
126    glDisable(GL_BLEND);
127    gl->coords.vertex    = gl->vertex_ptr;
128    gl->coords.tex_coord = gl->tex_info.coord;
129    gl->coords.color     = gl->white_color_ptr;
130    gl->coords.vertices  = 4;
131    if (gl->overlay_full_screen)
132       glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
133 }
134 
gl1_free_overlay(gl1_t * gl)135 static void gl1_free_overlay(gl1_t *gl)
136 {
137    glDeleteTextures(gl->overlays, gl->overlay_tex);
138 
139    free(gl->overlay_tex);
140    free(gl->overlay_vertex_coord);
141    free(gl->overlay_tex_coord);
142    free(gl->overlay_color_coord);
143    gl->overlay_tex          = NULL;
144    gl->overlay_vertex_coord = NULL;
145    gl->overlay_tex_coord    = NULL;
146    gl->overlay_color_coord  = NULL;
147    gl->overlays             = 0;
148 }
149 
gl1_overlay_vertex_geom(void * data,unsigned image,float x,float y,float w,float h)150 static void gl1_overlay_vertex_geom(void *data,
151       unsigned image,
152       float x, float y,
153       float w, float h)
154 {
155    GLfloat *vertex = NULL;
156    gl1_t *gl        = (gl1_t*)data;
157 
158    if (!gl)
159       return;
160 
161    if (image > gl->overlays)
162    {
163       RARCH_ERR("[GL]: Invalid overlay id: %u\n", image);
164       return;
165    }
166 
167    vertex          = (GLfloat*)&gl->overlay_vertex_coord[image * 8];
168 
169    /* Flipped, so we preserve top-down semantics. */
170    y               = 1.0f - y;
171    h               = -h;
172 
173    vertex[0]       = x;
174    vertex[1]       = y;
175    vertex[2]       = x + w;
176    vertex[3]       = y;
177    vertex[4]       = x;
178    vertex[5]       = y + h;
179    vertex[6]       = x + w;
180    vertex[7]       = y + h;
181 }
182 
gl1_overlay_tex_geom(void * data,unsigned image,GLfloat x,GLfloat y,GLfloat w,GLfloat h)183 static void gl1_overlay_tex_geom(void *data,
184       unsigned image,
185       GLfloat x, GLfloat y,
186       GLfloat w, GLfloat h)
187 {
188    GLfloat *tex = NULL;
189    gl1_t *gl     = (gl1_t*)data;
190 
191    if (!gl)
192       return;
193 
194    tex          = (GLfloat*)&gl->overlay_tex_coord[image * 8];
195 
196    tex[0]       = x;
197    tex[1]       = y;
198    tex[2]       = x + w;
199    tex[3]       = y;
200    tex[4]       = x;
201    tex[5]       = y + h;
202    tex[6]       = x + w;
203    tex[7]       = y + h;
204 }
205 
206 #endif
207 
is_pot(unsigned x)208 static bool is_pot(unsigned x)
209 {
210    return (x & (x - 1)) == 0;
211 }
212 
get_pot(unsigned x)213 static unsigned get_pot(unsigned x)
214 {
215    return (is_pot(x) ? x : next_pow2(x));
216 }
217 
gl1_gfx_init(const video_info_t * video,input_driver_t ** input,void ** input_data)218 static void *gl1_gfx_init(const video_info_t *video,
219       input_driver_t **input, void **input_data)
220 {
221    unsigned full_x, full_y;
222    void *ctx_data                       = NULL;
223    const gfx_ctx_driver_t *ctx_driver   = NULL;
224    unsigned mode_width                  = 0;
225    unsigned mode_height                 = 0;
226    unsigned win_width = 0, win_height   = 0;
227    unsigned temp_width = 0, temp_height = 0;
228    settings_t *settings                 = config_get_ptr();
229    bool video_smooth                    = settings->bools.video_smooth;
230    bool video_font_enable               = settings->bools.video_font_enable;
231    const char *video_context_driver     = settings->arrays.video_context_driver;
232    gl1_t *gl1                           = (gl1_t*)calloc(1, sizeof(*gl1));
233    const char *vendor                   = NULL;
234    const char *renderer                 = NULL;
235    const char *version                  = NULL;
236    const char *extensions               = NULL;
237    int interval                         = 0;
238    struct retro_hw_render_callback *hwr = NULL;
239 
240    if (!gl1)
241       return NULL;
242 
243    *input                               = NULL;
244    *input_data                          = NULL;
245 
246    gl1->video_width                     = video->width;
247    gl1->video_height                    = video->height;
248    gl1->rgb32                           = video->rgb32;
249 
250    gl1->video_bits                      = video->rgb32 ? 32 : 16;
251 
252    if (video->rgb32)
253       gl1->video_pitch                  = video->width * 4;
254    else
255       gl1->video_pitch                  = video->width * 2;
256 
257    ctx_driver = video_context_driver_init_first(gl1,
258          video_context_driver,
259          GFX_CTX_OPENGL_API, 1, 1, false, &ctx_data);
260 
261    if (!ctx_driver)
262       goto error;
263 
264    if (ctx_data)
265       gl1->ctx_data = ctx_data;
266 
267    gl1->ctx_driver  = ctx_driver;
268 
269    video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver);
270 
271    RARCH_LOG("[GL1]: Found GL1 context: %s\n", ctx_driver->ident);
272 
273    if (gl1->ctx_driver->get_video_size)
274       gl1->ctx_driver->get_video_size(gl1->ctx_data,
275                &mode_width, &mode_height);
276 
277    full_x      = mode_width;
278    full_y      = mode_height;
279    mode_width  = 0;
280    mode_height = 0;
281 #ifdef VITA
282    if (!vgl_inited)
283    {
284       vglInitExtended(0x1400000, full_x, full_y, RAM_THRESHOLD, SCE_GXM_MULTISAMPLE_4X);
285       vglUseVram(GL_TRUE);
286       vgl_inited = true;
287    }
288 #endif
289    /* Clear out potential error flags in case we use cached context. */
290    glGetError();
291 
292    if (string_is_equal(ctx_driver->ident, "null"))
293       goto error;
294 
295    RARCH_LOG("[GL1]: Detecting screen resolution %ux%u.\n", full_x, full_y);
296 
297    win_width   = video->width;
298    win_height  = video->height;
299 
300    if (video->fullscreen && (win_width == 0) && (win_height == 0))
301    {
302       win_width  = full_x;
303       win_height = full_y;
304    }
305 
306    mode_width      = win_width;
307    mode_height     = win_height;
308 
309    interval = video->swap_interval;
310 
311    if (ctx_driver->swap_interval)
312    {
313       bool adaptive_vsync_enabled            = video_driver_test_all_flags(
314             GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && video->adaptive_vsync;
315       if (adaptive_vsync_enabled && interval == 1)
316          interval = -1;
317       ctx_driver->swap_interval(gl1->ctx_data, interval);
318    }
319 
320    if (     !gl1->ctx_driver->set_video_mode
321          || !gl1->ctx_driver->set_video_mode(gl1->ctx_data,
322             win_width, win_height, video->fullscreen))
323       goto error;
324 
325    gl1->fullscreen = video->fullscreen;
326 
327    mode_width     = 0;
328    mode_height    = 0;
329 
330    if (gl1->ctx_driver->get_video_size)
331       gl1->ctx_driver->get_video_size(gl1->ctx_data,
332                &mode_width, &mode_height);
333 
334    temp_width     = mode_width;
335    temp_height    = mode_height;
336 
337    /* Get real known video size, which might have been altered by context. */
338 
339    if (temp_width != 0 && temp_height != 0)
340       video_driver_set_size(temp_width, temp_height);
341 
342    video_driver_get_size(&temp_width, &temp_height);
343 
344    RARCH_LOG("[GL1]: Using resolution %ux%u\n", temp_width, temp_height);
345 
346    vendor   = (const char*)glGetString(GL_VENDOR);
347    renderer = (const char*)glGetString(GL_RENDERER);
348    version  = (const char*)glGetString(GL_VERSION);
349    extensions = (const char*)glGetString(GL_EXTENSIONS);
350 
351    if (!string_is_empty(version))
352       sscanf(version, "%d.%d", &gl1->version_major, &gl1->version_minor);
353 
354    if (!string_is_empty(extensions))
355       gl1->extensions = string_split(extensions, " ");
356 
357    RARCH_LOG("[GL1]: Vendor: %s, Renderer: %s.\n", vendor, renderer);
358    RARCH_LOG("[GL1]: Version: %s.\n", version);
359    RARCH_LOG("[GL1]: Extensions: %s\n", extensions);
360 
361    {
362       char device_str[128];
363 
364       device_str[0] = '\0';
365 
366       if (!string_is_empty(vendor))
367       {
368          strlcpy(device_str, vendor, sizeof(device_str));
369          strlcat(device_str, " ", sizeof(device_str));
370       }
371 
372       if (!string_is_empty(renderer))
373          strlcat(device_str, renderer, sizeof(device_str));
374 
375       video_driver_set_gpu_device_string(device_str);
376 
377       if (!string_is_empty(version))
378          video_driver_set_gpu_api_version_string(version);
379    }
380 
381    if (gl1->ctx_driver->input_driver)
382    {
383       const char *joypad_name = settings->arrays.input_joypad_driver;
384       gl1->ctx_driver->input_driver(
385             gl1->ctx_data, joypad_name,
386             input, input_data);
387    }
388 
389    if (video_font_enable)
390       font_driver_init_osd(gl1,
391             video,
392             false,
393             video->is_threaded,
394             FONT_DRIVER_RENDER_OPENGL1_API);
395 
396    gl1->smooth        = video_smooth;
397    gl1->supports_bgra = string_list_find_elem(gl1->extensions, "GL_EXT_bgra");
398 
399    glDisable(GL_BLEND);
400    glDisable(GL_DEPTH_TEST);
401    glDisable(GL_CULL_FACE);
402    glDisable(GL_STENCIL_TEST);
403    glDisable(GL_SCISSOR_TEST);
404 #ifndef VITA
405    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
406 #endif
407    glGenTextures(1, &gl1->tex);
408    glGenTextures(1, &gl1->menu_tex);
409 
410    hwr = video_driver_get_hw_context();
411 
412    memcpy(gl1->tex_info.coord, gl1_tex_coords, sizeof(gl1->tex_info.coord));
413    gl1->vertex_ptr        = hwr->bottom_left_origin
414       ? gl1_vertexes : gl1_vertexes_flipped;
415    gl1->textures              = 4;
416    gl1->white_color_ptr       = gl1_white_color;
417    gl1->coords.vertex         = gl1->vertex_ptr;
418    gl1->coords.tex_coord      = gl1->tex_info.coord;
419    gl1->coords.color          = gl1->white_color_ptr;
420    gl1->coords.lut_tex_coord  = gl1_tex_coords;
421    gl1->coords.vertices       = 4;
422 
423    RARCH_LOG("[GL1]: Init complete.\n");
424 
425    return gl1;
426 
427 error:
428    video_context_driver_destroy();
429    if (gl1)
430    {
431       if (gl1->extensions)
432          string_list_free(gl1->extensions);
433       free(gl1);
434    }
435    return NULL;
436 }
437 
gl1_set_projection(gl1_t * gl1,struct video_ortho * ortho,bool allow_rotate)438 static void gl1_set_projection(gl1_t *gl1,
439       struct video_ortho *ortho, bool allow_rotate)
440 {
441    math_matrix_4x4 rot;
442 
443    /* Calculate projection. */
444    matrix_4x4_ortho(gl1->mvp_no_rot, ortho->left, ortho->right,
445          ortho->bottom, ortho->top, ortho->znear, ortho->zfar);
446 
447    if (!allow_rotate)
448    {
449       gl1->mvp = gl1->mvp_no_rot;
450       return;
451    }
452 
453    matrix_4x4_rotate_z(rot, M_PI * gl1->rotation / 180.0f);
454    matrix_4x4_multiply(gl1->mvp, rot, gl1->mvp_no_rot);
455 }
456 
gl1_gfx_set_viewport(gl1_t * gl1,unsigned viewport_width,unsigned viewport_height,bool force_full,bool allow_rotate)457 void gl1_gfx_set_viewport(gl1_t *gl1,
458       unsigned viewport_width,
459       unsigned viewport_height,
460       bool force_full, bool allow_rotate)
461 {
462    settings_t *settings     = config_get_ptr();
463    unsigned height          = gl1->video_height;
464    int x                    = 0;
465    int y                    = 0;
466    float device_aspect      = (float)viewport_width / viewport_height;
467 
468    if (gl1->ctx_driver->translate_aspect)
469       device_aspect         = gl1->ctx_driver->translate_aspect(
470             gl1->ctx_data, viewport_width, viewport_height);
471 
472    if (settings->bools.video_scale_integer && !force_full)
473    {
474       video_viewport_get_scaled_integer(&gl1->vp,
475             viewport_width, viewport_height,
476             video_driver_get_aspect_ratio(), gl1->keep_aspect);
477       viewport_width  = gl1->vp.width;
478       viewport_height = gl1->vp.height;
479    }
480    else if (gl1->keep_aspect && !force_full)
481    {
482       float desired_aspect = video_driver_get_aspect_ratio();
483 
484 #if defined(HAVE_MENU)
485       if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
486       {
487          const struct video_viewport *custom = video_viewport_get_custom();
488          /* GL has bottom-left origin viewport. */
489          x      = custom->x;
490          y      = height - custom->y - custom->height;
491          viewport_width  = custom->width;
492          viewport_height = custom->height;
493       }
494       else
495 #endif
496       {
497          float delta;
498 
499          if (fabsf(device_aspect - desired_aspect) < 0.0001f)
500          {
501             /* If the aspect ratios of screen and desired aspect
502              * ratio are sufficiently equal (floating point stuff),
503              * assume they are actually equal.
504              */
505          }
506          else if (device_aspect > desired_aspect)
507          {
508             delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
509             x     = (int)roundf(viewport_width * (0.5f - delta));
510             viewport_width = (unsigned)roundf(2.0f * viewport_width * delta);
511          }
512          else
513          {
514             delta  = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
515             y      = (int)roundf(viewport_height * (0.5f - delta));
516             viewport_height = (unsigned)roundf(2.0f * viewport_height * delta);
517          }
518       }
519 
520       gl1->vp.x      = x;
521       gl1->vp.y      = y;
522       gl1->vp.width  = viewport_width;
523       gl1->vp.height = viewport_height;
524    }
525    else
526    {
527       gl1->vp.x      = gl1->vp.y = 0;
528       gl1->vp.width  = viewport_width;
529       gl1->vp.height = viewport_height;
530    }
531 
532 #if defined(RARCH_MOBILE)
533    /* In portrait mode, we want viewport to gravitate to top of screen. */
534    if (device_aspect < 1.0f)
535       gl1->vp.y *= 2;
536 #endif
537 
538    glViewport(gl1->vp.x, gl1->vp.y, gl1->vp.width, gl1->vp.height);
539    gl1_set_projection(gl1, &gl1_default_ortho, allow_rotate);
540 
541    /* Set last backbuffer viewport. */
542    if (!force_full)
543    {
544       gl1->vp_out_width  = viewport_width;
545       gl1->vp_out_height = viewport_height;
546    }
547 
548 #if 0
549    RARCH_LOG("Setting viewport @ %ux%u\n", viewport_width, viewport_height);
550 #endif
551 }
552 
draw_tex(gl1_t * gl1,int pot_width,int pot_height,int width,int height,GLuint tex,const void * frame_to_copy)553 static void draw_tex(gl1_t *gl1, int pot_width, int pot_height, int width, int height, GLuint tex, const void *frame_to_copy)
554 {
555    uint8_t *frame       = NULL;
556    uint8_t *frame_rgba  = NULL;
557    /* FIXME: For now, everything is uploaded as BGRA8888, I could not get 444 or 555 to work, and there is no 565 support in GL 1.1 either. */
558    GLint internalFormat = GL_RGB8;
559    GLenum format        = gl1->supports_bgra ? GL_BGRA_EXT : GL_RGBA;
560    GLenum type          = GL_UNSIGNED_BYTE;
561 
562    float vertices[] = {
563 	   -1.0f, -1.0f, 0.0f,
564 	   -1.0f, 1.0f, 0.0f,
565 	   1.0f, -1.0f, 0.0f,
566 	   1.0f, 1.0f, 0.0f,
567    };
568 
569    float colors[] = {
570       1.0f, 1.0f, 1.0f, 1.0f,
571       1.0f, 1.0f, 1.0f, 1.0f,
572       1.0f, 1.0f, 1.0f, 1.0f,
573       1.0f, 1.0f, 1.0f, 1.0f
574    };
575 
576    float norm_width     = (1.0f / (float)pot_width) * (float)width;
577    float norm_height    = (1.0f / (float)pot_height) * (float)height;
578 
579    float texcoords[] = {
580       0.0f, 0.0f,
581       0.0f, 0.0f,
582       0.0f, 0.0f,
583       0.0f, 0.0f
584    };
585 
586    texcoords[1] = texcoords[5] = norm_height;
587    texcoords[4] = texcoords[6] = norm_width;
588 
589    glDisable(GL_DEPTH_TEST);
590    glDisable(GL_CULL_FACE);
591    glDisable(GL_STENCIL_TEST);
592    glDisable(GL_SCISSOR_TEST);
593    glEnable(GL_TEXTURE_2D);
594 
595    /* Multi-texture not part of GL 1.1 */
596    /*glActiveTexture(GL_TEXTURE0);*/
597 
598 #ifndef VITA
599    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
600    glPixelStorei(GL_UNPACK_ROW_LENGTH, pot_width);
601 #endif
602    glBindTexture(GL_TEXTURE_2D, tex);
603 
604    frame = (uint8_t*)frame_to_copy;
605    if (!gl1->supports_bgra)
606    {
607       frame_rgba = (uint8_t*)malloc(pot_width * pot_height * 4);
608       if (frame_rgba)
609       {
610          int x, y;
611          for (y = 0; y < pot_height; y++)
612          {
613             for (x = 0; x < pot_width; x++)
614             {
615                int index             = (y * pot_width + x) * 4;
616                frame_rgba[index + 2] = frame[index + 0];
617                frame_rgba[index + 1] = frame[index + 1];
618                frame_rgba[index + 0] = frame[index + 2];
619                frame_rgba[index + 3] = frame[index + 3];
620             }
621          }
622          frame = frame_rgba;
623       }
624    }
625 
626    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, pot_width, pot_height, 0, format, type, frame);
627    if (frame_rgba)
628        free(frame_rgba);
629 
630    if (tex == gl1->tex)
631    {
632       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (gl1->smooth ? GL_LINEAR : GL_NEAREST));
633       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (gl1->smooth ? GL_LINEAR : GL_NEAREST));
634    }
635    else if (tex == gl1->menu_tex)
636    {
637       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (gl1->menu_smooth ? GL_LINEAR : GL_NEAREST));
638       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (gl1->menu_smooth ? GL_LINEAR : GL_NEAREST));
639    }
640 
641    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
642    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
643 
644    glMatrixMode(GL_PROJECTION);
645    glPushMatrix();
646    glLoadIdentity();
647 
648    glMatrixMode(GL_MODELVIEW);
649    glPushMatrix();
650    glLoadIdentity();
651 
652    if (gl1->rotation && tex == gl1->tex)
653       glRotatef(gl1->rotation, 0.0f, 0.0f, 1.0f);
654 
655    glEnableClientState(GL_COLOR_ARRAY);
656    glEnableClientState(GL_VERTEX_ARRAY);
657    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
658 
659    glColorPointer(4, GL_FLOAT, 0, colors);
660    glVertexPointer(3, GL_FLOAT, 0, vertices);
661    glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
662 
663    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
664 
665    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
666    glDisableClientState(GL_VERTEX_ARRAY);
667    glDisableClientState(GL_COLOR_ARRAY);
668 
669    glMatrixMode(GL_MODELVIEW);
670    glPopMatrix();
671    glMatrixMode(GL_PROJECTION);
672    glPopMatrix();
673 }
674 
gl1_readback(gl1_t * gl1,unsigned alignment,unsigned fmt,unsigned type,void * src)675 static void gl1_readback(
676       gl1_t *gl1,
677       unsigned alignment,
678       unsigned fmt, unsigned type,
679       void *src)
680 {
681 #ifndef VITA
682    glPixelStorei(GL_PACK_ALIGNMENT, alignment);
683    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
684    glReadBuffer(GL_BACK);
685 #endif
686    glReadPixels(gl1->vp.x, gl1->vp.y,
687          gl1->vp.width, gl1->vp.height,
688          (GLenum)fmt, (GLenum)type, (GLvoid*)src);
689 }
690 
gl1_gfx_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)691 static bool gl1_gfx_frame(void *data, const void *frame,
692       unsigned frame_width, unsigned frame_height, uint64_t frame_count,
693       unsigned pitch, const char *msg, video_frame_info_t *video_info)
694 {
695    const void *frame_to_copy        = NULL;
696    unsigned mode_width              = 0;
697    unsigned mode_height             = 0;
698    unsigned width                   = video_info->width;
699    unsigned height                  = video_info->height;
700    bool draw                        = true;
701    bool do_swap                     = false;
702    gl1_t *gl1                       = (gl1_t*)data;
703    unsigned bits                    = gl1->video_bits;
704    unsigned pot_width               = 0;
705    unsigned pot_height              = 0;
706    unsigned video_width             = video_info->width;
707    unsigned video_height            = video_info->height;
708 #ifdef HAVE_MENU
709    bool menu_is_alive               = video_info->menu_is_alive;
710 #endif
711 #ifdef HAVE_GFX_WIDGETS
712    bool widgets_active              = video_info->widgets_active;
713 #endif
714    bool hard_sync                   = video_info->hard_sync;
715    struct font_params *osd_params   = (struct font_params*)
716       &video_info->osd_stat_params;
717 
718    /* FIXME: Force these settings off as they interfere with the rendering */
719    video_info->xmb_shadows_enable   = false;
720    video_info->menu_shader_pipeline = 0;
721 
722    gl1_context_bind_hw_render(gl1, false);
723 
724    if (gl1->should_resize)
725    {
726       gfx_ctx_mode_t mode;
727 
728       gl1->should_resize = false;
729 
730       mode.width        = width;
731       mode.height       = height;
732 
733       if (gl1->ctx_driver->set_resize)
734          gl1->ctx_driver->set_resize(gl1->ctx_data,
735                mode.width, mode.height);
736 
737       gl1_gfx_set_viewport(gl1,
738             video_width, video_height, false, true);
739    }
740 
741    if (  !frame || frame == RETRO_HW_FRAME_BUFFER_VALID || (
742          frame_width  == 4 &&
743          frame_height == 4 &&
744          (frame_width < width && frame_height < height))
745       )
746       draw = false;
747 
748    do_swap = frame || draw;
749 
750    if (  gl1->video_width  != frame_width  ||
751          gl1->video_height != frame_height ||
752          gl1->video_pitch  != pitch)
753    {
754       if (frame_width > 4 && frame_height > 4)
755       {
756          gl1->video_width  = frame_width;
757          gl1->video_height = frame_height;
758          gl1->video_pitch  = pitch;
759 
760          pot_width = get_pot(frame_width);
761          pot_height = get_pot(frame_height);
762 
763          if (draw)
764          {
765             if (gl1->video_buf)
766                free(gl1->video_buf);
767 
768             gl1->video_buf = (unsigned char*)malloc(pot_width * pot_height * 4);
769          }
770       }
771    }
772 
773    width         = gl1->video_width;
774    height        = gl1->video_height;
775    pitch         = gl1->video_pitch;
776 
777    pot_width = get_pot(width);
778    pot_height = get_pot(height);
779 
780    if (draw && gl1->video_buf)
781    {
782       if (bits == 32)
783       {
784          unsigned y;
785          /* copy lines into top-left portion of larger (power-of-two) buffer */
786          for (y = 0; y < height; y++)
787             memcpy(gl1->video_buf + ((pot_width * (bits / 8)) * y), (const unsigned char*)frame + (pitch * y), width * (bits / 8));
788       }
789       else if (bits == 16)
790          conv_rgb565_argb8888(gl1->video_buf, frame, width, height, pot_width * sizeof(unsigned), pitch);
791 
792       frame_to_copy = gl1->video_buf;
793    }
794 
795    if (gl1->video_width != width || gl1->video_height != height)
796    {
797       gl1->video_width  = width;
798       gl1->video_height = height;
799    }
800 
801    if (gl1->ctx_driver->get_video_size)
802       gl1->ctx_driver->get_video_size(gl1->ctx_data,
803                &mode_width, &mode_height);
804 
805    gl1->screen_width           = mode_width;
806    gl1->screen_height          = mode_height;
807 
808    if (draw)
809    {
810       glEnable(GL_BLEND);
811       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
812 
813       if (frame_to_copy)
814          draw_tex(gl1, pot_width, pot_height,
815                width, height, gl1->tex, frame_to_copy);
816    }
817 
818 #ifdef HAVE_MENU
819    if (gl1->menu_frame && menu_is_alive)
820    {
821       frame_to_copy = NULL;
822       width         = gl1->menu_width;
823       height        = gl1->menu_height;
824       pitch         = gl1->menu_pitch;
825       bits          = gl1->menu_bits;
826 
827       pot_width = get_pot(width);
828       pot_height = get_pot(height);
829 
830       do_swap = true;
831 
832       if (gl1->menu_size_changed)
833       {
834          gl1->menu_size_changed = false;
835 
836          if (gl1->menu_video_buf)
837             free(gl1->menu_video_buf);
838          gl1->menu_video_buf = NULL;
839       }
840 
841       if (!gl1->menu_video_buf)
842          gl1->menu_video_buf = (unsigned char*)
843             malloc(pot_width * pot_height * 4);
844 
845       if (bits == 16 && gl1->menu_video_buf)
846       {
847          conv_rgba4444_argb8888(gl1->menu_video_buf,
848                gl1->menu_frame, width, height,
849                pot_width * sizeof(unsigned), pitch);
850 
851          frame_to_copy = gl1->menu_video_buf;
852 
853          if (gl1->menu_texture_full_screen)
854          {
855             glViewport(0, 0, video_width, video_height);
856             draw_tex(gl1, pot_width, pot_height,
857                   width, height, gl1->menu_tex, frame_to_copy);
858             glViewport(gl1->vp.x, gl1->vp.y, gl1->vp.width, gl1->vp.height);
859          }
860          else
861             draw_tex(gl1, pot_width, pot_height,
862                   width, height, gl1->menu_tex, frame_to_copy);
863       }
864    }
865 
866    if (gl1->menu_texture_enable){
867       do_swap = true;
868 #ifdef VITA
869       glUseProgram(0);
870       bool enabled = glIsEnabled(GL_DEPTH_TEST);
871       if(enabled)
872          glDisable(GL_DEPTH_TEST);
873 #endif
874       menu_driver_frame(menu_is_alive, video_info);
875 #ifdef VITA
876       if(enabled)
877          glEnable(GL_DEPTH_TEST);
878 #endif
879    }
880    else
881 #endif
882       if (video_info->statistics_show)
883       {
884          if (osd_params)
885          {
886             font_driver_render_msg(gl1, video_info->stat_text,
887                   osd_params, NULL);
888 #if 0
889             osd_params->y               = 0.350f;
890             osd_params->scale           = 0.75f;
891             font_driver_render_msg(gl1, video_info->chat_text,
892                   (const struct font_params*)&video_info->osd_stat_params, NULL);
893 #endif
894          }
895       }
896 
897 #ifdef HAVE_GFX_WIDGETS
898    if (widgets_active)
899       gfx_widgets_frame(video_info);
900 #endif
901 
902 #ifdef HAVE_OVERLAY
903    if (gl1->overlay_enable)
904       gl1_render_overlay(gl1, video_width, video_height);
905 #endif
906 
907    if (msg)
908       font_driver_render_msg(gl1, msg, NULL, NULL);
909 
910    if (gl1->ctx_driver->update_window_title)
911       gl1->ctx_driver->update_window_title(
912             gl1->ctx_data);
913 
914    /* Screenshots. */
915    if (gl1->readback_buffer_screenshot)
916       gl1_readback(gl1,
917             4, GL_RGBA, GL_UNSIGNED_BYTE,
918             gl1->readback_buffer_screenshot);
919 
920 
921    if (do_swap && gl1->ctx_driver->swap_buffers)
922       gl1->ctx_driver->swap_buffers(gl1->ctx_data);
923 
924  /* Emscripten has to do black frame insertion in its main loop */
925 #ifndef EMSCRIPTEN
926    /* Disable BFI during fast forward, slow-motion,
927     * and pause to prevent flicker. */
928    if (
929          video_info->black_frame_insertion
930          && !video_info->input_driver_nonblock_state
931          && !video_info->runloop_is_slowmotion
932          && !video_info->runloop_is_paused
933          && !gl1->menu_texture_enable)
934    {
935 
936         unsigned n;
937         for (n = 0; n < video_info->black_frame_insertion; ++n)
938         {
939           glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
940           glClear(GL_COLOR_BUFFER_BIT);
941 
942           if (gl1->ctx_driver->swap_buffers)
943             gl1->ctx_driver->swap_buffers(gl1->ctx_data);
944         }
945    }
946 #endif
947 
948    /* check if we are fast forwarding or in menu, if we are ignore hard sync */
949    if (hard_sync
950          && !video_info->input_driver_nonblock_state
951          && !gl1->menu_texture_enable)
952    {
953       glClear(GL_COLOR_BUFFER_BIT);
954       glFinish();
955    }
956 
957    if(draw){
958       glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
959       glClear(GL_COLOR_BUFFER_BIT);
960    }
961 
962    gl1_context_bind_hw_render(gl1, true);
963 
964    return true;
965 }
966 
gl1_gfx_set_nonblock_state(void * data,bool state,bool adaptive_vsync_enabled,unsigned swap_interval)967 static void gl1_gfx_set_nonblock_state(void *data, bool state,
968       bool adaptive_vsync_enabled,
969       unsigned swap_interval)
970 {
971    int interval                = 0;
972    gl1_t             *gl1      = (gl1_t*)data;
973 
974    if (!gl1)
975       return;
976 
977    gl1_context_bind_hw_render(gl1, false);
978 
979    if (!state)
980       interval = swap_interval;
981 
982    if (gl1->ctx_driver->swap_interval)
983    {
984       if (adaptive_vsync_enabled && interval == 1)
985          interval = -1;
986       gl1->ctx_driver->swap_interval(gl1->ctx_data, interval);
987    }
988    gl1_context_bind_hw_render(gl1, true);
989 }
990 
gl1_gfx_alive(void * data)991 static bool gl1_gfx_alive(void *data)
992 {
993    unsigned temp_width  = 0;
994    unsigned temp_height = 0;
995    bool quit            = false;
996    bool resize          = false;
997    bool ret             = false;
998    gl1_t *gl1           = (gl1_t*)data;
999 
1000    /* Needed because some context drivers don't track their sizes */
1001    video_driver_get_size(&temp_width, &temp_height);
1002 
1003    gl1->ctx_driver->check_window(gl1->ctx_data,
1004             &quit, &resize, &temp_width, &temp_height);
1005 
1006    if (resize)
1007       gl1->should_resize = true;
1008 
1009    ret = !quit;
1010 
1011    if (temp_width != 0 && temp_height != 0)
1012       video_driver_set_size(temp_width, temp_height);
1013 
1014    return ret;
1015 }
1016 
gl1_gfx_focus(void * data)1017 static bool gl1_gfx_focus(void *data)
1018 {
1019    gl1_t *gl        = (gl1_t*)data;
1020    if (gl && gl->ctx_driver && gl->ctx_driver->has_focus)
1021       return gl->ctx_driver->has_focus(gl->ctx_data);
1022    return true;
1023 }
1024 
gl1_gfx_suppress_screensaver(void * data,bool enable)1025 static bool gl1_gfx_suppress_screensaver(void *data, bool enable)
1026 {
1027    (void)data;
1028    (void)enable;
1029    return false;
1030 }
1031 
gl1_gfx_free(void * data)1032 static void gl1_gfx_free(void *data)
1033 {
1034    gl1_t *gl1 = (gl1_t*)data;
1035 
1036    if (!gl1)
1037       return;
1038 
1039    gl1_context_bind_hw_render(gl1, false);
1040 
1041    if (gl1->menu_frame)
1042       free(gl1->menu_frame);
1043    gl1->menu_frame = NULL;
1044 
1045    if (gl1->video_buf)
1046       free(gl1->video_buf);
1047    gl1->video_buf = NULL;
1048 
1049    if (gl1->menu_video_buf)
1050       free(gl1->menu_video_buf);
1051    gl1->menu_video_buf = NULL;
1052 
1053    if (gl1->tex)
1054    {
1055       glDeleteTextures(1, &gl1->tex);
1056       gl1->tex = 0;
1057    }
1058 
1059    if (gl1->menu_tex)
1060    {
1061       glDeleteTextures(1, &gl1->menu_tex);
1062       gl1->menu_tex = 0;
1063    }
1064 
1065 #ifdef HAVE_OVERLAY
1066    gl1_free_overlay(gl1);
1067 #endif
1068 
1069    if (gl1->extensions)
1070       string_list_free(gl1->extensions);
1071    gl1->extensions = NULL;
1072 
1073    font_driver_free_osd();
1074    if (gl1->ctx_driver && gl1->ctx_driver->destroy)
1075       gl1->ctx_driver->destroy(gl1->ctx_data);
1076    video_context_driver_free();
1077    free(gl1);
1078 }
1079 
gl1_gfx_set_shader(void * data,enum rarch_shader_type type,const char * path)1080 static bool gl1_gfx_set_shader(void *data,
1081       enum rarch_shader_type type, const char *path)
1082 {
1083    (void)data;
1084    (void)type;
1085    (void)path;
1086 
1087    return false;
1088 }
1089 
gl1_gfx_set_rotation(void * data,unsigned rotation)1090 static void gl1_gfx_set_rotation(void *data,
1091       unsigned rotation)
1092 {
1093    gl1_t *gl1 = (gl1_t*)data;
1094 
1095    if (!gl1)
1096       return;
1097 
1098    gl1->rotation = 90 * rotation;
1099    gl1_set_projection(gl1, &gl1_default_ortho, true);
1100 }
1101 
gl1_gfx_viewport_info(void * data,struct video_viewport * vp)1102 static void gl1_gfx_viewport_info(void *data,
1103       struct video_viewport *vp)
1104 {
1105    unsigned width, height;
1106    unsigned top_y, top_dist;
1107    gl1_t *gl1             = (gl1_t*)data;
1108 
1109    video_driver_get_size(&width, &height);
1110 
1111    *vp             = gl1->vp;
1112    vp->full_width  = width;
1113    vp->full_height = height;
1114 
1115    /* Adjust as GL viewport is bottom-up. */
1116    top_y           = vp->y + vp->height;
1117    top_dist        = height - top_y;
1118    vp->y           = top_dist;
1119 }
1120 
gl1_gfx_read_viewport(void * data,uint8_t * buffer,bool is_idle)1121 static bool gl1_gfx_read_viewport(void *data, uint8_t *buffer, bool is_idle)
1122 {
1123    unsigned num_pixels = 0;
1124    gl1_t *gl1 = (gl1_t*)data;
1125 
1126    if (!gl1)
1127       return false;
1128 
1129    gl1_context_bind_hw_render(gl1, false);
1130 
1131    num_pixels = gl1->vp.width * gl1->vp.height;
1132 
1133    gl1->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t));
1134 
1135    if (!gl1->readback_buffer_screenshot)
1136       goto error;
1137 
1138    if (!is_idle)
1139       video_driver_cached_frame();
1140 
1141    video_frame_convert_rgba_to_bgr(
1142          (const void*)gl1->readback_buffer_screenshot,
1143          buffer,
1144          num_pixels);
1145 
1146    free(gl1->readback_buffer_screenshot);
1147    gl1->readback_buffer_screenshot = NULL;
1148 
1149    gl1_context_bind_hw_render(gl1, true);
1150    return true;
1151 
1152 error:
1153    gl1_context_bind_hw_render(gl1, true);
1154 
1155    return false;
1156 }
1157 
gl1_set_texture_frame(void * data,const void * frame,bool rgb32,unsigned width,unsigned height,float alpha)1158 static void gl1_set_texture_frame(void *data,
1159       const void *frame, bool rgb32, unsigned width, unsigned height,
1160       float alpha)
1161 {
1162    settings_t *settings    = config_get_ptr();
1163    bool menu_linear_filter = settings->bools.menu_linear_filter;
1164    unsigned       pitch    = width * 2;
1165    gl1_t              *gl1 = (gl1_t*)data;
1166 
1167    if (!gl1)
1168       return;
1169 
1170    gl1->menu_smooth        = menu_linear_filter;
1171 
1172    gl1_context_bind_hw_render(gl1, false);
1173 
1174    if (rgb32)
1175       pitch = width * 4;
1176 
1177    if (gl1->menu_frame)
1178       free(gl1->menu_frame);
1179    gl1->menu_frame = NULL;
1180 
1181    if ( !gl1->menu_frame            ||
1182          gl1->menu_width != width   ||
1183          gl1->menu_height != height ||
1184          gl1->menu_pitch != pitch)
1185    {
1186       if (pitch && height)
1187       {
1188          if (gl1->menu_frame)
1189             free(gl1->menu_frame);
1190 
1191          /* FIXME? We have to assume the pitch has no
1192           * extra padding in it because that will
1193           * mess up the POT calculation when we don't
1194           * know how many bpp there are. */
1195          gl1->menu_frame = (unsigned char*)malloc(pitch * height);
1196       }
1197    }
1198 
1199    if (gl1->menu_frame && frame && pitch && height)
1200    {
1201       memcpy(gl1->menu_frame, frame, pitch * height);
1202       gl1->menu_width        = width;
1203       gl1->menu_height       = height;
1204       gl1->menu_pitch        = pitch;
1205       gl1->menu_bits         = rgb32 ? 32 : 16;
1206       gl1->menu_size_changed = true;
1207    }
1208 
1209    gl1_context_bind_hw_render(gl1, true);
1210 }
1211 
gl1_get_video_output_size(void * data,unsigned * width,unsigned * height)1212 static void gl1_get_video_output_size(void *data,
1213       unsigned *width, unsigned *height)
1214 {
1215    gl1_t *gl         = (gl1_t*)data;
1216    if (!gl || !gl->ctx_driver || !gl->ctx_driver->get_video_output_size)
1217       return;
1218    gl->ctx_driver->get_video_output_size(
1219          gl->ctx_data,
1220          width, height);
1221 }
1222 
gl1_get_video_output_prev(void * data)1223 static void gl1_get_video_output_prev(void *data)
1224 {
1225    gl1_t *gl         = (gl1_t*)data;
1226    if (!gl || !gl->ctx_driver || !gl->ctx_driver->get_video_output_prev)
1227       return;
1228    gl->ctx_driver->get_video_output_prev(gl->ctx_data);
1229 }
1230 
gl1_get_video_output_next(void * data)1231 static void gl1_get_video_output_next(void *data)
1232 {
1233    gl1_t *gl         = (gl1_t*)data;
1234    if (!gl || !gl->ctx_driver || !gl->ctx_driver->get_video_output_next)
1235       return;
1236    gl->ctx_driver->get_video_output_next(gl->ctx_data);
1237 }
1238 
gl1_set_video_mode(void * data,unsigned width,unsigned height,bool fullscreen)1239 static void gl1_set_video_mode(void *data, unsigned width, unsigned height,
1240       bool fullscreen)
1241 {
1242    gl1_t               *gl = (gl1_t*)data;
1243    if (gl->ctx_driver->set_video_mode)
1244       gl->ctx_driver->set_video_mode(gl->ctx_data,
1245             width, height, fullscreen);
1246 }
1247 
gl1_wrap_type_to_enum(enum gfx_wrap_type type)1248 static unsigned gl1_wrap_type_to_enum(enum gfx_wrap_type type)
1249 {
1250    switch (type)
1251    {
1252       case RARCH_WRAP_REPEAT:
1253       case RARCH_WRAP_MIRRORED_REPEAT: /* mirrored not actually supported */
1254          return GL_REPEAT;
1255       default:
1256          return GL_CLAMP;
1257    }
1258 
1259    return 0;
1260 }
1261 
gl1_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)1262 static void gl1_load_texture_data(
1263       GLuint id,
1264       enum gfx_wrap_type wrap_type,
1265       enum texture_filter_type filter_type,
1266       unsigned alignment,
1267       unsigned width, unsigned height,
1268       const void *frame, unsigned base_size)
1269 {
1270    GLint mag_filter, min_filter;
1271    bool use_rgba    = video_driver_supports_rgba();
1272    bool rgb32       = (base_size == (sizeof(uint32_t)));
1273    GLenum wrap      = gl1_wrap_type_to_enum(wrap_type);
1274 
1275    /* GL1.x does not have mipmapping support. */
1276    switch (filter_type)
1277    {
1278       case TEXTURE_FILTER_MIPMAP_NEAREST:
1279       case TEXTURE_FILTER_NEAREST:
1280          min_filter = GL_NEAREST;
1281          mag_filter = GL_NEAREST;
1282          break;
1283       case TEXTURE_FILTER_MIPMAP_LINEAR:
1284       case TEXTURE_FILTER_LINEAR:
1285       default:
1286          min_filter = GL_LINEAR;
1287          mag_filter = GL_LINEAR;
1288          break;
1289    }
1290 
1291    gl1_bind_texture(id, wrap, mag_filter, min_filter);
1292 
1293 #ifndef VITA
1294    glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
1295 #endif
1296 
1297    glTexImage2D(GL_TEXTURE_2D,
1298          0,
1299          (use_rgba || !rgb32) ? GL_RGBA : RARCH_GL1_INTERNAL_FORMAT32,
1300          width, height, 0,
1301          (use_rgba || !rgb32) ? GL_RGBA : RARCH_GL1_TEXTURE_TYPE32,
1302          (rgb32) ? RARCH_GL1_FORMAT32 : GL_UNSIGNED_BYTE, frame);
1303 }
1304 
video_texture_load_gl1(struct texture_image * ti,enum texture_filter_type filter_type,uintptr_t * idptr)1305 static void video_texture_load_gl1(
1306       struct texture_image *ti,
1307       enum texture_filter_type filter_type,
1308       uintptr_t *idptr)
1309 {
1310    GLuint id;
1311    unsigned width     = 0;
1312    unsigned height    = 0;
1313    const void *pixels = NULL;
1314 
1315    /* Generate the OpenGL texture object */
1316    glGenTextures(1, &id);
1317    *idptr = id;
1318 
1319    if (ti)
1320    {
1321       width  = ti->width;
1322       height = ti->height;
1323       pixels = ti->pixels;
1324    }
1325 
1326    gl1_load_texture_data(id,
1327          RARCH_WRAP_EDGE, filter_type,
1328          4 /* TODO/FIXME - dehardcode */,
1329          width, height, pixels,
1330          sizeof(uint32_t) /* TODO/FIXME - dehardcode */
1331          );
1332 }
1333 
1334 #ifdef HAVE_THREADS
video_texture_load_wrap_gl1(void * data)1335 static int video_texture_load_wrap_gl1(void *data)
1336 {
1337    uintptr_t id = 0;
1338 
1339    if (!data)
1340       return 0;
1341    video_texture_load_gl1((struct texture_image*)data,
1342          TEXTURE_FILTER_NEAREST, &id);
1343    return (int)id;
1344 }
1345 #endif
1346 
gl1_load_texture(void * video_data,void * data,bool threaded,enum texture_filter_type filter_type)1347 static uintptr_t gl1_load_texture(void *video_data, void *data,
1348       bool threaded, enum texture_filter_type filter_type)
1349 {
1350    uintptr_t id = 0;
1351 
1352 #ifdef HAVE_THREADS
1353    if (threaded)
1354    {
1355       gl1_t                   *gl1 = (gl1_t*)video_data;
1356       custom_command_method_t func = video_texture_load_wrap_gl1;
1357 
1358       if (gl1->ctx_driver->make_current)
1359          gl1->ctx_driver->make_current(false);
1360 
1361       return video_thread_texture_load(data, func);
1362    }
1363 #endif
1364 
1365    video_texture_load_gl1((struct texture_image*)data, filter_type, &id);
1366    return id;
1367 }
1368 
gl1_set_aspect_ratio(void * data,unsigned aspect_ratio_idx)1369 static void gl1_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
1370 {
1371    gl1_t *gl1         = (gl1_t*)data;
1372 
1373    if (!gl1)
1374       return;
1375 
1376    gl1->keep_aspect   = true;
1377    gl1->should_resize = true;
1378 }
1379 
gl1_unload_texture(void * data,bool threaded,uintptr_t id)1380 static void gl1_unload_texture(void *data,
1381       bool threaded, uintptr_t id)
1382 {
1383    GLuint glid;
1384    gl1_t               *gl1 = (gl1_t*)data;
1385    if (!id)
1386       return;
1387 
1388 #ifdef HAVE_THREADS
1389    if (threaded)
1390    {
1391       if (gl1->ctx_driver->make_current)
1392          gl1->ctx_driver->make_current(false);
1393    }
1394 #endif
1395 
1396    glid = (GLuint)id;
1397    glDeleteTextures(1, &glid);
1398 }
1399 
gl1_get_refresh_rate(void * data)1400 static float gl1_get_refresh_rate(void *data)
1401 {
1402    float refresh_rate = 0.0f;
1403    if (video_context_driver_get_refresh_rate(&refresh_rate))
1404       return refresh_rate;
1405    return 0.0f;
1406 }
1407 
gl1_set_texture_enable(void * data,bool state,bool full_screen)1408 static void gl1_set_texture_enable(void *data, bool state, bool full_screen)
1409 {
1410    gl1_t *gl1                    = (gl1_t*)data;
1411 
1412    if (!gl1)
1413       return;
1414 
1415    gl1->menu_texture_enable      = state;
1416    gl1->menu_texture_full_screen = full_screen;
1417 }
1418 
gl1_get_flags(void * data)1419 static uint32_t gl1_get_flags(void *data)
1420 {
1421    uint32_t             flags = 0;
1422 
1423    BIT32_SET(flags, GFX_CTX_FLAGS_HARD_SYNC);
1424    BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
1425    BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
1426 
1427    return flags;
1428 }
1429 
1430 static const video_poke_interface_t gl1_poke_interface = {
1431    gl1_get_flags,
1432    gl1_load_texture,
1433    gl1_unload_texture,
1434    gl1_set_video_mode,
1435    gl1_get_refresh_rate,
1436    NULL,
1437    gl1_get_video_output_size,
1438    gl1_get_video_output_prev,
1439    gl1_get_video_output_next,
1440    NULL,
1441    NULL,
1442    gl1_set_aspect_ratio,
1443    NULL,
1444    gl1_set_texture_frame,
1445    gl1_set_texture_enable,
1446    font_driver_render_msg,
1447    NULL,
1448    NULL,                         /* grab_mouse_toggle */
1449    NULL,                         /* get_current_shader */
1450    NULL,                         /* get_current_software_framebuffer */
1451    NULL                          /* get_hw_render_interface */
1452 };
1453 
gl1_gfx_get_poke_interface(void * data,const video_poke_interface_t ** iface)1454 static void gl1_gfx_get_poke_interface(void *data,
1455       const video_poke_interface_t **iface)
1456 {
1457    (void)data;
1458    *iface = &gl1_poke_interface;
1459 }
1460 
1461 #ifdef HAVE_GFX_WIDGETS
gl1_gfx_widgets_enabled(void * data)1462 static bool gl1_gfx_widgets_enabled(void *data)
1463 {
1464    (void)data;
1465    return true;
1466 }
1467 #endif
1468 
gl1_gfx_set_viewport_wrapper(void * data,unsigned viewport_width,unsigned viewport_height,bool force_full,bool allow_rotate)1469 static void gl1_gfx_set_viewport_wrapper(void *data, unsigned viewport_width,
1470       unsigned viewport_height, bool force_full, bool allow_rotate)
1471 {
1472    gl1_t               *gl1 = (gl1_t*)data;
1473    gl1_gfx_set_viewport(gl1,
1474          viewport_width, viewport_height, force_full, allow_rotate);
1475 }
1476 
1477 #ifdef HAVE_OVERLAY
gl1_get_alignment(unsigned pitch)1478 static unsigned gl1_get_alignment(unsigned pitch)
1479 {
1480    if (pitch & 1)
1481       return 1;
1482    if (pitch & 2)
1483       return 2;
1484    if (pitch & 4)
1485       return 4;
1486    return 8;
1487 }
1488 
gl1_overlay_load(void * data,const void * image_data,unsigned num_images)1489 static bool gl1_overlay_load(void *data,
1490       const void *image_data, unsigned num_images)
1491 {
1492    unsigned i, j;
1493    gl1_t *gl = (gl1_t*)data;
1494    const struct texture_image *images =
1495       (const struct texture_image*)image_data;
1496 
1497    if (!gl)
1498       return false;
1499 
1500    gl1_context_bind_hw_render(gl, false);
1501 
1502    gl1_free_overlay(gl);
1503    gl->overlay_tex = (GLuint*)
1504       calloc(num_images, sizeof(*gl->overlay_tex));
1505 
1506    if (!gl->overlay_tex)
1507    {
1508       gl1_context_bind_hw_render(gl, true);
1509       return false;
1510    }
1511 
1512    gl->overlay_vertex_coord = (GLfloat*)
1513       calloc(2 * 4 * num_images, sizeof(GLfloat));
1514    gl->overlay_tex_coord    = (GLfloat*)
1515       calloc(2 * 4 * num_images, sizeof(GLfloat));
1516    gl->overlay_color_coord  = (GLfloat*)
1517       calloc(4 * 4 * num_images, sizeof(GLfloat));
1518 
1519    if (     !gl->overlay_vertex_coord
1520          || !gl->overlay_tex_coord
1521          || !gl->overlay_color_coord)
1522       return false;
1523 
1524    gl->overlays             = num_images;
1525    glGenTextures(num_images, gl->overlay_tex);
1526 
1527    for (i = 0; i < num_images; i++)
1528    {
1529       unsigned alignment = gl1_get_alignment(images[i].width
1530             * sizeof(uint32_t));
1531 
1532       gl1_load_texture_data(gl->overlay_tex[i],
1533             RARCH_WRAP_EDGE, TEXTURE_FILTER_LINEAR,
1534             alignment,
1535             images[i].width, images[i].height, images[i].pixels,
1536             sizeof(uint32_t));
1537 
1538       /* Default. Stretch to whole screen. */
1539       gl1_overlay_tex_geom(gl, i, 0, 0, 1, 1);
1540       gl1_overlay_vertex_geom(gl, i, 0, 0, 1, 1);
1541 
1542       for (j = 0; j < 16; j++)
1543          gl->overlay_color_coord[16 * i + j] = 1.0f;
1544    }
1545 
1546    gl1_context_bind_hw_render(gl, true);
1547    return true;
1548 }
1549 
gl1_overlay_enable(void * data,bool state)1550 static void gl1_overlay_enable(void *data, bool state)
1551 {
1552    gl1_t *gl           = (gl1_t*)data;
1553 
1554    if (!gl)
1555       return;
1556 
1557    gl->overlay_enable = state;
1558 
1559    if (gl->fullscreen && gl->ctx_driver->show_mouse)
1560       gl->ctx_driver->show_mouse(gl->ctx_data, state);
1561 }
1562 
gl1_overlay_full_screen(void * data,bool enable)1563 static void gl1_overlay_full_screen(void *data, bool enable)
1564 {
1565    gl1_t *gl = (gl1_t*)data;
1566 
1567    if (gl)
1568       gl->overlay_full_screen = enable;
1569 }
1570 
gl1_overlay_set_alpha(void * data,unsigned image,float mod)1571 static void gl1_overlay_set_alpha(void *data, unsigned image, float mod)
1572 {
1573    GLfloat *color = NULL;
1574    gl1_t *gl      = (gl1_t*)data;
1575    if (!gl)
1576       return;
1577 
1578    color          = (GLfloat*)&gl->overlay_color_coord[image * 16];
1579 
1580    color[ 0 + 3]  = mod;
1581    color[ 4 + 3]  = mod;
1582    color[ 8 + 3]  = mod;
1583    color[12 + 3]  = mod;
1584 }
1585 
1586 static const video_overlay_interface_t gl1_overlay_interface = {
1587    gl1_overlay_enable,
1588    gl1_overlay_load,
1589    gl1_overlay_tex_geom,
1590    gl1_overlay_vertex_geom,
1591    gl1_overlay_full_screen,
1592    gl1_overlay_set_alpha,
1593 };
1594 
gl1_get_overlay_interface(void * data,const video_overlay_interface_t ** iface)1595 static void gl1_get_overlay_interface(void *data,
1596       const video_overlay_interface_t **iface)
1597 {
1598    (void)data;
1599    *iface = &gl1_overlay_interface;
1600 }
1601 
1602 #endif
1603 
gl1_has_windowed(void * data)1604 static bool gl1_has_windowed(void *data)
1605 {
1606    gl1_t *gl        = (gl1_t*)data;
1607    if (gl && gl->ctx_driver)
1608       return gl->ctx_driver->has_windowed;
1609    return false;
1610 }
1611 
1612 video_driver_t video_gl1 = {
1613    gl1_gfx_init,
1614    gl1_gfx_frame,
1615    gl1_gfx_set_nonblock_state,
1616    gl1_gfx_alive,
1617    gl1_gfx_focus,
1618    gl1_gfx_suppress_screensaver,
1619    gl1_has_windowed,
1620    gl1_gfx_set_shader,
1621    gl1_gfx_free,
1622    "gl1",
1623    gl1_gfx_set_viewport_wrapper,
1624    gl1_gfx_set_rotation,
1625    gl1_gfx_viewport_info,
1626    gl1_gfx_read_viewport,
1627    NULL, /* read_frame_raw */
1628 
1629 #ifdef HAVE_OVERLAY
1630    gl1_get_overlay_interface,
1631 #endif
1632 #ifdef HAVE_VIDEO_LAYOUT
1633   NULL,
1634 #endif
1635   gl1_gfx_get_poke_interface,
1636   gl1_wrap_type_to_enum,
1637 #ifdef HAVE_GFX_WIDGETS
1638   gl1_gfx_widgets_enabled
1639 #endif
1640 };
1641