From 1ae221afb2c03d2b3cd0a607dc6646f33c07341c Mon Sep 17 00:00:00 2001
From: Brendan King <Brendan.King@imgtec.com>
Date: Mon, 10 Feb 2020 09:23:03 +0000
Subject: [PATCH] egl: query the supported ES2 context version

For OpenGL ES contexts, the EGL specification states that querying
EGL_CONTEXT_CLIENT_VERSION with eglQueryContext may return a version
that differs from that specified at context creation time. For example,
if an OpenGL ES2 context is specified at context creation time, an
OpenGL ES3 context may be created, and so "3" should be returned
when EGL_CONTEXT_CLIENT_VERSION is queried.

A new EGL driver API function has been added,
QueryContextClientVersion, that is called when the context client
version is queried, allowing EGL drivers to override the default
value (i.e. the version specified at context creation time). If the
function returns zero, the default is used.

For DRI drivers, QueryContextClientVersion returns zero for all API
contexts other than OpenGL ES2. For OpenGL ES2, the supported context
client version is queried via the Query Renderer driver extension, using
integer query __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG. If
the query isn't supported, or the query returns zero, zero is returned
to the caller.

IMG NOTE: In order to avoid potential name and value clashes, "_IMG"
has been added to the end of the new query name, this should be removed
if an attempt is made to push this patch upstream. The value of the new
query should be adjusted to be the next one in sequence, rather than the
large value it currently has.

---
 include/GL/internal/dri_interface.h |  2 ++
 src/egl/drivers/dri2/egl_dri2.c     | 21 +++++++++++++++++++++
 src/egl/drivers/haiku/egl_haiku.cpp |  9 +++++++++
 src/egl/main/eglapi.c               |  2 +-
 src/egl/main/eglcontext.c           | 16 ++++++++++++++--
 src/egl/main/eglcontext.h           |  3 ++-
 src/egl/main/egldriver.h            |  1 +
 7 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
