[Mesa-dev] [PATCH 7/7] mesa: Add support to allow blitting to multiple color draw buffers

Kenneth Graunke kenneth at whitecape.org
Mon Jan 7 15:52:31 PST 2013


On 01/07/2013 08:16 AM, Anuj Phogat wrote:
> Changes in fbobject.c fix a case when blitting to a framebuffer with
> renderbuffers/textures attached to GL_COLOR_ATTACHMENT{i} (where i!=0).
> Earlier it skips color blitting if nothing is found attached to
> GL_COLOR_ATTACHMENT0.

Could you please split this into two patches?

> Changes in swrast/s_blit.c fix a blitting case when drawAttachment->Texture
>   == readAttachment->Texture. This was causing an assertion failure
> intel_miptree_attach_map() with gles3 conformance test case:
> framebuffer_blit_functionality_minifying_blit
> Number of changes in this file look scary. But most of them are caused by
> introducing a big for loop to support rendering to multiple color draw buffers.
>
> V2: Fixed a case when number of draw buffer attachments are zero.
> V3: Do compatible_color_datatypes() check for all the  draw renderbuffers
>      in fbobject.c. Put a for loop in blit_nearest() and blit_linear()
>      functions in swrast/s_blit.c to support blitting to multiple color
>      draw buffers.
> V4: Remove variable declaration in for loop to avoid MSVC compilation issues.
>
> Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
> ---
>   src/mesa/main/fbobject.c |   32 ++-
>   src/mesa/swrast/s_blit.c |  561 +++++++++++++++++++++++++---------------------
>   2 files changed, 324 insertions(+), 269 deletions(-)
>
> diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c
> index 517bf13..e9fd9ca 100644
> --- a/src/mesa/main/fbobject.c
> +++ b/src/mesa/main/fbobject.c
> @@ -2789,6 +2789,8 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
>                                        GL_STENCIL_BUFFER_BIT);
>      const struct gl_framebuffer *readFb, *drawFb;
>      const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
> +   GLuint i;
> +
>      GET_CURRENT_CONTEXT(ctx);
>
>      ASSERT_OUTSIDE_BEGIN_END(ctx);
> @@ -2843,8 +2845,10 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
>
>      /* get color read/draw renderbuffers */
>      if (mask & GL_COLOR_BUFFER_BIT) {
> +      const  GLuint numColorDrawBuffers =
> +         ctx->DrawBuffer->_NumColorDrawBuffers;
>         colorReadRb = readFb->_ColorReadBuffer;
> -      colorDrawRb = drawFb->_ColorDrawBuffers[0];
> +      colorDrawRb = NULL;
>
>         /* From the EXT_framebuffer_object spec:
>          *
> @@ -2852,15 +2856,27 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
>          *     the read and draw framebuffers, the corresponding bit is silently
>          *     ignored."
>          */

How about:

       if (!colorReadRb || numColorDrawBuffers == 0) {
          mask &= ~GL_COLOR_BUFFER_BIT;
       } else {
          ...your loop and error checking...
       }

Then, colorReadRb/colorDrawRb don't need to be at global scope, and you 
can...

> -      if ((colorReadRb == NULL) || (colorDrawRb == NULL)) {
> -	 colorReadRb = colorDrawRb = NULL;
> +      if (colorReadRb == NULL) {
>   	 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++) {

...just declare them at the start of this loop (which should be valid 
even in C89):

             const struct gl_renderbuffer *colorDrawRb =
                ctx->DrawBuffer->_ColorDrawBuffers[i];
             if (!colorDrawRb)
                continue;

> +            if (ctx->DrawBuffer->_ColorDrawBuffers[i] == NULL)
> +	       continue;
> +	    colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
> +
> +            if (!compatible_color_datatypes(colorReadRb->Format,
> +                                            colorDrawRb->Format)) {
> +               _mesa_error(ctx, GL_INVALID_OPERATION,
> +                           "glBlitFramebufferEXT(color buffer datatypes mismatch)");
> +               return;
> +            }

You also need to move the multisampled compatible_resolve_formats (from 
below) into this loop.  Right here would be good.

> +         }
> +      }
> +
> +      if (colorDrawRb == NULL) {
> +	 colorReadRb = NULL;
> +	 mask &= ~GL_COLOR_BUFFER_BIT;
>         }
>      }
>      else {

The debug code at the bottom of the function will break since it still 
uses colorReadRb and colorDrawRb, but given that it's not paying 
attention to MRTs, it's probably already broken.  Maybe just comment 
it...or add a similar loop...

> diff --git a/src/mesa/swrast/s_blit.c b/src/mesa/swrast/s_blit.c
> index b0c56a4..043b578 100644
> --- a/src/mesa/swrast/s_blit.c
> +++ b/src/mesa/swrast/s_blit.c
> @@ -111,6 +111,11 @@ blit_nearest(struct gl_context *ctx,
>                GLbitfield buffer)
>   {
>      struct gl_renderbuffer *readRb, *drawRb;
> +   struct gl_renderbuffer_attachment *readAtt, *drawAtt;
> +   struct gl_framebuffer *readFb = ctx->ReadBuffer;
> +   struct gl_framebuffer *drawFb = ctx->DrawBuffer;
> +   GLint NumDrawBuffers = 0;
> +   GLuint i;
>
>      const GLint srcWidth = ABS(srcX1 - srcX0);
>      const GLint dstWidth = ABS(dstX1 - dstX0);
> @@ -146,21 +151,16 @@ blit_nearest(struct gl_context *ctx,
>
>      switch (buffer) {
>      case GL_COLOR_BUFFER_BIT:
> -      readRb = ctx->ReadBuffer->_ColorReadBuffer;
> -      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
> -
> -      if (readRb->Format == drawRb->Format) {
> -	 mode = DIRECT;
> -	 pixelSize = _mesa_get_format_bytes(readRb->Format);
> -      } else {
> -	 mode = UNPACK_RGBA_FLOAT;
> -	 pixelSize = 16;
> -      }
> -
> +      readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
> +      readRb = readFb->_ColorReadBuffer;
> +      NumDrawBuffers = drawFb->_NumColorDrawBuffers;
>         break;
>      case GL_DEPTH_BUFFER_BIT:
> -      readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
> -      drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
> +      readAtt = &readFb->Attachment[BUFFER_DEPTH];
> +      drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
> +      readRb = readAtt->Renderbuffer;
> +      drawRb = drawAtt->Renderbuffer;
> +      NumDrawBuffers = 1;
>
>         /* Note that for depth/stencil, the formats of src/dst must match.  By
>          * using the core helpers for pack/unpack, we avoid needing to handle
> @@ -175,8 +175,11 @@ blit_nearest(struct gl_context *ctx,
>         pixelSize = 4;
>         break;
>      case GL_STENCIL_BUFFER_BIT:
> -      readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
> -      drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
> +      readAtt = &readFb->Attachment[BUFFER_STENCIL];
> +      drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
> +      readRb = readAtt->Renderbuffer;
> +      drawRb = drawAtt->Renderbuffer;
> +      NumDrawBuffers = 1;
>         mode = UNPACK_S;
>         pixelSize = 1;
>         break;
> @@ -208,146 +211,167 @@ blit_nearest(struct gl_context *ctx,
>         return;
>      }
>
> -   if (readRb == drawRb) {
> -      /* map whole buffer for read/write */
> -      /* XXX we could be clever and just map the union region of the
> -       * source and dest rects.
> -       */
> -      GLubyte *map;
> -      GLint rowStride;
> -      GLint formatSize = _mesa_get_format_bytes(readRb->Format);
> -
> -      ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
> -                                  readRb->Width, readRb->Height,
> -                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
> -                                  &map, &rowStride);
> -      if (!map) {
> -         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> -         return;
> +   /* Blit to all the draw buffers */
> +   for (i = 0; i < NumDrawBuffers; i++) {
> +      if (buffer == GL_COLOR_BUFFER_BIT) {
> +         int idx = drawFb->_ColorDrawBufferIndexes[i];
> +         if (idx == -1)
> +            continue;
> +         drawAtt = &drawFb->Attachment[idx];
> +         drawRb = drawAtt->Renderbuffer;
> +
> +         if (readRb->Format == drawRb->Format) {
> +            mode = DIRECT;
> +            pixelSize = _mesa_get_format_bytes(readRb->Format);
> +         } else {
> +            mode = UNPACK_RGBA_FLOAT;
> +            pixelSize = 16;
> +         }
>         }
>
> -      srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
> -      dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
> +      if ((readRb == drawRb) ||

I'm not sure if you need this readRb == drawRb check anymore.  It seems 
like you just want the texture checks below.  Or maybe it needs to be &&...

> +          (readAtt->Texture && drawAtt->Texture &&
> +           (readAtt->Texture == drawAtt->Texture))) {
> +         /* map whole buffer for read/write */
> +         /* XXX we could be clever and just map the union region of the
> +          * source and dest rects.
> +          */
> +         GLubyte *map;
> +         GLint rowStride;
> +         GLint formatSize = _mesa_get_format_bytes(readRb->Format);
> +
> +         ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
> +                                     readRb->Width, readRb->Height,
> +                                     GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
> +                                     &map, &rowStride);
> +         if (!map) {
> +            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +            return;
> +         }
> +
> +         srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
> +         dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
>
> -      /* this handles overlapping copies */
> -      if (srcY0 < dstY0) {
> -         /* copy in reverse (top->down) order */
> -         srcMap += rowStride * (readRb->Height - 1);
> -         dstMap += rowStride * (readRb->Height - 1);
> -         srcRowStride = -rowStride;
> -         dstRowStride = -rowStride;
> +         /* this handles overlapping copies */
> +         if (srcY0 < dstY0) {
> +            /* copy in reverse (top->down) order */
> +            srcMap += rowStride * (readRb->Height - 1);
> +            dstMap += rowStride * (readRb->Height - 1);
> +            srcRowStride = -rowStride;
> +            dstRowStride = -rowStride;
> +         }
> +         else {
> +            /* copy in normal (bottom->up) order */
> +            srcRowStride = rowStride;
> +            dstRowStride = rowStride;
> +         }
>         }
>         else {
> -         /* copy in normal (bottom->up) order */
> -         srcRowStride = rowStride;
> -         dstRowStride = rowStride;
> +         /* different src/dst buffers */
> +         ctx->Driver.MapRenderbuffer(ctx, readRb,
> +                                     srcXpos, srcYpos,
> +                                     srcWidth, srcHeight,
> +                                     GL_MAP_READ_BIT, &srcMap, &srcRowStride);
> +         if (!srcMap) {
> +            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +            return;
> +         }
> +         ctx->Driver.MapRenderbuffer(ctx, drawRb,
> +                                     dstXpos, dstYpos,
> +                                     dstWidth, dstHeight,
> +                                     GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
> +         if (!dstMap) {
> +            ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> +            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +            return;
> +         }
>         }
> -   }
> -   else {
> -      /* different src/dst buffers */
> -      ctx->Driver.MapRenderbuffer(ctx, readRb,
> -				  srcXpos, srcYpos,
> -                                  srcWidth, srcHeight,
> -                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
> -      if (!srcMap) {
> -         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +
> +      /* allocate the src/dst row buffers */
> +      srcBuffer = malloc(pixelSize * srcWidth);
> +      if (!srcBuffer) {
> +         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
>            return;
>         }
> -      ctx->Driver.MapRenderbuffer(ctx, drawRb,
> -				  dstXpos, dstYpos,
> -                                  dstWidth, dstHeight,
> -                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
> -      if (!dstMap) {
> -         ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> -         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +      dstBuffer = malloc(pixelSize * dstWidth);
> +      if (!dstBuffer) {
> +         free(srcBuffer);
> +         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
>            return;
>         }
> -   }
>
> -   /* allocate the src/dst row buffers */
> -   srcBuffer = malloc(pixelSize * srcWidth);
> -   if (!srcBuffer) {
> -      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
> -      return;
> -   }
> -   dstBuffer = malloc(pixelSize * dstWidth);
> -   if (!dstBuffer) {
> -      free(srcBuffer);
> -      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
> -      return;
> -   }
> -
> -   for (dstRow = 0; dstRow < dstHeight; dstRow++) {
> -      GLint srcRow = (dstRow * srcHeight) / dstHeight;
> -      GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
> +      for (dstRow = 0; dstRow < dstHeight; dstRow++) {
> +         GLint srcRow = (dstRow * srcHeight) / dstHeight;
> +         GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
>
> -      ASSERT(srcRow >= 0);
> -      ASSERT(srcRow < srcHeight);
> +         ASSERT(srcRow >= 0);
> +         ASSERT(srcRow < srcHeight);
>
> -      if (invertY) {
> -         srcRow = srcHeight - 1 - srcRow;
> -      }
> +         if (invertY) {
> +            srcRow = srcHeight - 1 - srcRow;
> +         }
>
> -      /* get pixel row from source and resample to match dest width */
> -      if (prevY != srcRow) {
> -	 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
> -
> -	 switch (mode) {
> -	 case DIRECT:
> -	    memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
> -	    break;
> -	 case UNPACK_RGBA_FLOAT:
> -	    _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
> -				  srcBuffer);
> -	    break;
> -	 case UNPACK_Z_FLOAT:
> -	    _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
> -				     srcBuffer);
> -	    break;
> -	 case UNPACK_Z_INT:
> -	    _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
> -				    srcBuffer);
> -	    break;
> -	 case UNPACK_S:
> -	    _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
> -					   srcRowStart, srcBuffer);
> -	    break;
> -	 }
> +         /* get pixel row from source and resample to match dest width */
> +         if (prevY != srcRow) {
> +            GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
> +
> +            switch (mode) {
> +            case DIRECT:
> +               memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
> +               break;
> +            case UNPACK_RGBA_FLOAT:
> +               _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
> +                                     srcBuffer);
> +               break;
> +            case UNPACK_Z_FLOAT:
> +               _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
> +                                        srcBuffer);
> +               break;
> +            case UNPACK_Z_INT:
> +               _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
> +                                       srcBuffer);
> +               break;
> +            case UNPACK_S:
> +               _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
> +                                              srcRowStart, srcBuffer);
> +               break;
> +            }
>
> -         (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
> -         prevY = srcRow;
> -      }
> +            (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
> +            prevY = srcRow;
> +         }
>
> -      /* store pixel row in destination */
> -      switch (mode) {
> -      case DIRECT:
> -	 memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth);
> -	 break;
> -      case UNPACK_RGBA_FLOAT:
> -	 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
> -				   dstRowStart);
> -	 break;
> -      case UNPACK_Z_FLOAT:
> -	 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
> -				dstRowStart);
> -	 break;
> -      case UNPACK_Z_INT:
> -	 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
> -			       dstRowStart);
> -	 break;
> -      case UNPACK_S:
> -	 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
> -				      dstRowStart);
> -	 break;
> +         /* store pixel row in destination */
> +         switch (mode) {
> +         case DIRECT:
> +            memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth);
> +            break;
> +         case UNPACK_RGBA_FLOAT:
> +            _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
> +                                      dstRowStart);
> +            break;
> +         case UNPACK_Z_FLOAT:
> +            _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
> +                                   dstRowStart);
> +            break;
> +         case UNPACK_Z_INT:
> +            _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
> +                                  dstRowStart);
> +            break;
> +         case UNPACK_S:
> +            _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
> +                                         dstRowStart);
> +            break;
> +         }
>         }
> -   }
>
> -   free(srcBuffer);
> -   free(dstBuffer);
> +      free(srcBuffer);
> +      free(dstBuffer);
>
> -   ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> -   if (drawRb != readRb) {
> -      ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
> +      ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> +      if (drawRb != readRb) {
> +         ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
> +      }
>      }
>   }
>
> @@ -489,8 +513,13 @@ blit_linear(struct gl_context *ctx,
>               GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
>               GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
>   {
> -   struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer;
> -   struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
> +   struct gl_framebuffer *drawFb = ctx->DrawBuffer;
> +   struct gl_renderbuffer *drawRb = NULL;
> +   struct gl_renderbuffer_attachment *drawAtt = NULL;
> +   struct gl_framebuffer *readFb = ctx->ReadBuffer;
> +   struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
> +   struct gl_renderbuffer_attachment *readAtt =
> +      &readFb->Attachment[readFb->_ColorReadBufferIndex];
>
>      const GLint srcWidth = ABS(srcX1 - srcX0);
>      const GLint dstWidth = ABS(dstX1 - dstX0);
> @@ -521,6 +550,7 @@ blit_linear(struct gl_context *ctx,
>
>      GLubyte *srcMap, *dstMap;
>      GLint srcRowStride, dstRowStride;
> +   GLuint i;
>
>
>      /* Determine datatype for resampling */
> @@ -556,151 +586,160 @@ blit_linear(struct gl_context *ctx,
>         return;
>      }
>
> -   /*
> -    * Map src / dst renderbuffers
> -    */
> -   if (readRb == drawRb) {
> -      /* map whole buffer for read/write */
> -      ctx->Driver.MapRenderbuffer(ctx, readRb,
> -                                  0, 0, readRb->Width, readRb->Height,
> -                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
> -                                  &srcMap, &srcRowStride);
> -      if (!srcMap) {
> -         free(srcBuffer0);
> -         free(srcBuffer1);
> -         free(dstBuffer);
> -         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> -         return;
> -      }
> -
> -      dstMap = srcMap;
> -      dstRowStride = srcRowStride;
> -   }
> -   else {
> -      /* different src/dst buffers */
> -      /* XXX with a bit of work we could just map the regions to be
> -       * read/written instead of the whole buffers.
> +   for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
> +      int idx = drawFb->_ColorDrawBufferIndexes[i];
> +      if (idx == -1)
> +         continue;
> +      drawAtt = &drawFb->Attachment[idx];
> +      drawRb = drawAtt->Renderbuffer;
> +      /*
> +       * Map src / dst renderbuffers
>          */
> -      ctx->Driver.MapRenderbuffer(ctx, readRb,
> -				  0, 0, readRb->Width, readRb->Height,
> -                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
> -      if (!srcMap) {
> -         free(srcBuffer0);
> -         free(srcBuffer1);
> -         free(dstBuffer);
> -         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> -         return;
> +      if ((readRb == drawRb) ||

Ditto.  Otherwise, the swrast changes look okay...

> +          (readAtt->Texture && drawAtt->Texture &&
> +           (readAtt->Texture = drawAtt->Texture))) {
> +         /* map whole buffer for read/write */
> +         ctx->Driver.MapRenderbuffer(ctx, readRb,
> +                                     0, 0, readRb->Width, readRb->Height,
> +                                     GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
> +                                     &srcMap, &srcRowStride);
> +         if (!srcMap) {
> +            free(srcBuffer0);
> +            free(srcBuffer1);
> +            free(dstBuffer);
> +            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +            return;
> +         }
> +
> +         dstMap = srcMap;
> +         dstRowStride = srcRowStride;
>         }
> -      ctx->Driver.MapRenderbuffer(ctx, drawRb,
> -                                  0, 0, drawRb->Width, drawRb->Height,
> -                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
> -      if (!dstMap) {
> -         ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> -         free(srcBuffer0);
> -         free(srcBuffer1);
> -         free(dstBuffer);
> -         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> -         return;
> +      else {
> +         /* different src/dst buffers */
> +         /* XXX with a bit of work we could just map the regions to be
> +          * read/written instead of the whole buffers.
> +          */
> +         ctx->Driver.MapRenderbuffer(ctx, readRb,
> +                                     0, 0, readRb->Width, readRb->Height,
> +                                     GL_MAP_READ_BIT, &srcMap, &srcRowStride);
> +         if (!srcMap) {
> +            free(srcBuffer0);
> +            free(srcBuffer1);
> +            free(dstBuffer);
> +            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +            return;
> +         }
> +         ctx->Driver.MapRenderbuffer(ctx, drawRb,
> +                                     0, 0, drawRb->Width, drawRb->Height,
> +                                     GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
> +         if (!dstMap) {
> +            ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> +            free(srcBuffer0);
> +            free(srcBuffer1);
> +            free(dstBuffer);
> +            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
> +            return;
> +         }
>         }
> -   }
>
> -   for (dstRow = 0; dstRow < dstHeight; dstRow++) {
> -      const GLint dstY = dstYpos + dstRow;
> -      const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF;
> -      GLint srcRow0 = IFLOOR(srcRow);
> -      GLint srcRow1 = srcRow0 + 1;
> -      GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
> +      for (dstRow = 0; dstRow < dstHeight; dstRow++) {
> +         const GLint dstY = dstYpos + dstRow;
> +         const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF;
> +         GLint srcRow0 = IFLOOR(srcRow);
> +         GLint srcRow1 = srcRow0 + 1;
> +         GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
>
> -      ASSERT(srcRow >= 0);
> -      ASSERT(srcRow < srcHeight);
> +         ASSERT(srcRow >= 0);
> +         ASSERT(srcRow < srcHeight);
>
> -      if (srcRow1 == srcHeight) {
> -         /* last row fudge */
> -         srcRow1 = srcRow0;
> -         rowWeight = 0.0;
> -      }
> +         if (srcRow1 == srcHeight) {
> +            /* last row fudge */
> +            srcRow1 = srcRow0;
> +            rowWeight = 0.0;
> +         }
>
> -      if (invertY) {
> -         srcRow0 = srcHeight - 1 - srcRow0;
> -         srcRow1 = srcHeight - 1 - srcRow1;
> -      }
> +         if (invertY) {
> +            srcRow0 = srcHeight - 1 - srcRow0;
> +            srcRow1 = srcHeight - 1 - srcRow1;
> +         }
>
> -      srcY0 = srcYpos + srcRow0;
> -      srcY1 = srcYpos + srcRow1;
> +         srcY0 = srcYpos + srcRow0;
> +         srcY1 = srcYpos + srcRow1;
>
> -      /* get the two source rows */
> -      if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
> -         /* use same source row buffers again */
> -      }
> -      else if (srcY0 == srcBufferY1) {
> -         /* move buffer1 into buffer0 by swapping pointers */
> -         GLvoid *tmp = srcBuffer0;
> -         srcBuffer0 = srcBuffer1;
> -         srcBuffer1 = tmp;
> -         /* get y1 row */
> -         {
> -            GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
> -            if (pixelType == GL_UNSIGNED_BYTE) {
> -               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
> -                                           src, srcBuffer1);
> +         /* get the two source rows */
> +         if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
> +            /* use same source row buffers again */
> +         }
> +         else if (srcY0 == srcBufferY1) {
> +            /* move buffer1 into buffer0 by swapping pointers */
> +            GLvoid *tmp = srcBuffer0;
> +            srcBuffer0 = srcBuffer1;
> +            srcBuffer1 = tmp;
> +            /* get y1 row */
> +            {
> +               GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
> +               if (pixelType == GL_UNSIGNED_BYTE) {
> +                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
> +                                              src, srcBuffer1);
> +               }
> +               else {
> +                  _mesa_unpack_rgba_row(readFormat, srcWidth,
> +                                        src, srcBuffer1);
> +               }
>               }
> -            else {
> -               _mesa_unpack_rgba_row(readFormat, srcWidth,
> -                                     src, srcBuffer1);
> +            srcBufferY0 = srcY0;
> +            srcBufferY1 = srcY1;
> +         }
> +         else {
> +            /* get both new rows */
> +            {
> +               GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
> +               GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
> +               if (pixelType == GL_UNSIGNED_BYTE) {
> +                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
> +                                              src0, srcBuffer0);
> +                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
> +                                              src1, srcBuffer1);
> +               }
> +               else {
> +                  _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
> +                  _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
> +               }
>               }
> -         }
> -         srcBufferY0 = srcY0;
> -         srcBufferY1 = srcY1;
> -      }
> -      else {
> -         /* get both new rows */
> +            srcBufferY0 = srcY0;
> +            srcBufferY1 = srcY1;
> +         }
> +
> +         if (pixelType == GL_UNSIGNED_BYTE) {
> +            resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
> +                                   dstBuffer, invertX, rowWeight);
> +         }
> +         else {
> +            resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
> +                                      dstBuffer, invertX, rowWeight);
> +         }
> +
> +         /* store pixel row in destination */
>            {
> -            GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
> -            GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
> +            GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
>               if (pixelType == GL_UNSIGNED_BYTE) {
> -               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
> -                                           src0, srcBuffer0);
> -               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
> -                                           src1, srcBuffer1);
> +               _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
>               }
>               else {
> -               _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
> -               _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
> +               _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
>               }
>            }
> -         srcBufferY0 = srcY0;
> -         srcBufferY1 = srcY1;
>         }
>
> -      if (pixelType == GL_UNSIGNED_BYTE) {
> -         resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
> -                                dstBuffer, invertX, rowWeight);
> -      }
> -      else {
> -         resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
> -                                   dstBuffer, invertX, rowWeight);
> -      }
> +      free(srcBuffer0);
> +      free(srcBuffer1);
> +      free(dstBuffer);
>
> -      /* store pixel row in destination */
> -      {
> -         GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
> -         if (pixelType == GL_UNSIGNED_BYTE) {
> -            _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
> -         }
> -         else {
> -            _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
> -         }
> +      ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> +      if (drawRb != readRb) {
> +         ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
>         }
>      }
> -
> -   free(srcBuffer0);
> -   free(srcBuffer1);
> -   free(dstBuffer);
> -
> -   ctx->Driver.UnmapRenderbuffer(ctx, readRb);
> -   if (drawRb != readRb) {
> -      ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
> -   }
>   }
>
>
>



More information about the mesa-dev mailing list