diff --git a/Makefile.common b/Makefile.common
index bee4401f69..9352bfa7b7 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -1056,12 +1056,15 @@ endif
ifeq ($(HAVE_GL_CONTEXT), 1)
DEFINES += -DHAVE_OPENGL -DHAVE_GLSL
OBJ += gfx/drivers/gl.o \
+ gfx/drivers/gl1.o \
$(LIBRETRO_COMM_DIR)/gfx/gl_capabilities.o \
gfx/drivers_font/gl_raster_font.o \
+ gfx/drivers_font/gl1_raster_font.o \
$(LIBRETRO_COMM_DIR)/glsym/rglgen.o
ifeq ($(HAVE_MENU_COMMON), 1)
- OBJ += menu/drivers_display/menu_display_gl.o
+ OBJ += menu/drivers_display/menu_display_gl.o \
+ menu/drivers_display/menu_display_gl1.o
endif
ifeq ($(HAVE_VIDEOCORE), 1)
diff --git a/configuration.c b/configuration.c
index 49feb25290..b21432f7a8 100644
--- a/configuration.c
+++ b/configuration.c
@@ -2485,6 +2485,7 @@ static bool check_menu_driver_compatibility(void)
string_is_equal(video_driver, "d3d12") ||
string_is_equal(video_driver, "gdi") ||
string_is_equal(video_driver, "gl") ||
+ /*string_is_equal(video_driver, "gl1") ||*/
string_is_equal(video_driver, "gx2") ||
string_is_equal(video_driver, "vulkan") ||
string_is_equal(video_driver, "metal") ||
diff --git a/gfx/common/gl1_common.h b/gfx/common/gl1_common.h
new file mode 100644
index 0000000000..266dc00a02
--- /dev/null
+++ b/gfx/common/gl1_common.h
@@ -0,0 +1,90 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * copyright (c) 2011-2017 - Daniel De Matteis
+ * copyright (c) 2016-2019 - Brad Parker
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#ifndef __GL1_COMMON_H
+#define __GL1_COMMON_H
+
+#include
+#include
+
+#if defined(__APPLE__)
+#include
+#include
+#else
+#if defined(_WIN32) && !defined(_XBOX)
+#define WIN32_LEAN_AND_MEAN
+#include
+#endif
+#include
+#include
+#endif
+
+#include "../video_driver.h"
+
+struct string_list;
+
+typedef struct gl1
+{
+ unsigned video_width;
+ unsigned video_height;
+ unsigned screen_width;
+ unsigned screen_height;
+ int version_major;
+ int version_minor;
+ void *ctx_data;
+ const gfx_ctx_driver_t *ctx_driver;
+ GLuint tex;
+ struct string_list *extensions;
+ bool supports_bgra;
+ struct video_viewport vp;
+ bool keep_aspect;
+ unsigned vp_out_width;
+ unsigned vp_out_height;
+ bool should_resize;
+ struct video_coords coords;
+ GLuint texture[GFX_MAX_TEXTURES];
+ unsigned tex_index; /* For use with PREV. */
+ unsigned textures;
+ math_matrix_4x4 mvp, mvp_no_rot;
+ struct video_tex_info tex_info;
+ const float *vertex_ptr;
+ const float *white_color_ptr;
+ unsigned rotation;
+} gl1_t;
+
+typedef struct gl1_texture
+{
+ int width;
+ int height;
+ int active_width;
+ int active_height;
+
+ enum texture_filter_type type;
+ void* data;
+} gl1_texture_t;
+
+static INLINE void gl1_bind_texture(GLuint id, GLint wrap_mode, GLint mag_filter,
+ GLint min_filter)
+{
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
+}
+
+#endif
diff --git a/gfx/drivers/gl1.c b/gfx/drivers/gl1.c
new file mode 100644
index 0000000000..9a1e97a11e
--- /dev/null
+++ b/gfx/drivers/gl1.c
@@ -0,0 +1,1085 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2017 - Daniel De Matteis
+ * Copyright (C) 2016-2019 - Brad Parker
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+/* We are targeting a minimum of OpenGL 1.1 and the Microsoft "GDI Generic" software GL implementation.
+ * Any additional features added for later 1.x versions should only be enabled if they are detected at runtime. */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#ifdef HAVE_MENU
+#include "../../menu/menu_driver.h"
+#endif
+
+#include "../font_driver.h"
+
+#include "../../driver.h"
+#include "../../configuration.h"
+#include "../../retroarch.h"
+#include "../../verbosity.h"
+#include "../../frontend/frontend_driver.h"
+#include "../common/gl1_common.h"
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include "../common/win32_common.h"
+#endif
+
+static unsigned char *gl1_menu_frame = NULL;
+static unsigned gl1_menu_width = 0;
+static unsigned gl1_menu_height = 0;
+static unsigned gl1_menu_pitch = 0;
+static unsigned gl1_video_width = 0;
+static unsigned gl1_video_height = 0;
+static unsigned gl1_video_pitch = 0;
+static unsigned gl1_video_bits = 0;
+static unsigned gl1_menu_bits = 0;
+static bool gl1_rgb32 = false;
+static bool gl1_menu_rgb32 = false;
+static unsigned char *gl1_video_buf = NULL;
+
+static bool gl1_shared_context_use = false;
+
+static struct video_ortho gl1_default_ortho = {0, 1, 0, 1, -1, 1};
+
+/* Used for the last pass when rendering to the back buffer. */
+static const GLfloat gl1_vertexes_flipped[] = {
+ 0, 1,
+ 1, 1,
+ 0, 0,
+ 1, 0
+};
+
+static const GLfloat gl1_vertexes[] = {
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1
+};
+
+static const GLfloat gl1_tex_coords[] = {
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1
+};
+
+static const GLfloat gl1_white_color[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+};
+
+#define gl1_context_bind_hw_render(gl1, enable) \
+ if (gl1_shared_context_use) \
+ gl1->ctx_driver->bind_hw_render(gl1->ctx_data, enable)
+
+static bool is_pot(unsigned x)
+{
+ return (x & (x - 1)) == 0;
+}
+
+static unsigned get_pot(unsigned x)
+{
+ return (is_pot(x) ? x : next_pow2(x));
+}
+
+static void gl1_gfx_create(void)
+{
+}
+
+static void *gl1_gfx_init(const video_info_t *video,
+ const input_driver_t **input, void **input_data)
+{
+ unsigned full_x, full_y;
+ gfx_ctx_input_t inp;
+ gfx_ctx_mode_t mode;
+ void *ctx_data = NULL;
+ const gfx_ctx_driver_t *ctx_driver = NULL;
+ unsigned win_width = 0, win_height = 0;
+ unsigned temp_width = 0, temp_height = 0;
+ settings_t *settings = config_get_ptr();
+ gl1_t *gl1 = (gl1_t*)calloc(1, sizeof(*gl1));
+ const char *vendor = NULL;
+ const char *renderer = NULL;
+ const char *version = NULL;
+ const char *extensions = NULL;
+ int interval = 0;
+ struct retro_hw_render_callback *hwr = NULL;
+
+ if (!gl1)
+ return NULL;
+
+ *input = NULL;
+ *input_data = NULL;
+
+ gl1_video_width = video->width;
+ gl1_video_height = video->height;
+ gl1_rgb32 = video->rgb32;
+
+ gl1_video_bits = video->rgb32 ? 32 : 16;
+
+ if (video->rgb32)
+ gl1_video_pitch = video->width * 4;
+ else
+ gl1_video_pitch = video->width * 2;
+
+ gl1_gfx_create();
+
+ ctx_driver = video_context_driver_init_first(gl1,
+ settings->arrays.video_context_driver,
+ GFX_CTX_OPENGL_API, 1, 1, false, &ctx_data);
+
+ if (!ctx_driver)
+ goto error;
+
+ if (ctx_data)
+ gl1->ctx_data = ctx_data;
+
+ gl1->ctx_driver = ctx_driver;
+
+ video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver);
+
+ RARCH_LOG("[GL1]: Found GL1 context: %s\n", ctx_driver->ident);
+
+ video_context_driver_get_video_size(&mode);
+
+ full_x = mode.width;
+ full_y = mode.height;
+ mode.width = 0;
+ mode.height = 0;
+
+ /* Clear out potential error flags in case we use cached context. */
+ glGetError();
+
+ if (string_is_equal(ctx_driver->ident, "null"))
+ goto error;
+
+ if (!string_is_empty(version))
+ sscanf(version, "%d.%d", &gl1->version_major, &gl1->version_minor);
+
+ RARCH_LOG("[GL1]: Detecting screen resolution %ux%u.\n", full_x, full_y);
+
+ win_width = video->width;
+ win_height = video->height;
+
+ if (video->fullscreen && (win_width == 0) && (win_height == 0))
+ {
+ win_width = full_x;
+ win_height = full_y;
+ }
+
+ mode.width = win_width;
+ mode.height = win_height;
+ mode.fullscreen = video->fullscreen;
+
+ interval = video->swap_interval;
+
+ video_context_driver_swap_interval(&interval);
+
+ if (!video_context_driver_set_video_mode(&mode))
+ goto error;
+
+ mode.width = 0;
+ mode.height = 0;
+
+ video_context_driver_get_video_size(&mode);
+
+ temp_width = mode.width;
+ temp_height = mode.height;
+ mode.width = 0;
+ mode.height = 0;
+
+ /* Get real known video size, which might have been altered by context. */
+
+ if (temp_width != 0 && temp_height != 0)
+ video_driver_set_size(&temp_width, &temp_height);
+
+ video_driver_get_size(&temp_width, &temp_height);
+
+ RARCH_LOG("[GL1]: Using resolution %ux%u\n", temp_width, temp_height);
+
+ inp.input = input;
+ inp.input_data = input_data;
+
+ video_context_driver_input_driver(&inp);
+
+ if (settings->bools.video_font_enable)
+ font_driver_init_osd(gl1, false,
+ video->is_threaded,
+ FONT_DRIVER_RENDER_OPENGL1_API);
+
+ vendor = (const char*)glGetString(GL_VENDOR);
+ renderer = (const char*)glGetString(GL_RENDERER);
+ version = (const char*)glGetString(GL_VERSION);
+ extensions = (const char*)glGetString(GL_EXTENSIONS);
+
+ gl1->extensions = string_split(extensions, " ");
+
+ RARCH_LOG("[GL1]: Vendor: %s, Renderer: %s.\n", vendor, renderer);
+ RARCH_LOG("[GL1]: Version: %s.\n", version);
+ RARCH_LOG("[GL1]: Extensions: %s\n", extensions);
+
+ gl1->supports_bgra = string_list_find_elem(gl1->extensions, "GL_EXT_bgra");
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glGenTextures(1, &gl1->tex);
+
+ hwr = video_driver_get_hw_context();
+
+ memcpy(gl1->tex_info.coord, gl1_tex_coords, sizeof(gl1->tex_info.coord));
+ gl1->vertex_ptr = hwr->bottom_left_origin
+ ? gl1_vertexes : gl1_vertexes_flipped;
+ gl1->textures = 4;
+ gl1->white_color_ptr = gl1_white_color;
+ gl1->coords.vertex = gl1->vertex_ptr;
+ gl1->coords.tex_coord = gl1->tex_info.coord;
+ gl1->coords.color = gl1->white_color_ptr;
+ gl1->coords.lut_tex_coord = gl1_tex_coords;
+ gl1->coords.vertices = 4;
+
+ RARCH_LOG("[GL1]: Init complete.\n");
+
+ return gl1;
+
+error:
+ video_context_driver_destroy();
+ if (gl1)
+ {
+ if (gl1->extensions)
+ string_list_free(gl1->extensions);
+ free(gl1);
+ }
+ return NULL;
+}
+
+static void gl1_set_projection(gl1_t *gl1,
+ struct video_ortho *ortho, bool allow_rotate)
+{
+ math_matrix_4x4 rot;
+
+ /* Calculate projection. */
+ matrix_4x4_ortho(gl1->mvp_no_rot, ortho->left, ortho->right,
+ ortho->bottom, ortho->top, ortho->znear, ortho->zfar);
+
+ if (!allow_rotate)
+ {
+ gl1->mvp = gl1->mvp_no_rot;
+ return;
+ }
+
+ matrix_4x4_rotate_z(rot, M_PI * gl1->rotation / 180.0f);
+ matrix_4x4_multiply(gl1->mvp, rot, gl1->mvp_no_rot);
+}
+
+void gl1_gfx_set_viewport(gl1_t *gl1,
+ video_frame_info_t *video_info,
+ unsigned viewport_width,
+ unsigned viewport_height,
+ bool force_full, bool allow_rotate)
+{
+ gfx_ctx_aspect_t aspect_data;
+ int x = 0;
+ int y = 0;
+ float device_aspect = (float)viewport_width / viewport_height;
+ unsigned height = video_info->height;
+
+ aspect_data.aspect = &device_aspect;
+ aspect_data.width = viewport_width;
+ aspect_data.height = viewport_height;
+
+ video_context_driver_translate_aspect(&aspect_data);
+
+ if (video_info->scale_integer && !force_full)
+ {
+ video_viewport_get_scaled_integer(&gl1->vp,
+ viewport_width, viewport_height,
+ video_driver_get_aspect_ratio(), gl1->keep_aspect);
+ viewport_width = gl1->vp.width;
+ viewport_height = gl1->vp.height;
+ }
+ else if (gl1->keep_aspect && !force_full)
+ {
+ float desired_aspect = video_driver_get_aspect_ratio();
+
+#if defined(HAVE_MENU)
+ if (video_info->aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
+ {
+ /* GL has bottom-left origin viewport. */
+ x = video_info->custom_vp_x;
+ y = height - video_info->custom_vp_y - video_info->custom_vp_height;
+ viewport_width = video_info->custom_vp_width;
+ viewport_height = video_info->custom_vp_height;
+ }
+ else
+#endif
+ {
+ float delta;
+
+ if (fabsf(device_aspect - desired_aspect) < 0.0001f)
+ {
+ /* If the aspect ratios of screen and desired aspect
+ * ratio are sufficiently equal (floating point stuff),
+ * assume they are actually equal.
+ */
+ }
+ else if (device_aspect > desired_aspect)
+ {
+ delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
+ x = (int)roundf(viewport_width * (0.5f - delta));
+ viewport_width = (unsigned)roundf(2.0f * viewport_width * delta);
+ }
+ else
+ {
+ delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
+ y = (int)roundf(viewport_height * (0.5f - delta));
+ viewport_height = (unsigned)roundf(2.0f * viewport_height * delta);
+ }
+ }
+
+ gl1->vp.x = x;
+ gl1->vp.y = y;
+ gl1->vp.width = viewport_width;
+ gl1->vp.height = viewport_height;
+ }
+ else
+ {
+ gl1->vp.x = gl1->vp.y = 0;
+ gl1->vp.width = viewport_width;
+ gl1->vp.height = viewport_height;
+ }
+
+#if defined(RARCH_MOBILE)
+ /* In portrait mode, we want viewport to gravitate to top of screen. */
+ if (device_aspect < 1.0f)
+ gl1->vp.y *= 2;
+#endif
+
+ glViewport(gl1->vp.x, gl1->vp.y, gl1->vp.width, gl1->vp.height);
+ gl1_set_projection(gl1, &gl1_default_ortho, allow_rotate);
+
+ /* Set last backbuffer viewport. */
+ if (!force_full)
+ {
+ gl1->vp_out_width = viewport_width;
+ gl1->vp_out_height = viewport_height;
+ }
+
+#if 0
+ RARCH_LOG("Setting viewport @ %ux%u\n", viewport_width, viewport_height);
+#endif
+}
+
+static bool 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)
+{
+ gfx_ctx_mode_t mode;
+ const void *frame_to_copy = NULL;
+ unsigned width = 0;
+ unsigned height = 0;
+ unsigned bits = gl1_video_bits;
+ bool draw = true;
+ gl1_t *gl1 = (gl1_t*)data;
+ unsigned tex_width = 0;
+ unsigned pot_width = 0;
+ unsigned pot_height = 0;
+
+ gl1_context_bind_hw_render(gl1, false);
+
+ /* FIXME: Force these settings off as they interfere with the rendering */
+ video_info->xmb_shadows_enable = false;
+ video_info->menu_shader_pipeline = 0;
+
+ if (!frame || !frame_width || !frame_height)
+ return true;
+
+ if (gl1->should_resize)
+ {
+ gfx_ctx_mode_t mode;
+
+ gl1->should_resize = false;
+
+ mode.width = width;
+ mode.height = height;
+
+ video_info->cb_set_resize(video_info->context_data,
+ mode.width, mode.height);
+
+ gl1_gfx_set_viewport(gl1, video_info, video_info->width, video_info->height, false, true);
+ }
+
+#ifdef HAVE_MENU
+ menu_driver_frame(video_info);
+#endif
+
+ if ( gl1_video_width != frame_width ||
+ gl1_video_height != frame_height ||
+ gl1_video_pitch != pitch)
+ {
+ if (frame_width > 4 && frame_height > 4)
+ {
+ gl1_video_width = frame_width;
+ gl1_video_height = frame_height;
+ gl1_video_pitch = pitch;
+
+ tex_width = pitch / (bits / 8);
+ pot_width = get_pot(tex_width);
+ pot_height = get_pot(frame_height);
+
+ if (gl1_video_buf)
+ free(gl1_video_buf);
+
+ gl1_video_buf = (unsigned char*)malloc(pot_width * pot_height * 4);
+ }
+ }
+
+ if (gl1_menu_frame && video_info->menu_is_alive)
+ {
+ unsigned x, y;
+ frame_to_copy = NULL;
+ width = gl1_menu_width;
+ height = gl1_menu_height;
+ pitch = gl1_menu_pitch;
+ bits = gl1_menu_bits;
+
+ tex_width = pitch / (bits / 8);
+ pot_width = get_pot(tex_width);
+ pot_height = get_pot(height);
+
+ if (!gl1_video_buf)
+ gl1_video_buf = (unsigned char*)malloc(pot_width * pot_height * 4);
+
+ if (bits == 16 && gl1_video_buf)
+ {
+ /* change bit depth from 4444 to 8888 */
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < tex_width; x++)
+ {
+ unsigned pixel = ((unsigned short*)gl1_menu_frame)[tex_width * y + x];
+ unsigned *new_pixel = (unsigned*)gl1_video_buf + (pot_width * y + x);
+ unsigned r = (255.0f / 15.0f) * ((pixel & 0xF000) >> 12);
+ unsigned g = (255.0f / 15.0f) * ((pixel & 0xF00) >> 8);
+ unsigned b = (255.0f / 15.0f) * ((pixel & 0xF0) >> 4);
+ unsigned a = (255.0f / 15.0f) * ((pixel & 0xF) >> 0);
+ /* copy pixels into top-left portion of larger (power-of-two) buffer */
+ *new_pixel = (a << 24) | (r << 16) | (g << 8) | b;
+ }
+ }
+
+ frame_to_copy = gl1_video_buf;
+ }
+ }
+ else
+ {
+ width = gl1_video_width;
+ height = gl1_video_height;
+ pitch = gl1_video_pitch;
+
+ tex_width = pitch / (bits / 8);
+ pot_width = get_pot(tex_width);
+ pot_height = get_pot(height);
+
+ if ( frame_width == 4 &&
+ frame_height == 4 &&
+ (frame_width < width && frame_height < height)
+ )
+ draw = false;
+
+ if (video_info->menu_is_alive)
+ draw = false;
+
+ if (draw && gl1_video_buf)
+ {
+ unsigned x, y;
+
+ if (bits == 32)
+ {
+ for (y = 0; y < height; y++)
+ {
+ /* copy lines into top-left portion of larger (power-of-two) buffer */
+ memcpy(gl1_video_buf + ((pot_width * (bits / 8)) * y), frame + (pitch * y), pitch);
+ }
+ }
+ else if (bits == 16)
+ {
+ /* change bit depth from 565 to 8888 */
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < tex_width; x++)
+ {
+ unsigned pixel = ((unsigned short*)frame)[tex_width * y + x];
+ unsigned *new_pixel = (unsigned*)gl1_video_buf + (pot_width * y + x);
+ unsigned r = (255.0f / 31.0f) * ((pixel & 0xF800) >> 11);
+ unsigned g = (255.0f / 63.0f) * ((pixel & 0x7E0) >> 5);
+ unsigned b = (255.0f / 31.0f) * ((pixel & 0x1F) >> 0);
+ /* copy pixels into top-left portion of larger (power-of-two) buffer */
+ *new_pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
+ }
+ }
+ }
+
+ frame_to_copy = gl1_video_buf;
+ }
+ }
+
+ if (gl1->video_width != width || gl1->video_height != height)
+ {
+ gl1->video_width = width;
+ gl1->video_height = height;
+ }
+
+ video_context_driver_get_video_size(&mode);
+
+ gl1->screen_width = mode.width;
+ gl1->screen_height = mode.height;
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (draw && frame_to_copy)
+ {
+ /* 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. */
+ GLint internalFormat = GL_RGBA8;
+ GLenum format = (gl1->supports_bgra ? GL_BGRA_EXT : GL_RGBA);
+ GLenum type = GL_UNSIGNED_BYTE;
+
+ /*glDisable(GL_BLEND);*/
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glEnable(GL_TEXTURE_2D);
+
+ /* multi-texture not part of GL 1.1 */
+ /*glActiveTexture(GL_TEXTURE0);*/
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, pot_width);
+ glBindTexture(GL_TEXTURE_2D, gl1->tex);
+
+ /* TODO: We could implement red/blue swap if client GL does not support BGRA... but even MS GDI Generic supports it */
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, pot_width, pot_height, 0, format, type, NULL);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_width, height, format, type, frame_to_copy);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ /*glLoadMatrixf(gl1->mvp.data);*/
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ /*glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glColorPointer(4, GL_FLOAT, 0, gl1->coords.color);
+ glVertexPointer(2, GL_FLOAT, 0, gl1->coords.vertex);
+ glTexCoordPointer(2, GL_FLOAT, 0, gl1->coords.tex_coord);
+
+ glDrawArrays(GL_TRIANGLES, 0, gl1->coords.vertices);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);*/
+
+
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+
+ glBegin(GL_QUADS);
+
+ {
+ float tex_BL[2] = {0.0f, 0.0f};
+ float tex_BR[2] = {1.0f, 0.0f};
+ float tex_TL[2] = {0.0f, 1.0f};
+ float tex_TR[2] = {1.0f, 1.0f};
+ float *tex_mirror_BL = tex_TL;
+ float *tex_mirror_BR = tex_TR;
+ float *tex_mirror_TL = tex_BL;
+ float *tex_mirror_TR = tex_BR;
+ float norm_width = (1.0f / (float)pot_width) * (float)tex_width;
+ float norm_height = (1.0f / (float)pot_height) * (float)height;
+
+ /* remove extra POT padding */
+ tex_mirror_BR[0] = norm_width;
+ tex_mirror_TR[0] = norm_width;
+
+ /* normally this would be 1.0 - height, but we're drawing upside-down */
+ tex_mirror_BL[1] = norm_height;
+ tex_mirror_BR[1] = norm_height;
+
+ glTexCoord2f(tex_mirror_BL[0], tex_mirror_BL[1]);
+ glVertex2f(-1.0f, -1.0f);
+
+ glTexCoord2f(tex_mirror_TL[0], tex_mirror_TL[1]);
+ glVertex2f(-1.0f, 1.0f);
+
+ glTexCoord2f(tex_mirror_TR[0], tex_mirror_TR[1]);
+ glVertex2f(1.0f, 1.0f);
+
+ glTexCoord2f(tex_mirror_BR[0], tex_mirror_BR[1]);
+ glVertex2f(1.0f, -1.0f);
+ }
+
+ glEnd();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ }
+
+ if (msg)
+ font_driver_render_msg(video_info, NULL, msg, NULL);
+
+ video_info->cb_update_window_title(
+ video_info->context_data, video_info);
+
+ video_info->cb_swap_buffers(video_info->context_data, video_info);
+
+ gl1_context_bind_hw_render(gl1, true);
+
+ return true;
+}
+
+static void gl1_gfx_set_nonblock_state(void *data, bool state)
+{
+ int interval = 0;
+ gl1_t *gl1 = (gl1_t*)data;
+ settings_t *settings = config_get_ptr();
+
+ if (!gl1)
+ return;
+
+ RARCH_LOG("[GL1]: VSync => %s\n", state ? "off" : "on");
+
+ gl1_context_bind_hw_render(gl1, false);
+
+ if (!state)
+ interval = settings->uints.video_swap_interval;
+
+ video_context_driver_swap_interval(&interval);
+ gl1_context_bind_hw_render(gl1, true);
+}
+
+static bool gl1_gfx_alive(void *data)
+{
+ unsigned temp_width = 0;
+ unsigned temp_height = 0;
+ bool quit = false;
+ bool resize = false;
+ bool ret = false;
+ bool is_shutdown = rarch_ctl(RARCH_CTL_IS_SHUTDOWN, NULL);
+ gl1_t *gl1 = (gl1_t*)data;
+
+ /* Needed because some context drivers don't track their sizes */
+ video_driver_get_size(&temp_width, &temp_height);
+
+ gl1->ctx_driver->check_window(gl1->ctx_data,
+ &quit, &resize, &temp_width, &temp_height, is_shutdown);
+
+ if (resize)
+ gl1->should_resize = true;
+
+ ret = !quit;
+
+ if (temp_width != 0 && temp_height != 0)
+ video_driver_set_size(&temp_width, &temp_height);
+
+ return ret;
+}
+
+static bool gl1_gfx_focus(void *data)
+{
+ (void)data;
+ return true;
+}
+
+static bool gl1_gfx_suppress_screensaver(void *data, bool enable)
+{
+ (void)data;
+ (void)enable;
+ return false;
+}
+
+static bool gl1_gfx_has_windowed(void *data)
+{
+ (void)data;
+ return true;
+}
+
+static void gl1_gfx_free(void *data)
+{
+ gl1_t *gl1 = (gl1_t*)data;
+
+ gl1_context_bind_hw_render(gl1, false);
+
+ if (gl1_menu_frame)
+ {
+ free(gl1_menu_frame);
+ gl1_menu_frame = NULL;
+ }
+
+ if (gl1_video_buf)
+ {
+ free(gl1_video_buf);
+ gl1_video_buf = NULL;
+ }
+
+ if (!gl1)
+ return;
+
+ if (gl1->tex)
+ {
+ glDeleteTextures(1, &gl1->tex);
+ gl1->tex = 0;
+ }
+
+ if (gl1->extensions)
+ {
+ string_list_free(gl1->extensions);
+ gl1->extensions = NULL;
+ }
+
+ font_driver_free_osd();
+ video_context_driver_free();
+ free(gl1);
+}
+
+static bool gl1_gfx_set_shader(void *data,
+ enum rarch_shader_type type, const char *path)
+{
+ (void)data;
+ (void)type;
+ (void)path;
+
+ return false;
+}
+
+static void gl1_gfx_set_rotation(void *data,
+ unsigned rotation)
+{
+ gl1_t *gl1 = (gl1_t*)data;
+
+ if (!gl1)
+ return;
+
+ gl1->rotation = 90 * rotation;
+ gl1_set_projection(gl1, &gl1_default_ortho, true);
+}
+
+static void gl1_gfx_viewport_info(void *data,
+ struct video_viewport *vp)
+{
+ (void)data;
+ (void)vp;
+}
+
+static bool gl1_gfx_read_viewport(void *data, uint8_t *buffer, bool is_idle)
+{
+ (void)data;
+ (void)buffer;
+
+ return true;
+}
+
+static void gl1_set_texture_frame(void *data,
+ const void *frame, bool rgb32, unsigned width, unsigned height,
+ float alpha)
+{
+ unsigned pitch = width * 2;
+ gl1_t *gl1 = (gl1_t*)data;
+
+ if (!gl1)
+ return;
+
+ gl1_context_bind_hw_render(gl1, false);
+
+ if (rgb32)
+ pitch = width * 4;
+
+ if (gl1_menu_frame)
+ {
+ free(gl1_menu_frame);
+ gl1_menu_frame = NULL;
+ }
+
+ if ( !gl1_menu_frame ||
+ gl1_menu_width != width ||
+ gl1_menu_height != height ||
+ gl1_menu_pitch != pitch)
+ {
+ if (pitch && height)
+ {
+ if (gl1_menu_frame)
+ free(gl1_menu_frame);
+
+ /* FIXME? We have to assume the pitch has no extra padding in it because that will mess up the POT calculation when we don't know how many bpp there are. */
+ gl1_menu_frame = (unsigned char*)malloc(pitch * height);
+ }
+ }
+
+ if (gl1_menu_frame && frame && pitch && height)
+ {
+ memcpy(gl1_menu_frame, frame, pitch * height);
+ gl1_menu_width = width;
+ gl1_menu_height = height;
+ gl1_menu_pitch = pitch;
+ gl1_menu_bits = rgb32 ? 32 : 16;
+ }
+
+ gl1_context_bind_hw_render(gl1, true);
+}
+
+static void gl1_set_osd_msg(void *data,
+ video_frame_info_t *video_info,
+ const char *msg,
+ const void *params, void *font)
+{
+ font_driver_render_msg(video_info, font,
+ msg, (const struct font_params *)params);
+}
+
+static void gl1_get_video_output_size(void *data,
+ unsigned *width, unsigned *height)
+{
+ gfx_ctx_size_t size_data;
+ size_data.width = width;
+ size_data.height = height;
+ video_context_driver_get_video_output_size(&size_data);
+}
+
+static void gl1_get_video_output_prev(void *data)
+{
+ video_context_driver_get_video_output_prev();
+}
+
+static void gl1_get_video_output_next(void *data)
+{
+ video_context_driver_get_video_output_next();
+}
+
+static void gl1_set_video_mode(void *data, unsigned width, unsigned height,
+ bool fullscreen)
+{
+ gfx_ctx_mode_t mode;
+
+ mode.width = width;
+ mode.height = height;
+ mode.fullscreen = fullscreen;
+
+ video_context_driver_set_video_mode(&mode);
+}
+
+static uintptr_t gl1_load_texture(void *video_data, void *data,
+ bool threaded, enum texture_filter_type filter_type)
+{
+ void *tmpdata = NULL;
+ gl1_texture_t *texture = NULL;
+ struct texture_image *image = (struct texture_image*)data;
+ int size = image->width *
+ image->height * sizeof(uint32_t);
+
+ if (!image || image->width > 2048 || image->height > 2048)
+ return 0;
+
+ texture = (gl1_texture_t*)calloc(1, sizeof(*texture));
+
+ if (!texture)
+ return 0;
+
+ texture->width = image->width;
+ texture->height = image->height;
+ texture->active_width = image->width;
+ texture->active_height = image->height;
+ texture->data = calloc(1,
+ texture->width * texture->height * sizeof(uint32_t));
+ texture->type = filter_type;
+
+ if (!texture->data)
+ {
+ free(texture);
+ return 0;
+ }
+
+ memcpy(texture->data, image->pixels,
+ texture->width * texture->height * sizeof(uint32_t));
+
+ return (uintptr_t)texture;
+}
+
+static void gl1_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
+{
+ gl1_t *gl1 = (gl1_t*)data;
+
+ switch (aspect_ratio_idx)
+ {
+ case ASPECT_RATIO_SQUARE:
+ video_driver_set_viewport_square_pixel();
+ break;
+
+ case ASPECT_RATIO_CORE:
+ video_driver_set_viewport_core();
+ break;
+
+ case ASPECT_RATIO_CONFIG:
+ video_driver_set_viewport_config();
+ break;
+
+ default:
+ break;
+ }
+
+ video_driver_set_aspect_ratio_value(
+ aspectratio_lut[aspect_ratio_idx].value);
+
+ if (!gl1)
+ return;
+
+ gl1->keep_aspect = true;
+ gl1->should_resize = true;
+}
+
+static void gl1_unload_texture(void *data, uintptr_t handle)
+{
+ struct gl1_texture *texture = (struct gl1_texture*)handle;
+
+ if (!texture)
+ return;
+
+ if (texture->data)
+ free(texture->data);
+
+ free(texture);
+}
+
+static float gl1_get_refresh_rate(void *data)
+{
+ float refresh_rate = 0.0f;
+ if (video_context_driver_get_refresh_rate(&refresh_rate))
+ return refresh_rate;
+ return 0.0f;
+}
+
+static const video_poke_interface_t gl1_poke_interface = {
+ NULL, /* get_flags */
+ NULL, /* set_coords */
+ NULL, /* set_mvp */
+ gl1_load_texture,
+ gl1_unload_texture,
+ gl1_set_video_mode,
+ gl1_get_refresh_rate,
+ NULL,
+ gl1_get_video_output_size,
+ gl1_get_video_output_prev,
+ gl1_get_video_output_next,
+ NULL,
+ NULL,
+ gl1_set_aspect_ratio,
+ NULL,
+ gl1_set_texture_frame,
+ NULL,
+ gl1_set_osd_msg,
+ NULL,
+ NULL, /* grab_mouse_toggle */
+ NULL, /* get_current_shader */
+ NULL, /* get_current_software_framebuffer */
+ NULL /* get_hw_render_interface */
+};
+
+static void gl1_gfx_get_poke_interface(void *data,
+ const video_poke_interface_t **iface)
+{
+ (void)data;
+ *iface = &gl1_poke_interface;
+}
+
+static void gl1_gfx_set_viewport_wrapper(void *data, unsigned viewport_width,
+ unsigned viewport_height, bool force_full, bool allow_rotate)
+{
+ video_frame_info_t video_info;
+ gl1_t *gl1 = (gl1_t*)data;
+
+ video_driver_build_info(&video_info);
+
+ gl1_gfx_set_viewport(gl1, &video_info,
+ viewport_width, viewport_height, force_full, allow_rotate);
+}
+
+bool gl1_has_menu_frame(void)
+{
+ return (gl1_menu_frame != NULL);
+}
+
+static unsigned gl1_wrap_type_to_enum(enum gfx_wrap_type type)
+{
+ switch (type)
+ {
+ case RARCH_WRAP_REPEAT:
+ case RARCH_WRAP_MIRRORED_REPEAT: /* mirrored not actually supported */
+ return GL_REPEAT;
+ default:
+ return GL_CLAMP;
+ break;
+ }
+
+ return 0;
+}
+
+video_driver_t video_gl1 = {
+ gl1_gfx_init,
+ gl1_gfx_frame,
+ gl1_gfx_set_nonblock_state,
+ gl1_gfx_alive,
+ gl1_gfx_focus,
+ gl1_gfx_suppress_screensaver,
+ gl1_gfx_has_windowed,
+ gl1_gfx_set_shader,
+ gl1_gfx_free,
+ "gl1",
+ gl1_gfx_set_viewport_wrapper,
+ gl1_gfx_set_rotation,
+ gl1_gfx_viewport_info,
+ gl1_gfx_read_viewport,
+ NULL, /* read_frame_raw */
+
+#ifdef HAVE_OVERLAY
+ NULL, /* overlay_interface */
+#endif
+ gl1_gfx_get_poke_interface,
+ gl1_wrap_type_to_enum,
+#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
+ NULL
+#endif
+};
diff --git a/gfx/drivers_font/gl1_raster_font.c b/gfx/drivers_font/gl1_raster_font.c
new file mode 100644
index 0000000000..aed73f80fc
--- /dev/null
+++ b/gfx/drivers_font/gl1_raster_font.c
@@ -0,0 +1,581 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2017 - Daniel De Matteis
+ * Copyright (C) 2016-2017 - Brad Parker
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+
+#include
+#include
+#include
+
+#include "../common/gl1_common.h"
+#include "../font_driver.h"
+#include "../video_driver.h"
+#include "../../verbosity.h"
+
+/* TODO: Move viewport side effects to the caller: it's a source of bugs. */
+
+#define gl1_raster_font_emit(c, vx, vy) do { \
+ font_vertex[ 2 * (6 * i + c) + 0] = (x + (delta_x + off_x + vx * width) * scale) * inv_win_width; \
+ font_vertex[ 2 * (6 * i + c) + 1] = (y + (delta_y - off_y - vy * height) * scale) * inv_win_height; \
+ font_tex_coords[ 2 * (6 * i + c) + 0] = (tex_x + vx * width) * inv_tex_size_x; \
+ font_tex_coords[ 2 * (6 * i + c) + 1] = (tex_y + vy * height) * inv_tex_size_y; \
+ font_color[ 4 * (6 * i + c) + 0] = color[0]; \
+ font_color[ 4 * (6 * i + c) + 1] = color[1]; \
+ font_color[ 4 * (6 * i + c) + 2] = color[2]; \
+ font_color[ 4 * (6 * i + c) + 3] = color[3]; \
+ font_lut_tex_coord[ 2 * (6 * i + c) + 0] = gl->coords.lut_tex_coord[0]; \
+ font_lut_tex_coord[ 2 * (6 * i + c) + 1] = gl->coords.lut_tex_coord[1]; \
+} while(0)
+
+#define MAX_MSG_LEN_CHUNK 64
+
+typedef struct
+{
+ gl1_t *gl;
+ GLuint tex;
+ unsigned tex_width, tex_height;
+
+ const font_renderer_driver_t *font_driver;
+ void *font_data;
+ struct font_atlas *atlas;
+
+ video_font_raster_block_t *block;
+} gl1_raster_t;
+
+static void gl1_raster_font_free_font(void *data,
+ bool is_threaded)
+{
+ gl1_raster_t *font = (gl1_raster_t*)data;
+ if (!font)
+ return;
+
+ if (font->font_driver && font->font_data)
+ font->font_driver->free(font->font_data);
+
+ if (is_threaded)
+ video_context_driver_make_current(true);
+
+ glDeleteTextures(1, &font->tex);
+
+ free(font);
+}
+
+#if 0
+static bool gl1_raster_font_upload_atlas_components_4(gl1_raster_t *font)
+{
+ unsigned i, j;
+ GLint gl_internal = GL_RGBA;
+ GLenum gl_format = GL_RGBA;
+ size_t ncomponents = 4;
+ uint8_t *tmp = NULL;
+
+ tmp = (uint8_t*)calloc(font->tex_height, font->tex_width * ncomponents);
+
+ for (i = 0; i < font->atlas->height; ++i)
+ {
+ const uint8_t *src = &font->atlas->buffer[i * font->atlas->width];
+ uint8_t *dst = &tmp[i * font->tex_width * ncomponents];
+
+ for (j = 0; j < font->atlas->width; ++j)
+ {
+ *dst++ = 0xff;
+ *dst++ = 0xff;
+ *dst++ = 0xff;
+ *dst++ = *src++;
+ }
+ break;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_internal, font->tex_width, font->tex_height,
+ 0, gl_format, GL_UNSIGNED_BYTE, tmp);
+
+ free(tmp);
+
+ return true;
+}
+#endif
+
+static bool gl1_raster_font_upload_atlas(gl1_raster_t *font)
+{
+ unsigned i, j;
+ GLint gl_internal = GL_LUMINANCE_ALPHA;
+ GLenum gl_format = GL_LUMINANCE_ALPHA;
+ size_t ncomponents = 2;
+ uint8_t *tmp = NULL;
+
+ tmp = (uint8_t*)calloc(font->tex_height, font->tex_width * ncomponents);
+
+ switch (ncomponents)
+ {
+ case 1:
+ for (i = 0; i < font->atlas->height; ++i)
+ {
+ const uint8_t *src = &font->atlas->buffer[i * font->atlas->width];
+ uint8_t *dst = &tmp[i * font->tex_width * ncomponents];
+
+ memcpy(dst, src, font->atlas->width);
+ }
+ break;
+ case 2:
+ for (i = 0; i < font->atlas->height; ++i)
+ {
+ const uint8_t *src = &font->atlas->buffer[i * font->atlas->width];
+ uint8_t *dst = &tmp[i * font->tex_width * ncomponents];
+
+ for (j = 0; j < font->atlas->width; ++j)
+ {
+ *dst++ = 0xff;
+ *dst++ = *src++;
+ }
+ }
+ break;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_internal, font->tex_width, font->tex_height,
+ 0, gl_format, GL_UNSIGNED_BYTE, tmp);
+
+ free(tmp);
+
+ return true;
+}
+
+static void *gl1_raster_font_init_font(void *data,
+ const char *font_path, float font_size,
+ bool is_threaded)
+{
+ gl1_raster_t *font = (gl1_raster_t*)calloc(1, sizeof(*font));
+
+ if (!font)
+ return NULL;
+
+ font->gl = (gl1_t*)data;
+
+ if (!font_renderer_create_default(
+ &font->font_driver,
+ &font->font_data, font_path, font_size))
+ {
+ RARCH_WARN("Couldn't initialize font renderer.\n");
+ free(font);
+ return NULL;
+ }
+
+ RARCH_LOG("[Font]: Using font driver GL1\n");
+
+ if (is_threaded)
+ video_context_driver_make_current(false);
+
+ glGenTextures(1, &font->tex);
+
+ gl1_bind_texture(font->tex, GL_CLAMP, GL_LINEAR, GL_LINEAR);
+
+ font->atlas = font->font_driver->get_atlas(font->font_data);
+ font->tex_width = next_pow2(font->atlas->width);
+ font->tex_height = next_pow2(font->atlas->height);
+
+ if (!gl1_raster_font_upload_atlas(font))
+ goto error;
+
+ font->atlas->dirty = false;
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, font->gl->texture[font->gl->tex_index]);
+
+ return font;
+
+error:
+ gl1_raster_font_free_font(font, is_threaded);
+ font = NULL;
+
+ return NULL;
+}
+
+static int gl1_get_message_width(void *data, const char *msg,
+ unsigned msg_len, float scale)
+{
+ gl1_raster_t *font = (gl1_raster_t*)data;
+ const char* msg_end = msg + msg_len;
+ int delta_x = 0;
+
+ if ( !font
+ || !font->font_driver
+ || !font->font_driver->get_glyph
+ || !font->font_data )
+ return 0;
+
+ while (msg < msg_end)
+ {
+ unsigned code = utf8_walk(&msg);
+ const struct font_glyph *glyph = font->font_driver->get_glyph(
+ font->font_data, code);
+
+ if (!glyph) /* Do something smarter here ... */
+ glyph = font->font_driver->get_glyph(font->font_data, '?');
+ if (!glyph)
+ continue;
+
+ delta_x += glyph->advance_x;
+ }
+
+ return delta_x * scale;
+}
+
+static void gl1_raster_font_draw_vertices(gl1_raster_t *font,
+ const video_coords_t *coords,
+ video_frame_info_t *video_info)
+{
+ video_shader_ctx_coords_t coords_data;
+
+ if (font->atlas->dirty)
+ {
+ gl1_raster_font_upload_atlas(font);
+ font->atlas->dirty = false;
+ }
+
+ coords_data.handle_data = NULL;
+ coords_data.data = coords;
+
+ video_driver_set_coords(&coords_data);
+
+ /*video_info->cb_set_mvp(font->gl,
+ video_info->shader_data, &font->gl->mvp_no_rot);*/
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(font->gl->mvp.data);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glColorPointer(4, GL_FLOAT, 0, coords->color);
+ glVertexPointer(2, GL_FLOAT, 0, coords->vertex);
+ glTexCoordPointer(2, GL_FLOAT, 0, coords->tex_coord);
+
+ glDrawArrays(GL_TRIANGLES, 0, coords->vertices);
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+}
+
+static void gl1_raster_font_render_line(
+ gl1_raster_t *font, const char *msg, unsigned msg_len,
+ GLfloat scale, const GLfloat color[4], GLfloat pos_x,
+ GLfloat pos_y, unsigned text_align,
+ video_frame_info_t *video_info)
+{
+ unsigned i;
+ struct video_coords coords;
+ GLfloat font_tex_coords[2 * 6 * MAX_MSG_LEN_CHUNK];
+ GLfloat font_vertex[2 * 6 * MAX_MSG_LEN_CHUNK];
+ GLfloat font_color[4 * 6 * MAX_MSG_LEN_CHUNK];
+ GLfloat font_lut_tex_coord[2 * 6 * MAX_MSG_LEN_CHUNK];
+ gl1_t *gl = font->gl;
+ const char* msg_end = msg + msg_len;
+ int x = roundf(pos_x * gl->vp.width);
+ int y = roundf(pos_y * gl->vp.height);
+ int delta_x = 0;
+ int delta_y = 0;
+ float inv_tex_size_x = 1.0f / font->tex_width;
+ float inv_tex_size_y = 1.0f / font->tex_height;
+ float inv_win_width = 1.0f / font->gl->vp.width;
+ float inv_win_height = 1.0f / font->gl->vp.height;
+
+ switch (text_align)
+ {
+ case TEXT_ALIGN_RIGHT:
+ x -= gl1_get_message_width(font, msg, msg_len, scale);
+ break;
+ case TEXT_ALIGN_CENTER:
+ x -= gl1_get_message_width(font, msg, msg_len, scale) / 2.0;
+ break;
+ }
+
+ while (msg < msg_end)
+ {
+ i = 0;
+ while ((i < MAX_MSG_LEN_CHUNK) && (msg < msg_end))
+ {
+ int off_x, off_y, tex_x, tex_y, width, height;
+ unsigned code = utf8_walk(&msg);
+ const struct font_glyph *glyph = font->font_driver->get_glyph(
+ font->font_data, code);
+
+ if (!glyph) /* Do something smarter here ... */
+ glyph = font->font_driver->get_glyph(font->font_data, '?');
+
+ if (!glyph)
+ continue;
+
+ off_x = glyph->draw_offset_x;
+ off_y = glyph->draw_offset_y;
+ tex_x = glyph->atlas_offset_x;
+ tex_y = glyph->atlas_offset_y;
+ width = glyph->width;
+ height = glyph->height;
+
+ gl1_raster_font_emit(0, 0, 1); /* Bottom-left */
+ gl1_raster_font_emit(1, 1, 1); /* Bottom-right */
+ gl1_raster_font_emit(2, 0, 0); /* Top-left */
+
+ gl1_raster_font_emit(3, 1, 0); /* Top-right */
+ gl1_raster_font_emit(4, 0, 0); /* Top-left */
+ gl1_raster_font_emit(5, 1, 1); /* Bottom-right */
+
+ i++;
+
+ delta_x += glyph->advance_x;
+ delta_y -= glyph->advance_y;
+ }
+
+ coords.tex_coord = font_tex_coords;
+ coords.vertex = font_vertex;
+ coords.color = font_color;
+ coords.vertices = i * 6;
+ coords.lut_tex_coord = font_lut_tex_coord;
+
+ if (font->block)
+ video_coord_array_append(&font->block->carr, &coords, coords.vertices);
+ else
+ gl1_raster_font_draw_vertices(font, &coords, video_info);
+ }
+}
+
+static void gl1_raster_font_render_message(
+ gl1_raster_t *font, const char *msg, GLfloat scale,
+ const GLfloat color[4], GLfloat pos_x, GLfloat pos_y,
+ unsigned text_align,
+ video_frame_info_t *video_info)
+{
+ float line_height;
+ int lines = 0;
+
+ /* If the font height is not supported just draw as usual */
+ if (!font->font_driver->get_line_height)
+ {
+ gl1_raster_font_render_line(font,
+ msg, (unsigned)strlen(msg), scale, color, pos_x,
+ pos_y, text_align,
+ video_info);
+ return;
+ }
+
+ line_height = (float) font->font_driver->get_line_height(font->font_data) *
+ scale / font->gl->vp.height;
+
+ for (;;)
+ {
+ const char *delim = strchr(msg, '\n');
+ unsigned msg_len = delim
+ ? (unsigned)(delim - msg) : (unsigned)strlen(msg);
+
+ /* Draw the line */
+ gl1_raster_font_render_line(font,
+ msg, msg_len, scale, color, pos_x,
+ pos_y - (float)lines*line_height, text_align,
+ video_info);
+
+ if (!delim)
+ break;
+
+ msg += msg_len + 1;
+ lines++;
+ }
+}
+
+static void gl1_raster_font_setup_viewport(unsigned width, unsigned height,
+ gl1_raster_t *font, bool full_screen)
+{
+ video_shader_ctx_info_t shader_info;
+
+ video_driver_set_viewport(width, height, full_screen, false);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ /*glBlendEquation(GL_FUNC_ADD);*/
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, font->tex);
+
+ /*shader_info.data = NULL;
+ shader_info.idx = VIDEO_SHADER_STOCK_BLEND;
+ shader_info.set_active = true;
+
+ video_shader_driver_use(&shader_info);*/
+}
+
+static void gl1_raster_font_render_msg(
+ video_frame_info_t *video_info,
+ void *data, const char *msg,
+ const struct font_params *params)
+{
+ GLfloat color[4];
+ int drop_x, drop_y;
+ GLfloat x, y, scale, drop_mod, drop_alpha;
+ enum text_alignment text_align = TEXT_ALIGN_LEFT;
+ bool full_screen = false ;
+ gl1_raster_t *font = (gl1_raster_t*)data;
+ unsigned width = video_info->width;
+ unsigned height = video_info->height;
+
+ if (!font || string_is_empty(msg))
+ return;
+
+ if (params)
+ {
+ x = params->x;
+ y = params->y;
+ scale = params->scale;
+ full_screen = params->full_screen;
+ text_align = params->text_align;
+ drop_x = params->drop_x;
+ drop_y = params->drop_y;
+ drop_mod = params->drop_mod;
+ drop_alpha = params->drop_alpha;
+
+ color[0] = FONT_COLOR_GET_RED(params->color) / 255.0f;
+ color[1] = FONT_COLOR_GET_GREEN(params->color) / 255.0f;
+ color[2] = FONT_COLOR_GET_BLUE(params->color) / 255.0f;
+ color[3] = FONT_COLOR_GET_ALPHA(params->color) / 255.0f;
+
+ /* If alpha is 0.0f, turn it into default 1.0f */
+ if (color[3] <= 0.0f)
+ color[3] = 1.0f;
+ }
+ else
+ {
+ x = video_info->font_msg_pos_x;
+ y = video_info->font_msg_pos_y;
+ scale = 1.0f;
+ full_screen = true;
+ text_align = TEXT_ALIGN_LEFT;
+
+ color[0] = video_info->font_msg_color_r;
+ color[1] = video_info->font_msg_color_g;
+ color[2] = video_info->font_msg_color_b;
+ color[3] = 1.0f;
+
+ drop_x = -2;
+ drop_y = -2;
+ drop_mod = 0.3f;
+ drop_alpha = 1.0f;
+ }
+
+ if (font->block)
+ font->block->fullscreen = full_screen;
+ else
+ gl1_raster_font_setup_viewport(width, height, font, full_screen);
+
+ if (!string_is_empty(msg) && font->gl
+ && font->font_data && font->font_driver)
+ {
+ if (drop_x || drop_y)
+ {
+ GLfloat color_dark[4];
+
+ color_dark[0] = color[0] * drop_mod;
+ color_dark[1] = color[1] * drop_mod;
+ color_dark[2] = color[2] * drop_mod;
+ color_dark[3] = color[3] * drop_alpha;
+
+ if (font->gl)
+ gl1_raster_font_render_message(font, msg, scale, color_dark,
+ x + scale * drop_x / font->gl->vp.width, y +
+ scale * drop_y / font->gl->vp.height, text_align,
+ video_info);
+ }
+
+ if (font->gl)
+ gl1_raster_font_render_message(font, msg, scale, color,
+ x, y, text_align, video_info);
+ }
+
+ if (!font->block && font->gl)
+ {
+ /* restore viewport */
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, font->gl->texture[font->gl->tex_index]);
+
+ glDisable(GL_BLEND);
+ video_driver_set_viewport(width, height, false, true);
+ }
+}
+
+static const struct font_glyph *gl1_raster_font_get_glyph(
+ void *data, uint32_t code)
+{
+ gl1_raster_t *font = (gl1_raster_t*)data;
+
+ if (!font || !font->font_driver)
+ return NULL;
+ if (!font->font_driver->ident)
+ return NULL;
+ return font->font_driver->get_glyph((void*)font->font_driver, code);
+}
+
+static void gl1_raster_font_flush_block(unsigned width, unsigned height,
+ void *data, video_frame_info_t *video_info)
+{
+ gl1_raster_t *font = (gl1_raster_t*)data;
+ video_font_raster_block_t *block = font ? font->block : NULL;
+
+ if (!font || !block || !block->carr.coords.vertices)
+ return;
+
+ gl1_raster_font_setup_viewport(width, height, font, block->fullscreen);
+ gl1_raster_font_draw_vertices(font, (video_coords_t*)&block->carr.coords,
+ video_info);
+
+ if (font->gl)
+ {
+ /* restore viewport */
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, font->gl->texture[font->gl->tex_index]);
+
+ glDisable(GL_BLEND);
+ video_driver_set_viewport(width, height, block->fullscreen, true);
+ }
+}
+
+static void gl1_raster_font_bind_block(void *data, void *userdata)
+{
+ gl1_raster_t *font = (gl1_raster_t*)data;
+ video_font_raster_block_t *block = (video_font_raster_block_t*)userdata;
+
+ if (font)
+ font->block = block;
+}
+
+font_renderer_t gl1_raster_font = {
+ gl1_raster_font_init_font,
+ gl1_raster_font_free_font,
+ gl1_raster_font_render_msg,
+ "GL1 raster",
+ gl1_raster_font_get_glyph,
+ gl1_raster_font_bind_block,
+ gl1_raster_font_flush_block,
+ gl1_get_message_width
+};
diff --git a/gfx/font_driver.c b/gfx/font_driver.c
index de4cf2f5b1..7b53005901 100644
--- a/gfx/font_driver.c
+++ b/gfx/font_driver.c
@@ -183,6 +183,35 @@ static bool gl_font_init_first(
return false;
}
+
+static const font_renderer_t *gl1_font_backends[] = {
+ &gl1_raster_font,
+ NULL,
+};
+
+static bool gl1_font_init_first(
+ const void **font_driver, void **font_handle,
+ void *video_data, const char *font_path,
+ float font_size, bool is_threaded)
+{
+ unsigned i;
+
+ for (i = 0; gl1_font_backends[i]; i++)
+ {
+ void *data = gl1_font_backends[i]->init(
+ video_data, font_path, font_size,
+ is_threaded);
+
+ if (!data)
+ continue;
+
+ *font_driver = gl1_font_backends[i];
+ *font_handle = data;
+ return true;
+ }
+
+ return false;
+}
#endif
#ifdef HAVE_CACA
@@ -630,6 +659,9 @@ static bool font_init_first(
case FONT_DRIVER_RENDER_OPENGL_API:
return gl_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
+ case FONT_DRIVER_RENDER_OPENGL1_API:
+ return gl1_font_init_first(font_driver, font_handle,
+ video_data, font_path, font_size, is_threaded);
#endif
#ifdef HAVE_VULKAN
case FONT_DRIVER_RENDER_VULKAN_API:
diff --git a/gfx/font_driver.h b/gfx/font_driver.h
index 499c0a16e1..7e808311a1 100644
--- a/gfx/font_driver.h
+++ b/gfx/font_driver.h
@@ -157,6 +157,7 @@ void font_driver_init_osd(
void font_driver_free_osd(void);
extern font_renderer_t gl_raster_font;
+extern font_renderer_t gl1_raster_font;
extern font_renderer_t libdbg_font;
extern font_renderer_t d3d_xbox360_font;
extern font_renderer_t d3d_xdk1_font;
diff --git a/gfx/video_defines.h b/gfx/video_defines.h
index bf5a821972..b06287f5cc 100644
--- a/gfx/video_defines.h
+++ b/gfx/video_defines.h
@@ -83,6 +83,7 @@ enum font_driver_render_api
{
FONT_DRIVER_RENDER_DONT_CARE,
FONT_DRIVER_RENDER_OPENGL_API,
+ FONT_DRIVER_RENDER_OPENGL1_API,
FONT_DRIVER_RENDER_D3D8_API,
FONT_DRIVER_RENDER_D3D9_API,
FONT_DRIVER_RENDER_D3D10_API,
diff --git a/gfx/video_driver.c b/gfx/video_driver.c
index 9d7e308a0b..a6f5f29fae 100644
--- a/gfx/video_driver.c
+++ b/gfx/video_driver.c
@@ -260,6 +260,7 @@ struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = {
static const video_driver_t *video_drivers[] = {
#ifdef HAVE_OPENGL
&video_gl2,
+ &video_gl1,
#endif
#ifdef HAVE_VULKAN
&video_vulkan,
@@ -425,7 +426,6 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
NULL
};
-
bool video_driver_started_fullscreen(void)
{
return video_started_fullscreen;
diff --git a/gfx/video_driver.h b/gfx/video_driver.h
index 6e745f9c8a..fcdc17c5e3 100644
--- a/gfx/video_driver.h
+++ b/gfx/video_driver.h
@@ -1209,6 +1209,7 @@ bool video_driver_get_all_flags(gfx_ctx_flags_t *flags,
enum display_flags flag);
extern video_driver_t video_gl2;
+extern video_driver_t video_gl1;
extern video_driver_t video_vulkan;
extern video_driver_t video_metal;
extern video_driver_t video_psp1;
diff --git a/griffin/griffin.c b/griffin/griffin.c
index 7d54aead27..5d34ee0117 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -411,6 +411,7 @@ VIDEO DRIVER
#ifdef HAVE_OPENGL
#include "../gfx/drivers/gl.c"
+#include "../gfx/drivers/gl1.c"
#include "../libretro-common/gfx/gl_capabilities.c"
#ifndef HAVE_PSGL
@@ -488,6 +489,7 @@ FONTS
#if defined(HAVE_OPENGL)
#include "../gfx/drivers_font/gl_raster_font.c"
+#include "../gfx/drivers_font/gl1_raster_font.c"
#endif
#if defined(_XBOX1)
@@ -1248,6 +1250,7 @@ MENU
#ifdef HAVE_OPENGL
#include "../menu/drivers_display/menu_display_gl.c"
+#include "../menu/drivers_display/menu_display_gl1.c"
#endif
#ifdef HAVE_VULKAN
diff --git a/menu/drivers_display/menu_display_gl1.c b/menu/drivers_display/menu_display_gl1.c
new file mode 100644
index 0000000000..744bba10f6
--- /dev/null
+++ b/menu/drivers_display/menu_display_gl1.c
@@ -0,0 +1,223 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2011-2017 - Daniel De Matteis
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#include "../../retroarch.h"
+#include "../../gfx/font_driver.h"
+#include "../../gfx/video_driver.h"
+#include "../../gfx/common/gl1_common.h"
+
+#include "../menu_driver.h"
+
+static const GLfloat gl1_menu_vertexes[] = {
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1
+};
+
+static const GLfloat gl1_menu_tex_coords[] = {
+ 0, 1,
+ 1, 1,
+ 0, 0,
+ 1, 0
+};
+
+static const float *menu_display_gl1_get_default_vertices(void)
+{
+ return &gl1_menu_vertexes[0];
+}
+
+static const float *menu_display_gl1_get_default_tex_coords(void)
+{
+ return &gl1_menu_tex_coords[0];
+}
+
+static void *menu_display_gl1_get_default_mvp(video_frame_info_t *video_info)
+{
+ gl1_t *gl1 = video_info ? (gl1_t*)video_info->userdata : NULL;
+
+ if (!gl1)
+ return NULL;
+
+ return &gl1->mvp_no_rot;
+}
+
+static GLenum menu_display_prim_to_gl1_enum(
+ enum menu_display_prim_type type)
+{
+ switch (type)
+ {
+ case MENU_DISPLAY_PRIM_TRIANGLESTRIP:
+ return GL_TRIANGLE_STRIP;
+ case MENU_DISPLAY_PRIM_TRIANGLES:
+ return GL_TRIANGLES;
+ case MENU_DISPLAY_PRIM_NONE:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void menu_display_gl1_blend_begin(video_frame_info_t *video_info)
+{
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+static void menu_display_gl1_blend_end(video_frame_info_t *video_info)
+{
+ glDisable(GL_BLEND);
+}
+
+static void menu_display_gl1_viewport(menu_display_ctx_draw_t *draw,
+ video_frame_info_t *video_info)
+{
+ if (draw)
+ glViewport(draw->x, draw->y, draw->width, draw->height);
+}
+
+static void menu_display_gl1_draw(menu_display_ctx_draw_t *draw,
+ video_frame_info_t *video_info)
+{
+ video_shader_ctx_mvp_t mvp;
+ video_shader_ctx_coords_t coords;
+ gl1_t *gl1 = video_info ?
+ (gl1_t*)video_info->userdata : NULL;
+
+ if (!gl1 || !draw)
+ return;
+
+ if (!draw->coords->vertex)
+ draw->coords->vertex = menu_display_gl1_get_default_vertices();
+ if (!draw->coords->tex_coord)
+ draw->coords->tex_coord = menu_display_gl1_get_default_tex_coords();
+ if (!draw->coords->lut_tex_coord)
+ draw->coords->lut_tex_coord = menu_display_gl1_get_default_tex_coords();
+
+ menu_display_gl1_viewport(draw, video_info);
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, (GLuint)draw->texture);
+
+ coords.handle_data = gl1;
+ coords.data = draw->coords;
+
+ video_driver_set_coords(&coords);
+
+ mvp.data = gl1;
+ mvp.matrix = draw->matrix_data ? (math_matrix_4x4*)draw->matrix_data
+ : (math_matrix_4x4*)menu_display_gl1_get_default_mvp(video_info);
+
+ video_driver_set_mvp(&mvp);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(((math_matrix_4x4*)mvp.matrix)->data);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glColorPointer(4, GL_FLOAT, 0, draw->coords->color);
+ glVertexPointer(2, GL_FLOAT, 0, draw->coords->vertex);
+ glTexCoordPointer(2, GL_FLOAT, 0, draw->coords->tex_coord);
+
+ glDrawArrays(menu_display_prim_to_gl1_enum(
+ draw->prim_type), 0, draw->coords->vertices);
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ gl1->coords.color = gl1->white_color_ptr;
+}
+
+static void menu_display_gl1_restore_clear_color(void)
+{
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+static void menu_display_gl1_clear_color(
+ menu_display_ctx_clearcolor_t *clearcolor,
+ video_frame_info_t *video_info)
+{
+ if (!clearcolor)
+ return;
+
+ glClearColor(clearcolor->r,
+ clearcolor->g, clearcolor->b, clearcolor->a);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static bool menu_display_gl1_font_init_first(
+ void **font_handle, void *video_data,
+ const char *font_path, float menu_font_size,
+ bool is_threaded)
+{
+ font_data_t **handle = (font_data_t**)font_handle;
+ if (!(*handle = font_driver_init_first(video_data,
+ font_path, menu_font_size, true,
+ is_threaded,
+ FONT_DRIVER_RENDER_OPENGL1_API)))
+ return false;
+ return true;
+}
+
+static void menu_display_gl1_scissor_begin(video_frame_info_t *video_info, int x, int y,
+ unsigned width, unsigned height)
+{
+ glScissor(x, video_info->height - y - height, width, height);
+ glEnable(GL_SCISSOR_TEST);
+}
+
+static void menu_display_gl1_scissor_end(video_frame_info_t *video_info)
+{
+ glDisable(GL_SCISSOR_TEST);
+}
+
+menu_display_ctx_driver_t menu_display_ctx_gl1 = {
+ menu_display_gl1_draw,
+ NULL,
+ menu_display_gl1_viewport,
+ menu_display_gl1_blend_begin,
+ menu_display_gl1_blend_end,
+ menu_display_gl1_restore_clear_color,
+ menu_display_gl1_clear_color,
+ menu_display_gl1_get_default_mvp,
+ menu_display_gl1_get_default_vertices,
+ menu_display_gl1_get_default_tex_coords,
+ menu_display_gl1_font_init_first,
+ MENU_VIDEO_DRIVER_OPENGL1,
+ "gl1",
+ false,
+ menu_display_gl1_scissor_begin,
+ menu_display_gl1_scissor_end
+};
diff --git a/menu/menu_driver.c b/menu/menu_driver.c
index 311addcd7f..1375981f57 100644
--- a/menu/menu_driver.c
+++ b/menu/menu_driver.c
@@ -126,6 +126,7 @@ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = {
#endif
#ifdef HAVE_OPENGL
&menu_display_ctx_gl,
+ &menu_display_ctx_gl1,
#endif
#ifdef HAVE_VULKAN
&menu_display_ctx_vulkan,
@@ -274,6 +275,10 @@ static bool menu_display_check_compatibility(
if (string_is_equal(video_driver, "gl"))
return true;
break;
+ case MENU_VIDEO_DRIVER_OPENGL1:
+ if (string_is_equal(video_driver, "gl1"))
+ return true;
+ break;
case MENU_VIDEO_DRIVER_VULKAN:
if (string_is_equal(video_driver, "vulkan"))
return true;
@@ -781,7 +786,8 @@ void menu_display_draw_bg(menu_display_ctx_draw_t *draw,
if (!draw->texture)
draw->texture = menu_display_white_texture;
- draw->matrix_data = (math_matrix_4x4*)menu_disp->get_default_mvp(video_info);
+ if (menu_disp && menu_disp->get_default_mvp)
+ draw->matrix_data = (math_matrix_4x4*)menu_disp->get_default_mvp(video_info);
}
void menu_display_draw_gradient(menu_display_ctx_draw_t *draw,
diff --git a/menu/menu_driver.h b/menu/menu_driver.h
index 58cb2afac8..727c078370 100644
--- a/menu/menu_driver.h
+++ b/menu/menu_driver.h
@@ -692,6 +692,7 @@ void menu_subsystem_populate(const struct retro_subsystem_info* subsystem, menu_
extern uintptr_t menu_display_white_texture;
extern menu_display_ctx_driver_t menu_display_ctx_gl;
+extern menu_display_ctx_driver_t menu_display_ctx_gl1;
extern menu_display_ctx_driver_t menu_display_ctx_vulkan;
extern menu_display_ctx_driver_t menu_display_ctx_metal;
extern menu_display_ctx_driver_t menu_display_ctx_d3d8;