[Mesa-dev] [PATCH 1/7] egl: Simplify queries for EGL_RENDER_BUFFER

Chad Versace chadversary at chromium.org
Tue Jul 31 05:00:37 UTC 2018


There exist *two* queryable EGL_RENDER_BUFFER states in EGL:
eglQuerySurface(EGL_RENDER_BUFFER) and
eglQueryContext(EGL_RENDER_BUFFER).

These changes eliminate potentially very fragile code in the upcoming
EGL_KHR_mutable_render_buffer implementation.

* eglQuerySurface(EGL_RENDER_BUFFER)

  The implementation of eglQuerySurface(EGL_RENDER_BUFFER) contained
  abstruse logic which required comprehending the specification
  complexities of how the two EGL_RENDER_BUFFER states interact.  The
  function sometimes returned _EGLContext::WindowRenderBuffer, sometimes
  _EGLSurface::RenderBuffer. Why? The function tried to encode the
  actual logic from the EGL spec. When did the function return which
  variable? Go study the EGL spec, hope you understand it, then hope
  Mesa mutated the EGL_RENDER_BUFFER state in all the correct places.
  Have fun.

  To simplify eglQuerySurface(EGL_RENDER_BUFFER), and to improve
  confidence in its correctness, flatten its indirect logic. For pixmap
  and pbuffer surfaces, simply return a hard-coded literal value, as the
  spec suggests. For window surfaces, simply return
  _EGLSurface::RequestedRenderBuffer.  Nothing difficult here.

* eglQueryContext(EGL_RENDER_BUFFER)

  The implementation of this suffered from the same issues as
  eglQuerySurface, and the solution is the same.  confidence in its
  correctness, flatten its indirect logic. For pixmap and pbuffer
  surfaces, simply return a hard-coded literal value, as the spec
  suggests. For window surfaces, simply return
  _EGLSurface::ActiveRenderBuffer.
---
 src/egl/drivers/dri2/egl_dri2.c |  6 -----
 src/egl/main/eglcontext.c       | 40 +++++++++++++++++++++++++++------
 src/egl/main/eglcontext.h       |  3 ---
 src/egl/main/eglsurface.c       | 28 ++++++++++++++++++++---
 src/egl/main/eglsurface.h       | 28 ++++++++++++++++++++++-
 5 files changed, 85 insertions(+), 20 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index c3024795a10..e109ad37f55 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -1289,12 +1289,6 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
          dri_config = dri2_config->dri_config[1][0];
       else
          dri_config = dri2_config->dri_config[0][0];
-
-      /* EGL_WINDOW_BIT is set only when there is a double-buffered dri_config.
-       * This makes sure the back buffer will always be used.
-       */
-      if (conf->SurfaceType & EGL_WINDOW_BIT)
-         dri2_ctx->base.WindowRenderBuffer = EGL_BACK_BUFFER;
    }
    else
       dri_config = NULL;
diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c
index 3e5d8ad97bf..ecc546e1132 100644
--- a/src/egl/main/eglcontext.c
+++ b/src/egl/main/eglcontext.c
@@ -588,7 +588,6 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
    _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
    ctx->ClientAPI = api;
    ctx->Config = conf;
-   ctx->WindowRenderBuffer = EGL_NONE;
    ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
 
    ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
@@ -620,15 +619,42 @@ static EGLint
 _eglQueryContextRenderBuffer(_EGLContext *ctx)
 {
    _EGLSurface *surf = ctx->DrawSurface;
-   EGLint rb;
 
+   /* From the EGL 1.5 spec:
+    *
+    *    - If the context is not bound to a surface, then EGL_NONE will be
+    *      returned.
+    */
    if (!surf)
       return EGL_NONE;
-   if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
-      rb = ctx->WindowRenderBuffer;
-   else
-      rb = surf->RenderBuffer;
-   return rb;
+
+   switch (surf->Type) {
+   default:
+      unreachable("bad EGLSurface type");
+   case EGL_PIXMAP_BIT:
+      /* - If the context is bound to a pixmap surface, then EGL_SINGLE_BUFFER
+       *   will be returned.
+       */
+      return EGL_SINGLE_BUFFER;
+   case EGL_PBUFFER_BIT:
+      /* - If the context is bound to a pbuffer surface, then EGL_BACK_BUFFER
+       *   will be returned.
+       */
+      return EGL_BACK_BUFFER;
+   case EGL_WINDOW_BIT:
+      /* - If the context is bound to a window surface, then either
+       *   EGL_BACK_BUFFER or EGL_SINGLE_BUFFER may be returned. The value
+       *   returned depends on both the buffer requested by the setting of the
+       *   EGL_RENDER_BUFFER property of the surface [...], and on the client
+       *   API (not all client APIs support single-buffer Rendering to window
+       *   surfaces). Some client APIs allow control of whether rendering goes
+       *   to the front or back buffer. This client API-specific choice is not
+       *   reflected in the returned value, which only describes the buffer
+       *   that will be rendered to by default if not overridden by the client
+       *   API.
+       */
+      return surf->ActiveRenderBuffer;
+   }
 }
 
 
