From 8882e5cc84589f1caaef25c32a2d9e66beb764d4 Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Tue, 11 Aug 2026 20:18:19 +0300 Subject: [PATCH 1/4] functions: add a couple of missing stubs The SDL3 test program testgl[1] loads all the GL functions declared in the render backend[2] and fails to start if any of these fail. Exporting these two functions allows the testgl program to run. [1]: https://github.com/libsdl-org/SDL/blob/main/test/testgl.c [2]: https://github.com/libsdl-org/SDL/blob/main/src/render/opengl/SDL_glfuncs.h --- src/functions.c | 2 ++ src/gc_gl.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/functions.c b/src/functions.c index 457dfed..832f013 100644 --- a/src/functions.c +++ b/src/functions.c @@ -51,7 +51,9 @@ static const OgxProcMap s_proc_map[] = { PROC(glBindBuffer), /* OpenGL 1.5 */ PROC(glBindTexture), PROC(glBitmap), + PROC(glBlendEquation), PROC(glBlendFunc), + PROC(glBlendFuncSeparate), PROC(glBufferData), /* OpenGL 1.5 */ PROC(glBufferSubData), /* OpenGL 1.5 */ PROC(glCallList), diff --git a/src/gc_gl.c b/src/gc_gl.c index 2af568e..9424ffc 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -2826,6 +2826,8 @@ void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdou // NOT GOING TO IMPLEMENT void glBlendEquation(GLenum mode) {} +void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorAlpha, GLenum dfactorAlpha) {} void glShadeModel(GLenum mode) {} // In theory we don't have GX equivalent? void glHint(GLenum target, GLenum mode) {} From 0e2710455cb2fae5a58493e77711a5536a4d69be Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Fri, 14 Aug 2026 21:08:38 +0300 Subject: [PATCH 2/4] blending: add a simplistic implementation of glBlendFuncSeparate() This is completely missing out the alpha function, but is good enough to make the SDL3's OpenGL renderer to work. --- src/gc_gl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gc_gl.c b/src/gc_gl.c index 9424ffc..ee51c39 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -1670,6 +1670,13 @@ void glBlendFunc(GLenum sfactor, GLenum dfactor) glparamstate.dirty.bits.dirty_blend = 1; } +void glBlendFuncSeparate(GLenum sfactor_rgb, GLenum dfactor_rgb, + GLenum sfactor_alpha, GLenum dfactor_alpha) +{ + /* This is not correct, but better than nothing */ + glBlendFunc(sfactor_rgb, dfactor_rgb); +} + void glPointSize(GLfloat size) { unsigned int gxsize = size; @@ -2826,8 +2833,6 @@ void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdou // NOT GOING TO IMPLEMENT void glBlendEquation(GLenum mode) {} -void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorAlpha, GLenum dfactorAlpha) {} void glShadeModel(GLenum mode) {} // In theory we don't have GX equivalent? void glHint(GLenum target, GLenum mode) {} From 27b207561d15fdba7af27ed8d0c34a642f0d095d Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Fri, 14 Aug 2026 23:28:23 +0300 Subject: [PATCH 3/4] efb: do not restore the EFB contents if they were not changed Restore the condition check as it was before commit 6a474f851fe59ba3030fcc46912 (fbo: implement FBO API). Unfortunately that commit does not explain why this change was made, it may also be that it was only needed during certain stages of development; by itself, the change does not make much sense and it break at least one very simple use case: 1. Bind an empty texture to the FB (let's call it "A") 2. Draw a couple of textures 3. Unbind the FB 4. Draw the texture "A" on the screen 5. Error: the first texture drawn in point 2 will be vertically flipped This is what happens running SDL3's testrendercopyex.c test using the OpenGL render backend (backed by opengx). This commit fixes that case. --- src/efb.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/efb.h b/src/efb.h index 1fa8ab1..d6e5a99 100644 --- a/src/efb.h +++ b/src/efb.h @@ -85,8 +85,7 @@ void _ogx_efb_set_content_type_real(OgxEfbContentType content_type); /* We inline this part since most of the times the desired content type will be * the one already active */ static inline void _ogx_efb_set_content_type(OgxEfbContentType content_type) { - if (content_type == _ogx_efb_content_type && - (content_type != OGX_EFB_SCENE || _ogx_fbo_state.dirty.all == 0)) + if (content_type == _ogx_efb_content_type) return; _ogx_efb_set_content_type_real(content_type); } From f7ca42b7e4a9be8b71ac1465b3be4342a859cbfa Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Sat, 15 Aug 2026 09:43:20 +0300 Subject: [PATCH 4/4] fbo: add function pointers, declare FBO extension Improve the way the FBO module is used: 1. Add FBO functions (both with the OpenGL 3.0 name and with the older "EXT" suffix) to the ogx_get_proc_address() lookup tables. This is done only if the FBO module is actually used, using the same weak symbol trick we use for the shader functions. 2. Add a ogx_enable_module_fbo() function that the client can call to force the inclusion of the FBO code. This function also registers the GL_EXT_framebuffer_object extension. With these changes the OpenGL renderer backend in SDL3 can be used with opengx without any changes (other than calling ogx_enable_module_fbo() in its initialization code). --- src/fbo.c | 25 +++++++++++++++++++++++++ src/fbo.h | 8 +++++++- src/functions.c | 8 ++++++++ src/getters.c | 10 ++++++++-- src/opengx.h | 3 +++ src/utils.h | 2 ++ 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/fbo.c b/src/fbo.c index 3eb4314..d64fc4b 100644 --- a/src/fbo.c +++ b/src/fbo.c @@ -367,3 +367,28 @@ void glFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, warning("glFramebufferTexture3D is unsupported"); set_error(GL_INVALID_OPERATION); } + +void ogx_enable_module_fbo() { + _ogx_add_extension("GL_EXT_framebuffer_object"); +} + +/* FBOs are in OpenGL 3.0, and in older versions as an extension */ +#define PROC(name) \ + { #name, name }, \ + { #name "EXT", name } +static const OgxProcMap s_proc_map[] = { + PROC(glBindFramebuffer), + PROC(glCheckFramebufferStatus), + PROC(glDeleteFramebuffers), + PROC(glFramebufferTexture1D), + PROC(glFramebufferTexture2D), + PROC(glFramebufferTexture3D), + PROC(glGenFramebuffers), + PROC(glIsFramebuffer), +}; +#define NUM_PROCS (sizeof(s_proc_map) / sizeof(s_proc_map[0])) + +OgxFunctions _ogx_fbo_functions = { + NUM_PROCS, + s_proc_map, +}; diff --git a/src/fbo.h b/src/fbo.h index 50b1492..1c35c70 100644 --- a/src/fbo.h +++ b/src/fbo.h @@ -87,7 +87,11 @@ bool _ogx_fbo_get_integerv(GLenum pname, GLint *params); void _ogx_fbo_scene_save_from_efb(OgxEfbContentType next_content_type); void _ogx_fbo_scene_load_into_efb(void); -#ifndef BUILDING_FBO_CODE +#ifdef BUILDING_FBO_CODE + +extern OgxFunctions _ogx_fbo_functions; + +#else /* BUILDING_FBO_CODE not defined */ OgxFboState _ogx_fbo_state __attribute__((weak)) = { 0, 0 }; @@ -106,6 +110,8 @@ void __attribute__((weak)) _ogx_fbo_scene_load_into_efb() _ogx_scene_load_into_efb(); } +OgxFunctions _ogx_fbo_functions __attribute__((weak)) = { 0, NULL }; + #endif /* BUILDING_FBO_CODE */ #ifdef __cplusplus diff --git a/src/functions.c b/src/functions.c index 832f013..4715e1c 100644 --- a/src/functions.c +++ b/src/functions.c @@ -29,6 +29,7 @@ POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ #define GL_GLEXT_PROTOTYPES 1 +#include "fbo.h" #include "opengx.h" #include "shader.h" #include "types.h" @@ -472,5 +473,12 @@ void *ogx_get_proc_address(const char *proc) proc); if (ret) return ret; } + + if (_ogx_fbo_functions.num_functions > 0) { + ret = search_in_functions(_ogx_fbo_functions.functions, + _ogx_fbo_functions.num_functions, + proc); + if (ret) return ret; + } return search_in_functions(s_proc_map, NUM_PROCS, proc); } diff --git a/src/getters.c b/src/getters.c index 23b8468..cfe38ce 100644 --- a/src/getters.c +++ b/src/getters.c @@ -40,8 +40,9 @@ POSSIBILITY OF SUCH DAMAGE. #include static const GLubyte gl_null_string[1] = { 0 }; -/* This is not static because we might modify it in place */ -static GLubyte s_extension_string[] = +/* This is not const because we might modify it in place. + * Make sure that this buffer is large enough to fit all added extensions. */ +static GLubyte s_extension_string[256] = "GL_ARB_multitexture " "GL_ARB_vertex_buffer_object "; @@ -72,6 +73,11 @@ static GLubyte *get_extension_string(int index) return ptr; } +void _ogx_add_extension(const GLubyte *name) +{ + strcat(s_extension_string, name); +} + GLenum glGetError(void) { GLenum error = glparamstate.error; diff --git a/src/opengx.h b/src/opengx.h index 9a16111..4aa7ce1 100644 --- a/src/opengx.h +++ b/src/opengx.h @@ -254,6 +254,9 @@ static inline void ogx_shader_set_modelview_gl(const GLfloat *matrix) * matrices, and uploads them separately to GX. */ void ogx_shader_set_mvp_gl(const GLfloat *matrix); +/* Force the inclusion of the FBO code into the program */ +void ogx_enable_module_fbo(); + #ifdef __cplusplus } // extern C #endif diff --git a/src/utils.h b/src/utils.h index dc414d4..0143e40 100644 --- a/src/utils.h +++ b/src/utils.h @@ -355,6 +355,8 @@ void _ogx_set_projection(const Mtx44 matrix); bool _ogx_setup_render_stages(void); void _ogx_update_vertex_array_readers(OgxDrawMode mode); +void _ogx_add_extension(const GLubyte *name); + #ifdef __cplusplus } // extern C #endif