On Tue, Dec 13, 2011 at 1:53 PM, Eric Anholt <e...@anholt.net> wrote: > There is one significant functional change here: the simple blit now > only handles exact matches of formats. From the > ARB_framebuffer_object spec: > > "If the color formats of the read and draw framebuffers do not > match, and <mask> includes COLOR_BUFFER_BIT, pixel groups are > converted to match the destination format as in CopyPixels" > > The previous code would generally do this, unless the RB DataTypes > didn't match, in which case it assertion failed. Rather than adding > special-case format conversion code to the simple path, fall back to > the slow paths which will need to handle format conversion as well. > --- > src/mesa/swrast/s_blit.c | 188 +++++++++++++++++++++++---------------------- > 1 files changed, 96 insertions(+), 92 deletions(-) > > diff --git a/src/mesa/swrast/s_blit.c b/src/mesa/swrast/s_blit.c > index 803ad2e..6f10c3a 100644 > --- a/src/mesa/swrast/s_blit.c > +++ b/src/mesa/swrast/s_blit.c > @@ -454,7 +454,7 @@ blit_linear(struct gl_context *ctx, > * Simple case: Blit color, depth or stencil with no scaling or flipping. > * XXX we could easily support vertical flipping here. > */ > -static void > +static GLboolean > simple_blit(struct gl_context *ctx, > GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, > GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, > @@ -463,9 +463,10 @@ simple_blit(struct gl_context *ctx, > struct gl_renderbuffer *readRb, *drawRb; > const GLint width = srcX1 - srcX0; > const GLint height = srcY1 - srcY0; > - GLint row, srcY, dstY, yStep; > - GLint comps, bytesPerRow; > - void *rowBuffer; > + GLint row; > + GLint bytesPerRow, srcStride, dstStride; > + void *temp = NULL; > + GLubyte *srcMap, *dstMap; > > /* only one buffer */ > ASSERT(_mesa_bitcount(buffer) == 1); > @@ -478,85 +479,93 @@ simple_blit(struct gl_context *ctx, > ASSERT(srcX1 - srcX0 == dstX1 - dstX0); > ASSERT(srcY1 - srcY0 == dstY1 - dstY0); > > - /* From the GL_ARB_framebuffer_object spec: > - * > - * "If the source and destination buffers are identical, and the > source > - * and destination rectangles overlap, the result of the blit > operation > - * is undefined." > - * > - * However, we provide the expected result anyway by flipping the order of > - * the memcpy of rows. > - */ > - if (srcY0 > dstY0) { > - /* src above dst: copy bottom-to-top */ > - yStep = 1; > - srcY = srcY0; > - dstY = dstY0; > - } > - else { > - /* src below dst: copy top-to-bottom */ > - yStep = -1; > - srcY = srcY1 - 1; > - dstY = dstY1 - 1; > - } > - > switch (buffer) { > case GL_COLOR_BUFFER_BIT: > readRb = ctx->ReadBuffer->_ColorReadBuffer; > drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; > - comps = 4; > break; > case GL_DEPTH_BUFFER_BIT: > - readRb = ctx->ReadBuffer->_DepthBuffer; > - drawRb = ctx->DrawBuffer->_DepthBuffer; > - comps = 1; > + readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; > + drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; > break; > case GL_STENCIL_BUFFER_BIT: > - readRb = ctx->ReadBuffer->_StencilBuffer; > - drawRb = ctx->DrawBuffer->_StencilBuffer; > - comps = 1; > + readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; > + drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; > break; > default: > _mesa_problem(ctx, "unexpected buffer in simple_blit()"); > - return; > + return GL_TRUE; > } > > - ASSERT(readRb->DataType == drawRb->DataType); > + if (readRb->Format != drawRb->Format) > + return GL_FALSE; > > - /* compute bytes per row */ > - switch (readRb->DataType) { > - case GL_UNSIGNED_BYTE: > - bytesPerRow = comps * width * sizeof(GLubyte); > - break; > - case GL_UNSIGNED_SHORT: > - bytesPerRow = comps * width * sizeof(GLushort); > - break; > - case GL_UNSIGNED_INT: > - bytesPerRow = comps * width * sizeof(GLuint); > - break; > - case GL_FLOAT: > - bytesPerRow = comps * width * sizeof(GLfloat); > - break; > - default: > - _mesa_problem(ctx, "unexpected buffer type in simple_blit"); > - return; > + /* This path does direct memcpy of the data, and if the buffers are > + * depth/stencil, it would end up stomping over the other one of depth or > + * stencil even though it wasn't asked to. > + */ > + if (_mesa_is_format_packed_depth_stencil(readRb->Format)) > + return GL_FALSE; > + > + bytesPerRow = _mesa_get_format_bytes(readRb->Format) * width; > + > + ctx->Driver.MapRenderbuffer(ctx, readRb, srcX0, srcY0, width, height, > + GL_MAP_READ_BIT, &srcMap, &srcStride); > + if (!srcMap) { > + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); > + return GL_TRUE; > + } > + > + /* From the GL_ARB_framebuffer_object spec: > + * > + * "If the source and destination buffers are identical, and the > source > + * and destination rectangles overlap, the result of the blit > operation > + * is undefined." > + * > + * However, we provide the expected result anyway by copying to a > temporary, > + * since we can't do nested MapRenderbuffer()s on the same RB. > + */ > + if (drawRb == readRb) { > + temp = malloc(bytesPerRow * height); > + if (!temp) { > + ctx->Driver.UnmapRenderbuffer(ctx, readRb); > + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); > + return GL_TRUE; > + } > + > + for (row = 0; row < height; row++) { > + memcpy(temp + bytesPerRow * row, srcMap, bytesPerRow); > + > + srcMap += srcStride; > + } > + > + ctx->Driver.UnmapRenderbuffer(ctx, readRb); > + srcMap = temp; > + srcStride = bytesPerRow; > } > > - /* allocate the row buffer */ > - rowBuffer = malloc(bytesPerRow); > - if (!rowBuffer) { > + ctx->Driver.MapRenderbuffer(ctx, drawRb, dstX0, dstY0, width, height, > + GL_MAP_WRITE_BIT, &dstMap, &dstStride); > + if (!dstMap) { > _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); > - return; > + return GL_TRUE; > } > > for (row = 0; row < height; row++) { > - readRb->GetRow(ctx, readRb, width, srcX0, srcY, rowBuffer); > - drawRb->PutRow(ctx, drawRb, width, dstX0, dstY, rowBuffer, NULL); > - srcY += yStep; > - dstY += yStep; > + memcpy(dstMap, srcMap, bytesPerRow); > + > + srcMap += srcStride; > + dstMap += dstStride; > + } > + > + if (temp) { > + free(temp); > + } else { > + ctx->Driver.UnmapRenderbuffer(ctx, readRb); > } > + ctx->Driver.UnmapRenderbuffer(ctx, drawRb); > > - free(rowBuffer); > + return GL_TRUE; > } > > > @@ -575,6 +584,7 @@ _swrast_BlitFramebuffer(struct gl_context *ctx, > GL_STENCIL_BUFFER_BIT > }; > GLint i; > + GLboolean is_one_to_one; > > if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, > &dstX0, &dstY0, &dstX1, &dstY1)) { > @@ -584,41 +594,35 @@ _swrast_BlitFramebuffer(struct gl_context *ctx, > if (SWRAST_CONTEXT(ctx)->NewState) > _swrast_validate_derived(ctx); > > - swrast_render_start(ctx); > - > - if (srcX1 - srcX0 == dstX1 - dstX0 && > - srcY1 - srcY0 == dstY1 - dstY0 && > - srcX0 < srcX1 && > - srcY0 < srcY1 && > - dstX0 < dstX1 && > - dstY0 < dstY1) { > - /* no stretching or flipping. > - * filter doesn't matter. > - */ > + is_one_to_one = (srcX1 - srcX0 == dstX1 - dstX0 && > + srcY1 - srcY0 == dstY1 - dstY0 && > + srcX0 < srcX1 && > + srcY0 < srcY1 && > + dstX0 < dstX1 && > + dstY0 < dstY1); > + > + if (filter == GL_NEAREST) { > for (i = 0; i < 3; i++) { > - if (mask & buffers[i]) { > - simple_blit(ctx, srcX0, srcY0, srcX1, srcY1, > - dstX0, dstY0, dstX1, dstY1, buffers[i]); > - } > + if (mask & buffers[i]) { > + if (is_one_to_one && !simple_blit(ctx, > + srcX0, srcY0, srcX1, srcY1, > + dstX0, dstY0, dstX1, dstY1, > + buffers[i])) { > + swrast_render_start(ctx); > + blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1, > + dstX0, dstY0, dstX1, dstY1, buffers[i]); > + swrast_render_finish(ctx); > + } > + } > } > } > else { > - if (filter == GL_NEAREST) { > - for (i = 0; i < 3; i++) { > - if (mask & buffers[i]) { > - blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1, > - dstX0, dstY0, dstX1, dstY1, buffers[i]); > - } > - } > - } > - else { > - ASSERT(filter == GL_LINEAR); > - if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ > - blit_linear(ctx, srcX0, srcY0, srcX1, srcY1, > - dstX0, dstY0, dstX1, dstY1); > - } > + ASSERT(filter == GL_LINEAR); > + if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ > + swrast_render_start(ctx); > + blit_linear(ctx, srcX0, srcY0, srcX1, srcY1, > + dstX0, dstY0, dstX1, dstY1); > + swrast_render_finish(ctx); > } > } > - > - swrast_render_finish(ctx); > }
Looks good, but I think guts of simple_blit() are an awful lot like fast_copy_pixels() in s_copypix.c. I think we could refactor a little bit and have one function for both cases. For the srcRb==dstRb case of glCopyPixels I just map the whole rb READ/WRITE and do memcpy() without a temporary image. -Brian _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev