mesa: Rework discard_framebuffer()
authorRob Clark <robdclark@chromium.org>
Wed, 15 Mar 2023 14:54:23 +0000 (07:54 -0700)
committerMarge Bot <emma+marge@anholt.net>
Thu, 16 Mar 2023 00:56:37 +0000 (00:56 +0000)
Decouple the logic turning API attachment enums into gl_buffer_index.
This will make it easier to re-use discard_attachments() internally (See
!21910)

Signed-off-by: Rob Clark <robdclark@chromium.org>
Mike Blumenkrantz <michael.blumenkrantz@gmail.com>

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21916>

src/mesa/main/fbobject.c

index e02ab09..4b6fc23 100644 (file)
@@ -5291,13 +5291,13 @@ invalid_enum:
    return;
 }
 
-static struct gl_renderbuffer_attachment *
-get_fb_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
-                  const GLenum attachment)
+static gl_buffer_index
+get_fb_attachment_index(struct gl_context *ctx, struct gl_framebuffer *fb,
+                        const GLenum attachment)
 {
    switch (attachment) {
    case GL_COLOR:
-      return &fb->Attachment[BUFFER_BACK_LEFT];
+      return BUFFER_BACK_LEFT;
    case GL_COLOR_ATTACHMENT0:
    case GL_COLOR_ATTACHMENT1:
    case GL_COLOR_ATTACHMENT2:
@@ -5316,19 +5316,19 @@ get_fb_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
    case GL_COLOR_ATTACHMENT15: {
       const unsigned i = attachment - GL_COLOR_ATTACHMENT0;
       if (i >= ctx->Const.MaxColorAttachments)
-         return NULL;
+         return BUFFER_NONE;
       assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment));
-      return &fb->Attachment[BUFFER_COLOR0 + i];
+      return BUFFER_COLOR0 + i;
    }
    case GL_DEPTH:
    case GL_DEPTH_ATTACHMENT:
    case GL_DEPTH_STENCIL_ATTACHMENT:
-      return &fb->Attachment[BUFFER_DEPTH];
+      return BUFFER_DEPTH;
    case GL_STENCIL:
    case GL_STENCIL_ATTACHMENT:
-      return &fb->Attachment[BUFFER_STENCIL];
+      return BUFFER_STENCIL;
    default:
-      return NULL;
+      return BUFFER_NONE;
    }
 }
 
@@ -5352,52 +5352,63 @@ do_discard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
 }
 
 static void
-discard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
-                    GLsizei numAttachments, const GLenum *attachments)
+discard_attachments(struct gl_context *ctx, struct gl_framebuffer *fb,
+                    uint32_t mask)
 {
-   GLenum depth_att, stencil_att;
+   const uint32_t zsmask = BITFIELD_BIT(BUFFER_DEPTH) | BITFIELD_BIT(BUFFER_STENCIL);
 
-   if (_mesa_is_user_fbo(fb)) {
-      depth_att = GL_DEPTH_ATTACHMENT;
-      stencil_att = GL_STENCIL_ATTACHMENT;
-   } else {
-      depth_att = GL_DEPTH;
-      stencil_att = GL_STENCIL;
+   /* If we're asked to invalidate just depth or just stencil, but the
+    * attachment is packed depth/stencil, then we can only use
+    * DiscardFramebuffer if the attachments list includes both depth
+    * and stencil and they both point at the same renderbuffer.
+    *
+    * Note EXT_discard_framebuffer says that discarding only one component
+    * of a packed z/s implicitly discards both.  But glInvalidateFramebuffer
+    * does not appear to specify the behavior.  So this may be overly
+    * conservative.
+    */
+   if ((mask & zsmask) && ((mask & zsmask) != zsmask) &&
+       (fb->Attachment[BUFFER_DEPTH].Renderbuffer ==
+             fb->Attachment[BUFFER_STENCIL].Renderbuffer)) {
+      mask &= ~zsmask;
    }
 
-   for (int i = 0; i < numAttachments; i++) {
-      struct gl_renderbuffer_attachment *att =
-            get_fb_attachment(ctx, fb, attachments[i]);
+   u_foreach_bit (b, mask) {
+      struct gl_renderbuffer_attachment *att = &fb->Attachment[b];
 
-      if (!att)
-         continue;
+      do_discard_framebuffer(ctx, fb, att);
+   }
+}
 
-      /* If we're asked to invalidate just depth or just stencil, but the
-       * attachment is packed depth/stencil, then we can only use
-       * DiscardFramebuffer if the attachments list includes both depth
-       * and stencil and they both point at the same renderbuffer.
-       */
-      if ((attachments[i] == depth_att ||
-           attachments[i] == stencil_att) &&
-          (!att->Renderbuffer ||
-           att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL)) {
-         GLenum other_format = (attachments[i] == depth_att ?
-                                stencil_att : depth_att);
-         bool has_both = false;
-         for (int j = 0; j < numAttachments; j++) {
-            if (attachments[j] == other_format) {
-               has_both = true;
-               break;
-            }
+static void
+discard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
+                    GLsizei numAttachments, const GLenum *attachments)
+{
+   uint32_t mask = 0;
+
+   for (int i = 0; i < numAttachments; i++) {
+      GLenum att = attachments[i];
+
+      /* A couple enums need special handling, because gl.. */
+      if (!_mesa_is_user_fbo(fb)) {
+         if (att == GL_DEPTH) {
+            att = GL_DEPTH_ATTACHMENT;
+         } else if (att == GL_STENCIL) {
+            att = GL_STENCIL_ATTACHMENT;
          }
+      }
 
-         if (fb->Attachment[BUFFER_DEPTH].Renderbuffer !=
-             fb->Attachment[BUFFER_STENCIL].Renderbuffer || !has_both)
-            continue;
+      if (att == GL_DEPTH_STENCIL_ATTACHMENT) {
+         mask |= BITFIELD_BIT(BUFFER_DEPTH) | BITFIELD_BIT(BUFFER_STENCIL);
+         continue;
       }
 
-      do_discard_framebuffer(ctx, fb, att);
+      gl_buffer_index idx = get_fb_attachment_index(ctx, fb, att);
+      if (idx != BUFFER_NONE)
+         mask |= BITFIELD_BIT(idx);
    }
+
+   discard_attachments(ctx, fb, mask);
 }
 
 void GLAPIENTRY