From 68898f5aa43eaa28621c3d64505466ee91f9f98c Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Tue, 3 Mar 2026 10:10:04 +0000
Subject: [PATCH] video/out: add OpenGL 2.0 support

Add support for OpenGL 2.0 for legacy systems like macOS 10.6.

Changes:
- Lower minimum OpenGL version from 2.1 to 2.0
- Update GLSL version: GL 2.0 uses GLSL 110, GL 2.1+ uses GLSL 120
- Update format flags comments to reflect GL 2.0-2.x range
- Update error messages to mention GL 2.0 instead of 2.1
- Load GL 2.0 core functions (same as 2.1)
- Note: F_GL2 flag already correctly matches GL 2.0-2.x range
- Note: F_GL2F flag covers GL 2.x with extensions (texture_rg, etc.)

This allows mpv to run on systems with OpenGL 2.0 drivers, such as
older macOS versions and legacy graphics hardware.
---
 video/out/gpu/video.c           |  2 +-
 video/out/hwdec/hwdec_cuda_gl.c |  4 ++--
 video/out/opengl/common.c       | 13 +++++++------
 video/out/opengl/context.c      |  1 +
 video/out/opengl/formats.c      |  4 ++--
 video/out/opengl/formats.h      |  4 ++--
 video/out/opengl/ra_gl.c        |  4 ++--
 7 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index f9649501f7..50addcc0d6 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -3060,7 +3060,7 @@ static float chroma_realign(int size, int pixel)
     return size / (float)chroma_upsize(size, pixel);
 }
 
