gl: update
authornotaz <notasas@gmail.com>
Wed, 14 May 2025 16:44:58 +0000 (19:44 +0300)
committernotaz <notasas@gmail.com>
Fri, 16 May 2025 13:12:14 +0000 (16:12 +0300)
- more error checking
- add a workaround for mesa compiled without OpenGL ES1.x (but with egl)
- don't leave half-initialized state (and just a black screen) on error
- clear texture memory, otherwise edges sometimes pick up noise from
  filtering taking garbage texels behind the edges
- allow to pass vertices to flip
- new clear function

gl.c
gl.h

diff --git a/gl.c b/gl.c
index c5c5050..975520e 100644 (file)
--- a/gl.c
+++ b/gl.c
@@ -1,14 +1,16 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <assert.h>
 
 #include <EGL/egl.h>
 #include <GLES/gl.h>
 #include "gl_platform.h"
 #include "gl.h"
 
-static EGLDisplay edpy;
-static EGLSurface esfc;
-static EGLContext ectxt;
+static EGLDisplay edpy = EGL_NO_DISPLAY;
+static EGLSurface esfc = EGL_NO_SURFACE;
+static EGLContext ectxt = EGL_NO_CONTEXT;
 
 static GLuint texture_name;
 
@@ -46,7 +48,7 @@ int gl_init(void *display, void *window, int *quirks, int w, int h)
        EGLint num_config;
        int retval = -1;
        int ret;
-       EGLint attr[] =
+       EGLint config_attr[] =
        {
                EGL_NONE
        };
@@ -67,6 +69,7 @@ int gl_init(void *display, void *window, int *quirks, int w, int h)
                fprintf(stderr, "OOM\n");
                goto out;
        }
+       memset(tex_mem, 0, tex_w * tex_h * 2);
 
        edpy = eglGetDisplay((EGLNativeDisplayType)display);
        if (edpy == EGL_NO_DISPLAY) {
@@ -79,7 +82,7 @@ int gl_init(void *display, void *window, int *quirks, int w, int h)
                goto out;
        }
 
-       if (!eglChooseConfig(edpy, attr, &ecfg, 1, &num_config)) {
+       if (!eglChooseConfig(edpy, config_attr, &ecfg, 1, &num_config)) {
                fprintf(stderr, "Failed to choose config (%x)\n", eglGetError());
                goto out;
        }
@@ -101,19 +104,39 @@ int gl_init(void *display, void *window, int *quirks, int w, int h)
        if (ectxt == EGL_NO_CONTEXT) {
                fprintf(stderr, "Unable to create EGL context (%x)\n",
                        eglGetError());
-               goto out;
+               // on mesa, some distros disable ES1.x but compat GL still works
+               ret = eglBindAPI(EGL_OPENGL_API);
+               if (!ret) {
+                       fprintf(stderr, "eglBindAPI: %x\n", eglGetError());
+                       goto out;
+               }
+               ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL);
+               if (ectxt == EGL_NO_CONTEXT) {
+                       fprintf(stderr, "giving up on EGL context (%x)\n",
+                               eglGetError());
+                       goto out;
+               }
        }
 
-       eglMakeCurrent(edpy, esfc, esfc, ectxt);
+       ret = eglMakeCurrent(edpy, esfc, esfc, ectxt);
+       if (!ret) {
+               fprintf(stderr, "eglMakeCurrent: %x\n", eglGetError());
+               goto out;
+       }
 
+       // 1.x (fixed-function) only
        glEnable(GL_TEXTURE_2D);
+       glGetError();
 
-       if (texture_name)
-               glDeleteTextures(1, &texture_name);
+       assert(!texture_name);
 
        glGenTextures(1, &texture_name);
+       if (gl_have_error("glGenTextures"))
+               goto out;
 
        glBindTexture(GL_TEXTURE_2D, texture_name);
+       if (gl_have_error("glBindTexture"))
+               goto out;
 
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h, 0, GL_RGB,
                GL_UNSIGNED_SHORT_5_6_5, tex_mem);
@@ -139,15 +162,18 @@ int gl_init(void *display, void *window, int *quirks, int w, int h)
        gl_es_surface = (void *)esfc;
        retval = 0;
 out:
+       if (retval && edpy != EGL_NO_DISPLAY)
+               gl_finish();
        return retval;
 }
 
 void gl_announce(void)
 {
        printf("GL_RENDERER: %s\n", (char *)glGetString(GL_RENDERER));
+       printf("GL_VERSION: %s\n", (char *)glGetString(GL_VERSION));
 }
 