index 6490f6e..9c7bcac 100644
--- a/include/GL/internal/dri_interface.h
+++ b/include/GL/internal/dri_interface.h
@@ -2052,6 +2052,8 @@ typedef struct __DRIDriverVtableExtensionRec {
 
 #define __DRI2_RENDERER_HAS_PROTECTED_CONTENT                 0x000e
 
+#define __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG 0x7001
+
 typedef struct __DRI2rendererQueryExtensionRec __DRI2rendererQueryExtension;
 struct __DRI2rendererQueryExtensionRec {
    __DRIextension base;
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 6b26ff9..c4a49ca 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -2055,6 +2055,26 @@ dri2_make_current(_EGLDisplay *disp, _EGLSurface *dsurf,
    return EGL_TRUE;
 }
 
+static EGLint
+dri2_query_context_client_version(_EGLDisplay *disp, _EGLContext *ctx)
+{
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+   switch (dri2_ctx->base.ClientAPI) {
+   case EGL_OPENGL_ES_API:
+      switch (dri2_ctx->base.ClientMajorVersion) {
+      case 2:
+         return dri2_renderer_query_integer(dri2_dpy,
+                   __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG);
+      default:
+         return 0;
+      }
+   default:
+      return 0;
+   }
+}
+
 __DRIdrawable *
 dri2_surface_get_dri_drawable(_EGLSurface *surf)
 {
@@ -4336,6 +4356,7 @@ const _EGLDriver _eglDriver = {
    .CreateContext = dri2_create_context,
    .DestroyContext = dri2_destroy_context,
    .MakeCurrent = dri2_make_current,
+   .QueryContextClientVersion = dri2_query_context_client_version,
    .CreateWindowSurface = dri2_create_window_surface,
    .CreatePixmapSurface = dri2_create_pixmap_surface,
    .CreatePbufferSurface = dri2_create_pbuffer_surface,
diff --git a/src/egl/drivers/haiku/egl_haiku.cpp b/src/egl/drivers/haiku/egl_haiku.cpp
index 18c73c9..2690a82 100644
--- a/src/egl/drivers/haiku/egl_haiku.cpp
+++ b/src/egl/drivers/haiku/egl_haiku.cpp
@@ -297,6 +297,14 @@ haiku_make_current(_EGLDisplay *disp, _EGLSurface *dsurf,
 }
 
 
+extern "C"
+EGLint
+haiku_dri2_query_context_client_version(_EGLDisplay *disp, _EGLContext *ctx)
+{
+	// Tell caller to use the default value.
+	return 0;
+}
+
 extern "C"
 EGLBoolean
 haiku_swap_buffers(_EGLDisplay *disp, _EGLSurface *surf)
@@ -316,6 +324,7 @@ const _EGLDriver _eglDriver = {
 	.CreateContext = haiku_create_context,
 	.DestroyContext = haiku_destroy_context,
 	.MakeCurrent = haiku_make_current,
+	.QueryContextClientVersion = haiku_dri2_query_context_client_version,
 	.CreateWindowSurface = haiku_create_window_surface,
 	.CreatePixmapSurface = haiku_create_pixmap_surface,
 	.CreatePbufferSurface = haiku_create_pbuffer_surface,
diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 2d3931d..1cbff96 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -948,7 +948,7 @@ eglQueryContext(EGLDisplay dpy, EGLContext ctx,
 
    _EGL_CHECK_CONTEXT(disp, context, EGL_FALSE);
 
-   ret = _eglQueryContext(context, attribute, value);
+   ret = _eglQueryContext(disp, context, attribute, value);
 
    RETURN_EGL_EVAL(disp, ret);
 }
diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c
index 15de7c9..7274d24 100644
--- a/src/egl/main/eglcontext.c
+++ b/src/egl/main/eglcontext.c
@@ -35,6 +35,7 @@
 #include "eglcontext.h"
 #include "egldisplay.h"
 #include "eglcurrent.h"
+#include "egldriver.h"
 #include "eglsurface.h"
 #include "egllog.h"
 #include "util/macros.h"
@@ -670,8 +671,19 @@ _eglQueryContextRenderBuffer(_EGLContext *ctx)
 }
 
 
+static EGLint
+_eglQueryContextClientVersion(_EGLDisplay *disp, _EGLContext *ctx)
+{
+   EGLint version;
+
+   version = disp->Driver->QueryContextClientVersion(disp, ctx);
+
+   return (version) ? version : ctx->ClientMajorVersion;
+}
+
 EGLBoolean
-_eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value)
+_eglQueryContext(_EGLDisplay *disp, _EGLContext *c,
+                 EGLint attribute, EGLint *value)
 {
    if (!value)
       return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
@@ -688,7 +700,7 @@ _eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value)
       *value = c->Config ? c->Config->ConfigID : 0;
       break;
    case EGL_CONTEXT_CLIENT_VERSION:
-      *value = c->ClientMajorVersion;
+      *value = _eglQueryContextClientVersion(disp, c);
       break;
    case EGL_CONTEXT_CLIENT_TYPE:
       *value = c->ClientAPI;
diff --git a/src/egl/main/eglcontext.h b/src/egl/main/eglcontext.h
index 06029e8..d890217 100644
--- a/src/egl/main/eglcontext.h
+++ b/src/egl/main/eglcontext.h
@@ -74,7 +74,8 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *disp,
 
 
 extern EGLBoolean
-_eglQueryContext(_EGLContext *ctx, EGLint attribute, EGLint *value);
+_eglQueryContext(_EGLDisplay *disp, _EGLContext *ctx,
+                 EGLint attribute, EGLint *value);
 
 
 extern EGLBoolean
diff --git a/src/egl/main/egldriver.h b/src/egl/main/egldriver.h
index 12f9a0a..92af8bd 100644
--- a/src/egl/main/egldriver.h
+++ b/src/egl/main/egldriver.h
@@ -97,6 +97,7 @@ struct _egl_driver
    EGLBoolean (*MakeCurrent)(_EGLDisplay *disp,
                              _EGLSurface *draw, _EGLSurface *read,
                              _EGLContext *ctx);
+   EGLint (*QueryContextClientVersion)(_EGLDisplay *disp, _EGLContext *ctx);
 
    /* surface funcs */
    _EGLSurface *(*CreateWindowSurface)(_EGLDisplay *disp, _EGLConfig *config,