-// Minimal rendering code path, for GLES or OpenGL 2.1 without proper FBOs.
+// Minimal rendering code path, for GLES or OpenGL 2.0 without proper FBOs.
 static void pass_render_frame_dumb(struct gl_video *p)
 {
     struct image img[4];
diff --git a/video/out/hwdec/hwdec_cuda_gl.c b/video/out/hwdec/hwdec_cuda_gl.c
index 4c2535232f..ce590cc724 100644
--- a/video/out/hwdec/hwdec_cuda_gl.c
+++ b/video/out/hwdec/hwdec_cuda_gl.c
@@ -110,8 +110,8 @@ static bool cuda_gl_check(const struct ra_hwdec *hw) {
         return false; // This is not an OpenGL RA.
 
     GL *gl = ra_gl_get(hw->ra_ctx->ra);
-    if (gl->version < 210 && gl->es < 300) {
-        MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n");
+    if (gl->version < 200 && gl->es < 300) {
+        MP_VERBOSE(hw, "need OpenGL >= 2.0 or OpenGL-ES >= 3.0\n");
         return false;
     }
 
diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c
index a5de79c901..f51f4ddf29 100644
--- a/video/out/opengl/common.c
+++ b/video/out/opengl/common.c
@@ -89,10 +89,10 @@ struct gl_functions {
 // Note: to keep the number of sections low, some functions are in multiple
 //       sections (if there are tricky combinations of GL/ES versions)
 static const struct gl_functions gl_functions[] = {
-    // GL 2.1+ desktop and GLES 2.0+ (anything we support)
-    // Probably all of these are in GL 2.0 too, but we require GLSL 120.
+    // GL 2.0+ desktop and GLES 2.0+ (anything we support)
+    // All these functions are in GL 2.0 core.
     {
-        .ver_core = 210,
+        .ver_core = 200,
         .ver_es_core = 200,
         .functions = (const struct gl_function[]) {
             DEF_FN(ActiveTexture),
@@ -150,9 +150,9 @@ static const struct gl_functions gl_functions[] = {
             {0}
         },
     },
-    // GL 2.1+ desktop only (and GLSL 120 shaders)
+    // GL 2.0+ desktop only (these are not in GLES 2.0)
     {
-        .ver_core = 210,
+        .ver_core = 200,
         .provides = MPGL_CAP_ROW_LENGTH | MPGL_CAP_1D_TEX,
         .functions = (const struct gl_function[]) {
             DEF_FN(DrawBuffer),
@@ -649,7 +649,8 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
         if (gl->es >= 300)
             gl->glsl_version = gl->es;
     } else {
-        gl->glsl_version = 120;
+        // GL 2.0 supports GLSL 110, GL 2.1+ supports GLSL 120
+        gl->glsl_version = gl->version >= 210 ? 120 : 110;
         int glsl_major = 0, glsl_minor = 0;
         if (shader && sscanf(shader, "%d.%d", &glsl_major, &glsl_minor) == 2)
             gl->glsl_version = glsl_major * 100 + glsl_minor;
diff --git a/video/out/opengl/context.c b/video/out/opengl/context.c
index 31675dc4f2..810df30dda 100644
--- a/video/out/opengl/context.c
+++ b/video/out/opengl/context.c
@@ -34,6 +34,7 @@ const int mpgl_min_required_gl_versions[] = {
     440,
     320,
     210,
+    200,
     0
 };
 
diff --git a/video/out/opengl/formats.c b/video/out/opengl/formats.c
index dd0e89d54d..7ea1e84048 100644
--- a/video/out/opengl/formats.c
+++ b/video/out/opengl/formats.c
@@ -104,7 +104,7 @@ const struct gl_format gl_formats[] = {
 // Return an or-ed combination of all F_ flags that apply.
 int gl_format_feature_flags(GL *gl)
 {
-    return (gl->version == 210 ? F_GL2 : 0)
+    return (gl->version >= 200 && gl->version < 300 ? F_GL2 : 0)
          | (gl->version >= 300 ? F_GL3 : 0)
          | (gl->es == 200 ? F_ES2 : 0)
          | (gl->es >= 300 ? F_ES3 : 0)
@@ -112,7 +112,7 @@ int gl_format_feature_flags(GL *gl)
          | (gl->mpgl_caps & MPGL_CAP_EXT16 ? F_EXT16 : 0)
          | ((gl->es >= 300 &&
             (gl->mpgl_caps & MPGL_CAP_EXT_CR_HFLOAT)) ? F_EXTF16 : 0)
-         | ((gl->version == 210 &&
+         | ((gl->version >= 200 && gl->version < 300 &&
             (gl->mpgl_caps & MPGL_CAP_ARB_FLOAT) &&
             (gl->mpgl_caps & MPGL_CAP_TEX_RG) &&
             (gl->mpgl_caps & MPGL_CAP_FB)) ? F_GL2F : 0)
diff --git a/video/out/opengl/formats.h b/video/out/opengl/formats.h
index f727a3b6ef..93bd341e8c 100644
--- a/video/out/opengl/formats.h
+++ b/video/out/opengl/formats.h
@@ -16,14 +16,14 @@ enum {
 
     // Version flags. If at least 1 flag matches, the format entry is considered
     // supported on the current GL context.
-    F_GL2       = 1 << 0, // GL2.1-only
+    F_GL2       = 1 << 0, // GL 2.0-2.x (without extensions)
     F_GL3       = 1 << 1, // GL3.0 or later
     F_ES2       = 1 << 2, // ES2-only
     F_ES3       = 1 << 3, // ES3.0 or later
     F_ES32      = 1 << 4, // ES3.2 or later
     F_EXT16     = 1 << 5, // ES with GL_EXT_texture_norm16
     F_EXTF16    = 1 << 6, // GL_EXT_color_buffer_half_float
-    F_GL2F      = 1 << 7, // GL2.1-only with texture_rg + texture_float + FBOs
+    F_GL2F      = 1 << 7, // GL 2.0-2.x with texture_rg + texture_float + FBOs
     F_APPL      = 1 << 8, // GL_APPLE_rgb_422
 
     // Feature flags. They are additional and signal presence of features.
diff --git a/video/out/opengl/ra_gl.c b/video/out/opengl/ra_gl.c
index 8662bd4f5a..c61a04361e 100644
--- a/video/out/opengl/ra_gl.c
+++ b/video/out/opengl/ra_gl.c
@@ -80,8 +80,8 @@ static void probe_real_size(GL *gl, struct ra_format *fmt)
 
 static int ra_init_gl(struct ra *ra, GL *gl)
 {
-    if (gl->version < 210 && gl->es < 200) {
-        MP_ERR(ra, "At least OpenGL 2.1 or OpenGL ES 2.0 required.\n");
+    if (gl->version < 200 && gl->es < 200) {
+        MP_ERR(ra, "At least OpenGL 2.0 or OpenGL ES 2.0 required.\n");
         return -1;
     }
 