diff --git a/src/egl/main/eglcontext.h b/src/egl/main/eglcontext.h
index 8d97ef9eab9..deddefdcaba 100644
--- a/src/egl/main/eglcontext.h
+++ b/src/egl/main/eglcontext.h
@@ -65,9 +65,6 @@ struct _egl_context
    EGLint ContextPriority;
    EGLBoolean NoError;
    EGLint ReleaseBehavior;
-
-   /* The real render buffer when a window surface is bound */
-   EGLint WindowRenderBuffer;
 };
 
 
diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c
index 3bd14a8cd03..73c31e11588 100644
--- a/src/egl/main/eglsurface.c
+++ b/src/egl/main/eglsurface.c
@@ -122,7 +122,7 @@ _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
-         surf->RenderBuffer = val;
+         surf->RequestedRenderBuffer = val;
          break;
       case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
          if (!dpy->Extensions.NV_post_sub_buffer ||
@@ -285,7 +285,8 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
    surf->TextureTarget = EGL_NO_TEXTURE;
    surf->MipmapTexture = EGL_FALSE;
    surf->LargestPbuffer = EGL_FALSE;
-   surf->RenderBuffer = renderBuffer;
+   surf->RequestedRenderBuffer = renderBuffer;
+   surf->ActiveRenderBuffer = renderBuffer;
    surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
    surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
    surf->GLColorspace = EGL_GL_COLORSPACE_LINEAR_KHR;
@@ -358,7 +359,28 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
       *value = surface->SwapBehavior;
       break;
    case EGL_RENDER_BUFFER:
-      *value = surface->RenderBuffer;
+      /* From the EGL 1.5 spec (2014.08.27):
+       *
+       *    Querying EGL_RENDER_BUFFER returns the buffer which client API
+       *    rendering is requested to use. For a window surface, this is the
+       *    same attribute value specified when the surface was created. For
+       *    a pbuffer surface, it is always EGL_BACK_BUFFER . For a pixmap
+       *    surface, it is always EGL_SINGLE_BUFFER . To determine the actual
+       *    buffer being rendered to by a context, call eglQueryContext.
+       */
+      switch (surface->Type) {
+      default:
+         unreachable("bad EGLSurface type");
+      case EGL_WINDOW_BIT:
+         *value = surface->RequestedRenderBuffer;
+         break;
+      case EGL_PBUFFER_BIT:
+         *value = EGL_BACK_BUFFER;
+         break;
+      case EGL_PIXMAP_BIT:
+         *value = EGL_SINGLE_BUFFER;
+         break;
+      }
       break;
    case EGL_PIXEL_ASPECT_RATIO:
       *value = surface->AspectRatio;
diff --git a/src/egl/main/eglsurface.h b/src/egl/main/eglsurface.h
index c53e8d00671..06e3b5b1b81 100644
--- a/src/egl/main/eglsurface.h
+++ b/src/egl/main/eglsurface.h
@@ -67,7 +67,33 @@ struct _egl_surface
    EGLenum TextureTarget;
    EGLBoolean MipmapTexture;
    EGLBoolean LargestPbuffer;
-   EGLenum RenderBuffer;
+
+   /**
+    * Value of EGL_RENDER_BUFFER selected at creation.
+    *
+    * The user may select, for window surfaces, the EGL_RENDER_BUFFER through
+    * the attribute list of eglCreateWindowSurface(). The EGL spec allows the
+    * implementation to ignore request, though; hence why we maintain both
+    * RequestedRenderBuffer and ActiveRenderBuffer. For pbuffer and pixmap
+    * surfaces, the EGL spec hard-codes the EGL_RENDER_BUFFER value and the
+    * user must not provide it in the attribute list.
+    *
+    * Refer to eglQuerySurface() in the EGL spec.
+    * eglQueryContext(EGL_RENDER_BUFFER) ignores this.
+    */
+   EGLenum RequestedRenderBuffer;
+
+   /**
+    * The EGL_RENDER_BUFFER in use by the context.
+    *
+    * This is valid only when bound as the draw surface.  This may differ from
+    * the RequestedRenderBuffer.
+    *
+    * Refer to eglQueryContext(EGL_RENDER_BUFFER) in the EGL spec.
+    * eglQuerySurface(EGL_RENDER_BUFFER) ignores this.
+    */
+   EGLenum ActiveRenderBuffer;
+
    EGLenum VGAlphaFormat;
    EGLenum VGColorspace;
    EGLenum GLColorspace;
-- 
2.18.0.345.g5c9ce644c3-goog



More information about the mesa-dev mailing list