[Mesa-dev] [PATCH 7.1/7] mesa: Add error checking in _mesa_BlitFramebuffer() for MRTs

Anuj Phogat anuj.phogat at gmail.com
Wed Jan 9 00:06:46 PST 2013


On Wed, Jan 9, 2013 at 1:30 AM, Kenneth Graunke <kenneth at whitecape.org> wrote:
> On 01/08/2013 03:54 AM, Anuj Phogat wrote:
>>
>> This patch adds required error checking in _mesa_BlitFramebuffer() when
>> blitting to multiple color render targets. It also fixes a case when
>> blitting to a framebuffer with renderbuffer/texture attached to
>> GL_COLOR_ATTACHMENT{i} (where i!=0). Earlier it skips color blitting if
>> nothing is found attached to GL_COLOR_ATTACHMENT0.
>>
>> V2: Fixed a case when number of draw buffer attachments are zero.
>> V3: Do compatible_color_datatypes() and compatible_resolve_formats()
>>      check for all the  draw renderbuffers in fbobject.c. Fix debug
>>      code at bottom of _mesa_BlitFramebuffer() to handle MRTs. Combine
>>      error checking code for linear blits with other color blit error
>>      checking.
>>
>> Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
>> ---
>>   src/mesa/main/fbobject.c |  115
>> +++++++++++++++++++++++++++-------------------
>>   1 files changed, 68 insertions(+), 47 deletions(-)
>>
>> diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c
>> index 517bf13..fe9043c 100644
>> --- a/src/mesa/main/fbobject.c
>> +++ b/src/mesa/main/fbobject.c
>> @@ -2788,7 +2788,6 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0,
>> GLint srcX1, GLint srcY1,
>>                                        GL_DEPTH_BUFFER_BIT |
>>                                        GL_STENCIL_BUFFER_BIT);
>>      const struct gl_framebuffer *readFb, *drawFb;
>> -   const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
>>      GET_CURRENT_CONTEXT(ctx);
>>
>>      ASSERT_OUTSIDE_BEGIN_END(ctx);
>> @@ -2843,8 +2842,10 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0,
>> GLint srcX1, GLint srcY1,
>>
>>      /* get color read/draw renderbuffers */
>>      if (mask & GL_COLOR_BUFFER_BIT) {
>> -      colorReadRb = readFb->_ColorReadBuffer;
>> -      colorDrawRb = drawFb->_ColorDrawBuffers[0];
>> +      const GLuint numColorDrawBuffers =
>> ctx->DrawBuffer->_NumColorDrawBuffers;
>> +      const struct gl_renderbuffer *colorReadRb =
>> readFb->_ColorReadBuffer;
>> +      const struct gl_renderbuffer *colorDrawRb = NULL;
>> +      GLuint i;
>>
>>         /* From the EXT_framebuffer_object spec:
>>          *
>> @@ -2852,19 +2853,50 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0,
>> GLint srcX1, GLint srcY1,
>>          *     the read and draw framebuffers, the corresponding bit is
>> silently
>>          *     ignored."
>>          */
>> -      if ((colorReadRb == NULL) || (colorDrawRb == NULL)) {
>> -        colorReadRb = colorDrawRb = NULL;
>> -        mask &= ~GL_COLOR_BUFFER_BIT;
>> +      if (!colorReadRb || numColorDrawBuffers == 0) {
>> +         mask &= ~GL_COLOR_BUFFER_BIT;
>>         }
>> -      else if (!compatible_color_datatypes(colorReadRb->Format,
>> -                                           colorDrawRb->Format)) {
>> -         _mesa_error(ctx, GL_INVALID_OPERATION,
>> -                     "glBlitFramebufferEXT(color buffer datatypes
>> mismatch)");
>> -         return;
>> +      else {
>> +         for (i = 0; i < numColorDrawBuffers; i++) {
>> +            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
>> +            if (!colorDrawRb)
>> +               continue;
>> +
>> +            if (!compatible_color_datatypes(colorReadRb->Format,
>> +                                            colorDrawRb->Format)) {
>> +               _mesa_error(ctx, GL_INVALID_OPERATION,
>> +                           "glBlitFramebufferEXT(color buffer datatypes
>> mismatch)");
>> +               return;
>> +            }
>> +            /* extra checks for multisample copies... */
>> +            if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0)
>> {
>> +               /* color formats must match */
>> +               if (!compatible_resolve_formats(colorReadRb, colorDrawRb))
>> {
>> +                  _mesa_error(ctx, GL_INVALID_OPERATION,
>> +                         "glBlitFramebufferEXT(bad src/dst multisample
>> pixel formats)");
>> +                  return;
>> +               }
>> +            }
>> +         }
>> +      }
>> +
>> +      if (colorDrawRb == NULL) {
>> +         colorReadRb = NULL;
>> +         mask &= ~GL_COLOR_BUFFER_BIT;
>> +      }
>
>
> I don't think this if-statement should exist.  There are two ways to get
> here.  First is via:
>
>       if (!colorReadRb || numColorDrawBuffers == 0) {
>          mask &= ~GL_COLOR_BUFFER_BIT;
>       } else {
> handles the case of no draw buffers.  mask already gets updated.  In the
> "else" case, we hit the loop.  Substituting the post-loop value for
> colorDrawRb, this block becomes equivalent to:
>
> if (ctx->DrawBuffer->_ColorDrawBuffers[numColorDrawBuffers-1] == NULL) {
>    colorReadRb = NULL;
>    mask &= ~GL_COLOR_BUFFER_BIT;
> }
>
> and that looks really sketchy - why is the last element special?
>
This doesn't always test for last element. It tests for last non-null element.
It was used to verify that we have atleast one valid draw renderbuffer. But
you are right it is already tested by numColorDrawBuffers == 0. I'll omit this
if statement before pushing upstream.

>> +      if (filter == GL_LINEAR && (mask & GL_COLOR_BUFFER_BIT)) {
>> +         /* 3.1 spec, page 199:
>> +          * "Calling BlitFramebuffer will result in an INVALID_OPERATION
>> error
>> +          * if filter is LINEAR and read buffer contains integer data."
>> +          */
>> +         GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
>> +         if (type == GL_INT || type == GL_UNSIGNED_INT) {
>> +            _mesa_error(ctx, GL_INVALID_OPERATION,
>> +                        "glBlitFramebufferEXT(integer color type)");
>> +            return;
>> +         }
>>         }
>
>
> I would like to see this block moved into the } else { block above. That
> way, you already know that colorReadRb exists and (mask &
> GL_COLOR_BUFFER_BIT) is true, so you can simply change this to:
>
> if (filter == GL_LINEAR) {
>    ...
> }
>
yes. I'll do that.
> With those two changes, this gets a:
> Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
>
>
>> -   }
>> -   else {
>> -      colorReadRb = colorDrawRb = NULL;
>>      }
>>
>>      if (mask & GL_STENCIL_BUFFER_BIT) {
>> @@ -2952,28 +2984,6 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0,
>> GLint srcX1, GLint srcY1,
>>                   "glBlitFramebufferEXT(bad src/dst multisample region
>> sizes)");
>>            return;
>>         }
>> -
>> -      /* color formats must match */
>> -      if (colorReadRb &&
>> -          colorDrawRb &&
>> -          !compatible_resolve_formats(colorReadRb, colorDrawRb)) {
>> -         _mesa_error(ctx, GL_INVALID_OPERATION,
>> -                "glBlitFramebufferEXT(bad src/dst multisample pixel
>> formats)");
>> -         return;
>> -      }
>> -   }
>> -
>> -   if (filter == GL_LINEAR && (mask & GL_COLOR_BUFFER_BIT)) {
>> -      /* 3.1 spec, page 199:
>> -       * "Calling BlitFramebuffer will result in an INVALID_OPERATION
>> error
>> -       * if filter is LINEAR and read buffer contains integer data."
>> -       */
>> -      GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
>> -      if (type == GL_INT || type == GL_UNSIGNED_INT) {
>> -         _mesa_error(ctx, GL_INVALID_OPERATION,
>> -                     "glBlitFramebufferEXT(integer color type)");
>> -         return;
>> -      }
>>      }
>>
>>      if (!ctx->Extensions.EXT_framebuffer_blit) {
>> @@ -2983,6 +2993,10 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0,
>> GLint srcX1, GLint srcY1,
>>
>>      /* Debug code */
>>      if (DEBUG_BLIT) {
>> +      const struct gl_renderbuffer *colorReadRb =
>> readFb->_ColorReadBuffer;
>> +      const struct gl_renderbuffer *colorDrawRb = NULL;
>> +      GLuint i = 0;
>> +
>>         printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
>>              " 0x%x, 0x%x)\n",
>>              srcX0, srcY0, srcX1, srcY1,
>> @@ -3004,18 +3018,25 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0,
>> GLint srcX1, GLint srcY1,
>>            }
>>            printf("\n");
>>
>> -         att = find_attachment(drawFb, colorDrawRb);
>> -         printf("  Dst FBO %u  RB %u (%dx%d)  ",
>> -               drawFb->Name, colorDrawRb->Name,
>> -               colorDrawRb->Width, colorDrawRb->Height);
>> -         if (att && att->Texture) {
>> -            printf("Tex %u  tgt 0x%x  level %u  face %u",
>> -                  att->Texture->Name,
>> -                  att->Texture->Target,
>> -                  att->TextureLevel,
>> -                  att->CubeMapFace);
>> +         /* Print all active color render buffers */
>> +         for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
>> +            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
>> +            if (!colorDrawRb)
>> +               continue;
>> +
>> +            att = find_attachment(drawFb, colorDrawRb);
>> +            printf("  Dst FBO %u  RB %u (%dx%d)  ",
>> +                  drawFb->Name, colorDrawRb->Name,
>> +                  colorDrawRb->Width, colorDrawRb->Height);
>> +            if (att && att->Texture) {
>> +               printf("Tex %u  tgt 0x%x  level %u  face %u",
>> +                     att->Texture->Name,
>> +                     att->Texture->Target,
>> +                     att->TextureLevel,
>> +                     att->CubeMapFace);
>> +            }
>> +            printf("\n");
>>            }
>> -         printf("\n");
>>         }
>>      }
>>
>>
>


More information about the mesa-dev mailing list