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