[2/3] mesa: fix pbuffers because internally they are front buffers

Submitted by Marek Olšák on April 27, 2019, 3:31 a.m.

Details

Message ID 20190427033147.12859-3-maraeo@gmail.com
State New
Headers show
Series "Pbuffer fixes" ( rev: 2 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Marek Olšák April 27, 2019, 3:31 a.m.
From: Marek Olšák <marek.olsak@amd.com>

This fixes the egl_ext_device_base piglit test, which uses EGL pbuffers.
---
 src/mesa/main/buffers.c | 56 ++++++++++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 20 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/mesa/main/buffers.c b/src/mesa/main/buffers.c
index 2148fa1316c..1ac0d5d0798 100644
--- a/src/mesa/main/buffers.c
+++ b/src/mesa/main/buffers.c
@@ -86,46 +86,62 @@  supported_buffer_bitmask(const struct gl_context *ctx,
 
 
 /**
  * Helper routine used by glDrawBuffer and glDrawBuffersARB.
  * Given a GLenum naming one or more color buffers (such as
  * GL_FRONT_AND_BACK), return the corresponding bitmask of BUFFER_BIT_* flags.
  */
 static GLbitfield
 draw_buffer_enum_to_bitmask(const struct gl_context *ctx, GLenum buffer)
 {
+   /* If the front buffer is the only buffer, GL_BACK and all other flags
+    * that include BACK select the front buffer for drawing. There are
+    * several reasons we want to do this.
+    *
+    * 1) OpenGL ES 3.0 requires it:
+    *
+    *   Page 181 (page 192 of the PDF) in section 4.2.1 of the OpenGL
+    *   ES 3.0.1 specification says:
+    *
+    *     "When draw buffer zero is BACK, color values are written
+    *     into the sole buffer for single-buffered contexts, or into
+    *     the back buffer for double-buffered contexts."
+    *
+    *   We also do this for GLES 1 and 2 because those APIs have no
+    *   concept of selecting the front and back buffer anyway and it's
+    *   convenient to be able to maintain the magic behaviour of
+    *   GL_BACK in that case.
+    *
+    * 2) Pbuffers are back buffers from the application point of view,
+    *    but they are front buffers from the Mesa point of view,
+    *    because they are always single buffered.
+    */
+   if (!ctx->DrawBuffer->Visual.doubleBufferMode) {
+      switch (buffer) {
+      case GL_BACK:
+         buffer = GL_FRONT;
+         break;
+      case GL_BACK_RIGHT:
+         buffer = GL_FRONT_RIGHT;
+         break;
+      case GL_BACK_LEFT:
+         buffer = GL_FRONT_LEFT;
+         break;
+      }
+   }
+
    switch (buffer) {
       case GL_NONE:
          return 0;
       case GL_FRONT:
          return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_FRONT_RIGHT;
       case GL_BACK:
-         if (_mesa_is_gles(ctx)) {
-            /* Page 181 (page 192 of the PDF) in section 4.2.1 of the OpenGL
-             * ES 3.0.1 specification says:
-             *
-             *     "When draw buffer zero is BACK, color values are written
-             *     into the sole buffer for single-buffered contexts, or into
-             *     the back buffer for double-buffered contexts."
-             *
-             * Since there is no stereo rendering in ES 3.0, only return the
-             * LEFT bits.  This also satisfies the "n must be 1" requirement.
-             *
-             * We also do this for GLES 1 and 2 because those APIs have no
-             * concept of selecting the front and back buffer anyway and it's
-             * convenient to be able to maintain the magic behaviour of
-             * GL_BACK in that case.
-             */
-            if (ctx->DrawBuffer->Visual.doubleBufferMode)
-               return BUFFER_BIT_BACK_LEFT;
-            return BUFFER_BIT_FRONT_LEFT;
-         }
          return BUFFER_BIT_BACK_LEFT | BUFFER_BIT_BACK_RIGHT;
       case GL_RIGHT:
          return BUFFER_BIT_FRONT_RIGHT | BUFFER_BIT_BACK_RIGHT;
       case GL_FRONT_RIGHT:
          return BUFFER_BIT_FRONT_RIGHT;
       case GL_BACK_RIGHT:
          return BUFFER_BIT_BACK_RIGHT;
       case GL_BACK_LEFT:
          return BUFFER_BIT_BACK_LEFT;
       case GL_FRONT_AND_BACK:

Comments

On Fri, 2019-04-26 at 23:31 -0400, Marek Olšák wrote:

I don't claim to know what this series is trying to fix, but:

> +    * 2) Pbuffers are back buffers from the application point of view,
> +    *    but they are front buffers from the Mesa point of view,
> +    *    because they are always single buffered.
> +    */

The EGL spec (back to 1.0!) says:

"The resulting pbuffer will contain color buffers and ancillary buffers
as specified by config."

This appears to be copied from GLX, which has something more elaborate:

"The resulting pbuffer will contain color buffers and ancillary buffers
as specified by config. It is possible to create a pbuffer with back
buffers and to swap the front and back buffers by calling
glXSwapBuffers. Note that pbuffers use framebuffer resources so
applications should consider deallocating them when they are not in
use."

So I'm not convinced that pbuffers are "always single-buffered". The
back buffer is definitely a color buffer, and at least under GLX it
seems like it should be possible to draw red to back, swap, draw blue
to back, glReadBuffer(GL_FRONT), and expect glReadPixels to return red.

- ajax

Adam, Marek,

On Monday, 29 April 2019 18:28:21 CEST Adam Jackson wrote:
> On Fri, 2019-04-26 at 23:31 -0400, Marek Olšák wrote:
> 
> I don't claim to know what this series is trying to fix, but:
> 
> > +    * 2) Pbuffers are back buffers from the application point of view,
> > +    *    but they are front buffers from the Mesa point of view,
> > +    *    because they are always single buffered.
> > +    */
> 
> The EGL spec (back to 1.0!) says:
> 
> "The resulting pbuffer will contain color buffers and ancillary buffers
> as specified by config."
> 
> This appears to be copied from GLX, which has something more elaborate:
> 
> "The resulting pbuffer will contain color buffers and ancillary buffers
> as specified by config. It is possible to create a pbuffer with back
> buffers and to swap the front and back buffers by calling
> glXSwapBuffers. Note that pbuffers use framebuffer resources so
> applications should consider deallocating them when they are not in
> use."
> 
> So I'm not convinced that pbuffers are "always single-buffered". The
> back buffer is definitely a color buffer, and at least under GLX it
> seems like it should be possible to draw red to back, swap, draw blue
> to back, glReadBuffer(GL_FRONT), and expect glReadPixels to return red.

Hmm, probably Marek's escape could be 2.2.2 Rendering Models form the eglspec:
[...]
Pbuffer surfaces have a back buffer but no associated
window, so the back buffer need not be copied.
[...]

Not sure myself what that means in its total consequence, but can't we read that as
there is only undefined behavior associated with the pbuffer front buffer?

Why, do I get to that?
IIRC somewhere in EGL there is a note that there is basically no front buffer rendering
in EGL. And the above tells that the implementation may behave as if there is no way
to swap the back buffers content into the front buffer.

Is there some path left using egl images or egl copy buffers?
Or what else do I miss?

best

Mathias

On Mon, 2019-04-29 at 20:35 -0400, Marek Olšák wrote:

> Yeah that's possible. The thing is that a GL context can have a
> doublebuffered config and begin with GL_BACK as the draw buffer, but
> MakeCurrent can set a pbuffer with a singlebuffered config and then
> nothing is rendered with Mesa because there is no back buffer. This
> case appears to work on NVIDIA.

Okay, that makes sense. Thanks for the explanation.

I think this is only true because of EGL_KHR_no_config_context? If the
context has a config, then you shouldn't be able to make a single-
buffered pbuffer current to a double-buffered context. EGL section
2.2's definition of compatibility includes having "color and ancillary
buffers of the same depth"; if you don't have a back buffer, then you
have zero bits of back buffer, and you would not be compatible with
non-zero bits of back buffer. I would think, anyway.

Now if you bind a single-buffered pbuffer to a no-config context,
obviously rendering should go to GL_FRONT.

- ajax