ref: 4f97999d66ba83fa51dbfda53e2e1bcd348f6150
parent: 70a08f116cc48d82908b440def4a5fbb2da9edff
author: vanfanel <redwindwanderer@gmail.com>
date: Mon Dec 12 08:28:09 EST 2022
Fix OpenGL ES support (Fixes #192) Co-authored-by: Snesrev <snesrev@protonmail.com>
--- a/config.c
+++ b/config.c
@@ -354,7 +354,9 @@
return true;
} else if (StringEqualsNoCase(key, "OutputMethod")) {
g_config.output_method = StringEqualsNoCase(value, "SDL-Software") ? kOutputMethod_SDLSoftware :
- StringEqualsNoCase(value, "OpenGL") ? kOutputMethod_OpenGL : kOutputMethod_SDL;
+ StringEqualsNoCase(value, "OpenGL") ? kOutputMethod_OpenGL :
+ StringEqualsNoCase(value, "OpenGL ES") ? kOutputMethod_OpenGL_ES :
+ kOutputMethod_SDL;
return true;
} else if (StringEqualsNoCase(key, "LinearFiltering")) {
return ParseBool(value, &g_config.linear_filtering);
--- a/config.h
+++ b/config.h
@@ -41,6 +41,7 @@
kOutputMethod_SDL,
kOutputMethod_SDLSoftware,
kOutputMethod_OpenGL,
+ kOutputMethod_OpenGL_ES,
};
typedef struct Config {
--- a/glsl_shader.c
+++ b/glsl_shader.c
@@ -212,9 +212,11 @@
free(data_org);
}
-static bool GlslPass_Compile(GlslPass *p, uint type, const uint8 *data, size_t size) {
+static bool GlslPass_Compile(GlslPass *p, uint type, const uint8 *data, size_t size, bool use_opengl_es) {
static const char kVertexPrefix[] = "#define VERTEX\n#define PARAMETER_UNIFORM\n";
- static const char kFragmentPrefix[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n";
+ static const char kFragmentPrefixCore[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n";
+ static const char kFragmentPrefixEs[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n" \
+ "precision mediump float;";
const GLchar *strings[3];
GLint lengths[3];
char buffer[256];
@@ -222,15 +224,25 @@
size_t skip = 0;
if (size < 8 || memcmp(data, "#version", 8) != 0) {
- strings[0] = "#version 330\n";
- lengths[0] = sizeof("#version 330\n") - 1;
+ if (!use_opengl_es) {
+ strings[0] = "#version 330\n";
+ lengths[0] = sizeof("#version 330\n") - 1;
+ } else {
+ strings[0] = "#version 300 es\n";
+ lengths[0] = sizeof("#version 300 es\n") - 1;
+ }
} else {
while (skip < size && data[skip++] != '\n') {}
strings[0] = (char*)data;
lengths[0] = (int)skip;
}
- strings[1] = (type == GL_VERTEX_SHADER) ? (char*)kVertexPrefix : kFragmentPrefix;
- lengths[1] = (type == GL_VERTEX_SHADER) ? sizeof(kVertexPrefix) - 1 : sizeof(kFragmentPrefix) - 1;
+ if (type == GL_VERTEX_SHADER) {
+ strings[1] = (char *)kVertexPrefix;
+ lengths[1] = sizeof(kVertexPrefix) - 1;
+ } else {
+ strings[1] = (use_opengl_es) ? (char *)kFragmentPrefixEs : kFragmentPrefixCore;
+ lengths[1] = (use_opengl_es) ? sizeof(kFragmentPrefixEs) - 1 : sizeof(kFragmentPrefixCore) - 1;
+ }
strings[2] = (GLchar *)data + skip;
lengths[2] = (int)(size - skip);
uint shader = glCreateShader(type);
@@ -311,7 +323,7 @@
return len >= 5 && memcmp(filename + len - 5, ".glsl", 5) == 0;
}
-GlslShader *GlslShader_CreateFromFile(const char *filename) {
+GlslShader *GlslShader_CreateFromFile(const char *filename, bool opengl_es) {
char buffer[256];
GLint link_status;
ByteArray shader_code = { 0 };
@@ -348,8 +360,8 @@
goto FAIL;
}
p->gl_program = glCreateProgram();
- if (!GlslPass_Compile(p, GL_VERTEX_SHADER, shader_code.data, shader_code.size) ||
- !GlslPass_Compile(p, GL_FRAGMENT_SHADER, shader_code.data, shader_code.size)) {
+ if (!GlslPass_Compile(p, GL_VERTEX_SHADER, shader_code.data, shader_code.size, opengl_es) ||
+ !GlslPass_Compile(p, GL_FRAGMENT_SHADER, shader_code.data, shader_code.size, opengl_es)) {
goto FAIL;
}
glLinkProgram(p->gl_program);
--- a/glsl_shader.h
+++ b/glsl_shader.h
@@ -91,7 +91,7 @@
GlTextureWithSize prev_frame[8];
} GlslShader;
-GlslShader *GlslShader_CreateFromFile(const char *filename);
+GlslShader *GlslShader_CreateFromFile(const char *filename, bool opengl_es);
void GlslShader_Destroy(GlslShader *gs);
void GlslShader_Render(GlslShader *gs, GlTextureWithSize *tex, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
--- a/main.c
+++ b/main.c
@@ -29,8 +29,6 @@
static bool g_run_without_emu = 0;
-void ShaderInit();
-
// Forwards
static bool LoadRom(const char *filename);
static void LoadLinkGraphics();
@@ -45,7 +43,6 @@
static void LoadAssets();
static void SwitchDirectory();
-
enum {
kDefaultFullscreen = 0,
kMaxWindowScale = 10,
@@ -55,7 +52,6 @@
};
static const char kWindowTitle[] = "The Legend of Zelda: A Link to the Past";
-
static uint32 g_win_flags = SDL_WINDOW_RESIZABLE;
static SDL_Window *g_window;
@@ -278,7 +274,7 @@
&SdlRenderer_EndDraw,
};
-void OpenGLRenderer_Create(struct RendererFuncs *funcs);
+void OpenGLRenderer_Create(struct RendererFuncs *funcs, bool use_opengl_es);
#undef main
int main(int argc, char** argv) {
@@ -339,9 +335,10 @@
int window_width = custom_size ? g_config.window_width : g_current_window_scale * g_snes_width;
int window_height = custom_size ? g_config.window_height : g_current_window_scale * g_snes_height;
- if (g_config.output_method == kOutputMethod_OpenGL) {
+ if (g_config.output_method == kOutputMethod_OpenGL ||
+ g_config.output_method == kOutputMethod_OpenGL_ES) {
g_win_flags |= SDL_WINDOW_OPENGL;
- OpenGLRenderer_Create(&g_renderer_funcs);
+ OpenGLRenderer_Create(&g_renderer_funcs, (g_config.output_method == kOutputMethod_OpenGL_ES));
} else {
g_renderer_funcs = kSdlRendererFuncs;
}
--- a/opengl.c
+++ b/opengl.c
@@ -16,6 +16,7 @@
static unsigned int g_program, g_VAO;
static GlTextureWithSize g_texture;
static GlslShader *g_glsl_shader;
+static bool g_opengl_es;
static void GL_APIENTRY MessageCallback(GLenum source,
GLenum type,
@@ -42,9 +43,18 @@
SDL_GL_SetSwapInterval(1);
ogl_LoadFunctions();
- if (!ogl_IsVersionGEQ(3, 3))
- Die("You need OpenGL 3.3");
+ if (!g_opengl_es) {
+ if (!ogl_IsVersionGEQ(3, 3))
+ Die("You need OpenGL 3.3");
+ } else {
+ int majorVersion = 0, minorVersion = 0;
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
+ if (majorVersion < 3)
+ Die("You need OpenGL ES 3.0");
+ }
+
if (kDebugFlag) {
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -80,7 +90,7 @@
glEnableVertexAttribArray(1);
// vertex shader
- const GLchar *vs_code = "#version 330 core\n" CODE(
+ const GLchar *vs_code_core = "#version 330 core\n" CODE(
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
@@ -90,6 +100,17 @@
}
);
+ const GLchar *vs_code_es = "#version 300 es\n" CODE(
+ layout(location = 0) in vec3 aPos;
+ layout(location = 1) in vec2 aTexCoord;
+ out vec2 TexCoord;
+ void main() {
+ gl_Position = vec4(aPos, 1.0);
+ TexCoord = vec2(aTexCoord.x, aTexCoord.y);
+ }
+);
+
+ const GLchar *vs_code = g_opengl_es ? vs_code_es : vs_code_core;
unsigned int vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vs_code, NULL);
glCompileShader(vs);
@@ -103,7 +124,7 @@
}
// fragment shader
- const GLchar *fs_code = "#version 330 core\n" CODE(
+ const GLchar *fs_code_core = "#version 330 core\n" CODE(
out vec4 FragColor;
in vec2 TexCoord;
// texture samplers
@@ -113,6 +134,19 @@
}
);
+ const GLchar *fs_code_es = "#version 300 es\n" CODE(
+ precision mediump float;
+ out vec4 FragColor;
+ in vec2 TexCoord;
+ // texture samplers
+ uniform sampler2D texture1;
+ void main() {
+ FragColor = texture(texture1, TexCoord);
+ }
+);
+
+
+ const GLchar *fs_code = g_opengl_es ? fs_code_es : fs_code_core;
unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fs_code, NULL);
glCompileShader(fs);
@@ -136,7 +170,7 @@
}
if (g_config.shader)
- g_glsl_shader = GlslShader_CreateFromFile(g_config.shader);
+ g_glsl_shader = GlslShader_CreateFromFile(g_config.shader, g_opengl_es);
return true;
}
@@ -178,11 +212,17 @@
glBindTexture(GL_TEXTURE_2D, g_texture.gl_texture);
if (g_draw_width == g_texture.width && g_draw_height == g_texture.height) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
+ if (!g_opengl_es)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
+ else
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_BYTE, g_screen_buffer);
} else {
g_texture.width = g_draw_width;
g_texture.height = g_draw_height;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
+ if (!g_opengl_es)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, g_screen_buffer);
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@@ -203,7 +243,6 @@
SDL_GL_SwapWindow(g_window);
}
-
static const struct RendererFuncs kOpenGLRendererFuncs = {
&OpenGLRenderer_Init,
&OpenGLRenderer_Destroy,
@@ -211,10 +250,17 @@
&OpenGLRenderer_EndDraw,
};
-void OpenGLRenderer_Create(struct RendererFuncs *funcs) {
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+void OpenGLRenderer_Create(struct RendererFuncs *funcs, bool use_opengl_es) {
+ g_opengl_es = use_opengl_es;
+ if (!g_opengl_es) {
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ } else {
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ }
*funcs = kOpenGLRendererFuncs;
}