-static float vertices[] = {
+static const float default_vertices[] = {
        -1.0f,  1.0f,  0.0f, // 0    0  1
         1.0f,  1.0f,  0.0f, // 1  ^
        -1.0f, -1.0f,  0.0f, // 2  | 2  3
@@ -161,8 +187,14 @@ static float texture[] = {
        1.0f, 1.0f, //  +-->
 };
 
-int gl_flip(const void *fb, int w, int h)
+int gl_flip_v(const void *fb, int w, int h, const float *vertices)
 {
+       gl_have_error("pre-flip unknown");
+
+       glBindTexture(GL_TEXTURE_2D, texture_name);
+       if (gl_have_error("glBindTexture"))
+               return -1;
+
        if (fb != NULL) {
                if (w != flip_old_w || h != flip_old_h) {
                        float f_w = (float)w / tex_w;
@@ -177,14 +209,15 @@ int gl_flip(const void *fb, int w, int h)
 
                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
-               if (gl_have_error("glTexSubImage2D"))
+               if (gl_have_error("glTexSubImage2D")) {
+                       fprintf(stderr, "  %dx%d t: %dx%d %p\n", w, h, tex_w, tex_h, fb);
                        return -1;
+               }
        }
 
-       glVertexPointer(3, GL_FLOAT, 0, vertices);
+       glVertexPointer(3, GL_FLOAT, 0, vertices ? vertices : default_vertices);
        glTexCoordPointer(2, GL_FLOAT, 0, texture);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
        if (gl_have_error("glDrawArrays"))
                return -1;
 
@@ -195,15 +228,49 @@ int gl_flip(const void *fb, int w, int h)
        return 0;
 }
 
+int gl_flip(const void *fb, int w, int h)
+{
+       return gl_flip_v(fb, w, h, NULL);
+}
+
+// to be used once after exiting menu, etc
+void gl_clear(void)
+{
+       glClearColor(0, 0, 0, 0);
+       glClear(GL_COLOR_BUFFER_BIT);
+       eglSwapBuffers(edpy, esfc);
+       glClear(GL_COLOR_BUFFER_BIT);
+       eglSwapBuffers(edpy, esfc);
+       glClear(GL_COLOR_BUFFER_BIT);
+       gl_have_error("glClear");
+}
+
 void gl_finish(void)
 {
+       // sometimes there is an error... from somewhere?
+       //gl_have_error("finish");
+       glGetError();
+
+       if (texture_name)
+       {
+               glDeleteTextures(1, &texture_name);
+               gl_have_error("glDeleteTextures");
+               texture_name = 0;
+       }
+
        eglMakeCurrent(edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-       eglDestroyContext(edpy, ectxt);
-       ectxt = EGL_NO_CONTEXT;
-       eglDestroySurface(edpy, esfc);
-       esfc = EGL_NO_SURFACE;
-       eglTerminate(edpy);
-       edpy = EGL_NO_DISPLAY;
+       if (ectxt != EGL_NO_CONTEXT) {
+               eglDestroyContext(edpy, ectxt);
+               ectxt = EGL_NO_CONTEXT;
+       }
+       if (esfc != EGL_NO_SURFACE) {
+               eglDestroySurface(edpy, esfc);
+               esfc = EGL_NO_SURFACE;
+       }
+       if (edpy != EGL_NO_DISPLAY) {
+               eglTerminate(edpy);
+               edpy = EGL_NO_DISPLAY;
+       }
 
        gl_es_display = (void *)edpy;
        gl_es_surface = (void *)esfc;
diff --git a/gl.h b/gl.h
index bddacdc..760960d 100644 (file)
--- a/gl.h
+++ b/gl.h
@@ -5,7 +5,9 @@
 
 int  gl_init(void *display, void *window, int *quirks, int w, int h);
 void gl_announce(void);
+int  gl_flip_v(const void *fb, int w, int h, const float *vertices);
 int  gl_flip(const void *fb, int w, int h);
+void gl_clear(void);
 void gl_finish(void);
 
 /* for external flips */
@@ -21,13 +23,16 @@ static __inline int gl_init(void *display, void *window, int *quirks, int w, int
 static __inline void gl_announce(void)
 {
 }
-static __inline int gl_flip(const void *fb, int w, int h)
+static __inline int gl_flip_v(const void *fb, int w, int h, const float *vertices)
 {
   return -1;
 }
-static __inline void gl_finish(void)
+static __inline int gl_flip(const void *fb, int w, int h)
 {
+  return -1;
 }
+static __inline void gl_clear(void) {}
+static __inline void gl_finish(void) {}
 
 #define gl_es_display (void *)0
 #define gl_es_surface (void *)0