X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_blit.c;h=6b7e5e4533381a077be10248ee7917716460a77e;hb=HEAD;hp=753f3136f550c88a7babaacefe25ca291a024ea0;hpb=685340a53e1dcb2a888e634ee71ba24356befe69;p=mesa.git diff --git a/src/mesa/swrast/s_blit.c b/src/mesa/swrast/s_blit.c index 753f3136f55..6b7e5e45333 100644 --- a/src/mesa/swrast/s_blit.c +++ b/src/mesa/swrast/s_blit.c @@ -1,6 +1,5 @@ /* * Mesa 3-D graphics library - * Version: 6.5 * * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * @@ -17,9 +16,10 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ @@ -27,6 +27,9 @@ #include "main/condrender.h" #include "main/image.h" #include "main/macros.h" +#include "main/format_unpack.h" +#include "main/format_pack.h" +#include "main/condrender.h" #include "s_context.h" @@ -49,8 +52,8 @@ NAME(GLint srcWidth, GLint dstWidth, \ if (flip) { \ for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ GLint srcCol = (dstCol * srcWidth) / dstWidth; \ - ASSERT(srcCol >= 0); \ - ASSERT(srcCol < srcWidth); \ + assert(srcCol >= 0); \ + assert(srcCol < srcWidth); \ srcCol = srcWidth - 1 - srcCol; /* flip */ \ if (SIZE == 1) { \ dst[dstCol] = src[srcCol]; \ @@ -70,8 +73,8 @@ NAME(GLint srcWidth, GLint dstWidth, \ else { \ for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ GLint srcCol = (dstCol * srcWidth) / dstWidth; \ - ASSERT(srcCol >= 0); \ - ASSERT(srcCol < srcWidth); \ + assert(srcCol >= 0); \ + assert(srcCol < srcWidth); \ if (SIZE == 1) { \ dst[dstCol] = src[srcCol]; \ } \ @@ -103,12 +106,17 @@ RESAMPLE(resample_row_16, GLuint, 4) * Blit color, depth or stencil with GL_NEAREST filtering. */ static void -blit_nearest(GLcontext *ctx, +blit_nearest(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield buffer) { - struct gl_renderbuffer *readRb, *drawRb; + struct gl_renderbuffer *readRb, *drawRb = NULL; + struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL; + GLuint numDrawBuffers = 0; + GLuint i; const GLint srcWidth = ABS(srcX1 - srcX0); const GLint dstWidth = ABS(dstX1 - dstX0); @@ -122,10 +130,18 @@ blit_nearest(GLcontext *ctx, const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); - + enum mode { + DIRECT, + UNPACK_RGBA_FLOAT, + UNPACK_Z_FLOAT, + UNPACK_Z_INT, + UNPACK_S, + } mode = DIRECT; + GLubyte *srcMap, *dstMap; + GLint srcRowStride, dstRowStride; GLint dstRow; - GLint comps, pixelSize; + GLint pixelSize = 0; GLvoid *srcBuffer, *dstBuffer; GLint prevY = -1; @@ -136,114 +152,238 @@ blit_nearest(GLcontext *ctx, switch (buffer) { case GL_COLOR_BUFFER_BIT: - readRb = ctx->ReadBuffer->_ColorReadBuffer; - drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; - comps = 4; + readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex]; + readRb = readFb->_ColorReadBuffer; + numDrawBuffers = drawFb->_NumColorDrawBuffers; break; case GL_DEPTH_BUFFER_BIT: - readRb = ctx->ReadBuffer->_DepthBuffer; - drawRb = ctx->DrawBuffer->_DepthBuffer; - comps = 1; + 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 + * masking for things like DEPTH copies of Z24S8. + */ + if (readRb->Format == MESA_FORMAT_Z_FLOAT32 || + readRb->Format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) { + mode = UNPACK_Z_FLOAT; + } else { + mode = UNPACK_Z_INT; + } + pixelSize = 4; break; case GL_STENCIL_BUFFER_BIT: - readRb = ctx->ReadBuffer->_StencilBuffer; - drawRb = ctx->DrawBuffer->_StencilBuffer; - comps = 1; + readAtt = &readFb->Attachment[BUFFER_STENCIL]; + drawAtt = &drawFb->Attachment[BUFFER_STENCIL]; + readRb = readAtt->Renderbuffer; + drawRb = drawAtt->Renderbuffer; + numDrawBuffers = 1; + mode = UNPACK_S; + pixelSize = 1; break; default: _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); return; } - switch (readRb->DataType) { - case GL_UNSIGNED_BYTE: - pixelSize = comps * sizeof(GLubyte); - break; - case GL_UNSIGNED_SHORT: - pixelSize = comps * sizeof(GLushort); - break; - case GL_UNSIGNED_INT: - pixelSize = comps * sizeof(GLuint); - break; - case GL_FLOAT: - pixelSize = comps * sizeof(GLfloat); - break; - default: - _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest", - readRb->DataType); - return; - } - - /* choose row resampler */ - switch (pixelSize) { - case 1: - resampleRow = resample_row_1; - break; - case 2: - resampleRow = resample_row_2; - break; - case 4: - resampleRow = resample_row_4; - break; - case 8: - resampleRow = resample_row_8; - break; - case 16: - resampleRow = resample_row_16; - break; - default: - _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", - pixelSize); - 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; - } + srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth); + dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth); + if (!srcBuffer || !dstBuffer) + goto fail_no_memory; + + /* Blit to all the draw buffers */ + for (i = 0; i < numDrawBuffers; i++) { + if (buffer == GL_COLOR_BUFFER_BIT) { + gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; + if (idx == BUFFER_NONE) + continue; + drawAtt = &drawFb->Attachment[idx]; + drawRb = drawAtt->Renderbuffer; + + if (!drawRb) + continue; + + if (readRb->Format == drawRb->Format) { + mode = DIRECT; + pixelSize = _mesa_get_format_bytes(readRb->Format); + } else { + mode = UNPACK_RGBA_FLOAT; + pixelSize = 16; + } + } + + /* choose row resampler */ + switch (pixelSize) { + case 1: + resampleRow = resample_row_1; + break; + case 2: + resampleRow = resample_row_2; + break; + case 4: + resampleRow = resample_row_4; + break; + case 8: + resampleRow = resample_row_8; + break; + case 16: + resampleRow = resample_row_16; + break; + default: + _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", + pixelSize); + goto fail; + } - for (dstRow = 0; dstRow < dstHeight; dstRow++) { - const GLint dstY = dstYpos + dstRow; - GLint srcRow = (dstRow * srcHeight) / dstHeight; - GLint srcY; + if ((readRb == drawRb) || + (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, readFb->FlipY); + if (!map) { + goto fail_no_memory; + } - ASSERT(srcRow >= 0); - ASSERT(srcRow < srcHeight); + srcMap = map + srcYpos * rowStride + srcXpos * formatSize; + dstMap = map + dstYpos * rowStride + dstXpos * formatSize; - if (invertY) { - srcRow = srcHeight - 1 - srcRow; + /* 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 { + /* different src/dst buffers */ + ctx->Driver.MapRenderbuffer(ctx, readRb, + srcXpos, srcYpos, + srcWidth, srcHeight, + GL_MAP_READ_BIT, &srcMap, &srcRowStride, + readFb->FlipY); + if (!srcMap) { + goto fail_no_memory; + } + ctx->Driver.MapRenderbuffer(ctx, drawRb, + dstXpos, dstYpos, + dstWidth, dstHeight, + GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, + drawFb->FlipY); + if (!dstMap) { + ctx->Driver.UnmapRenderbuffer(ctx, readRb); + goto fail_no_memory; + } } - srcY = srcYpos + srcRow; + for (dstRow = 0; dstRow < dstHeight; dstRow++) { + GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; + GLint srcRow = lroundf(srcRowF); + GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; + + assert(srcRow >= 0); + assert(srcRow < srcHeight); + + 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; + } + + resampleRow(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); + prevY = srcRow; + } - /* get pixel row from source and resample to match dest width */ - if (prevY != srcY) { - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY, srcBuffer); - (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); - prevY = srcY; + /* store pixel row in destination */ + switch (mode) { + case DIRECT: + memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth); + 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 */ - drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL); + ctx->Driver.UnmapRenderbuffer(ctx, readRb); + if (drawRb != readRb) { + ctx->Driver.UnmapRenderbuffer(ctx, drawRb); + } } +fail: free(srcBuffer); free(dstBuffer); + return; + +fail_no_memory: + free(srcBuffer); + free(dstBuffer); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer"); } #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) -static INLINE GLfloat +static inline GLfloat lerp_2d(GLfloat a, GLfloat b, GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) { @@ -265,19 +405,17 @@ resample_linear_row_ub(GLint srcWidth, GLint dstWidth, const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; - const GLfloat dstWidthF = (GLfloat) dstWidth; GLint dstCol; for (dstCol = 0; dstCol < dstWidth; dstCol++) { - const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF; - GLint srcCol0 = IFLOOR(srcCol); + const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; + GLint srcCol0 = MAX2(0, util_ifloor(srcCol)); GLint srcCol1 = srcCol0 + 1; GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ GLfloat red, green, blue, alpha; - ASSERT(srcCol0 >= 0); - ASSERT(srcCol0 < srcWidth); - ASSERT(srcCol1 <= srcWidth); + assert(srcCol0 < srcWidth); + assert(srcCol1 <= srcWidth); if (srcCol1 == srcWidth) { /* last column fudge */ @@ -302,32 +440,89 @@ resample_linear_row_ub(GLint srcWidth, GLint dstWidth, alpha = lerp_2d(colWeight, rowWeight, srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); - - dstColor[dstCol][RCOMP] = IFLOOR(red); - dstColor[dstCol][GCOMP] = IFLOOR(green); - dstColor[dstCol][BCOMP] = IFLOOR(blue); - dstColor[dstCol][ACOMP] = IFLOOR(alpha); + + dstColor[dstCol][RCOMP] = util_ifloor(red); + dstColor[dstCol][GCOMP] = util_ifloor(green); + dstColor[dstCol][BCOMP] = util_ifloor(blue); + dstColor[dstCol][ACOMP] = util_ifloor(alpha); + } +} + + +/** + * Bilinear interpolation of two source rows. floating point pixels. + */ +static void +resample_linear_row_float(GLint srcWidth, GLint dstWidth, + const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, + GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) +{ + const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0; + const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1; + GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer; + GLint dstCol; + + for (dstCol = 0; dstCol < dstWidth; dstCol++) { + const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; + GLint srcCol0 = MAX2(0, util_ifloor(srcCol)); + GLint srcCol1 = srcCol0 + 1; + GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ + GLfloat red, green, blue, alpha; + + assert(srcCol0 < srcWidth); + assert(srcCol1 <= srcWidth); + + if (srcCol1 == srcWidth) { + /* last column fudge */ + srcCol1--; + colWeight = 0.0; + } + + if (flip) { + srcCol0 = srcWidth - 1 - srcCol0; + srcCol1 = srcWidth - 1 - srcCol1; + } + + red = lerp_2d(colWeight, rowWeight, + srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], + srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); + green = lerp_2d(colWeight, rowWeight, + srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], + srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); + blue = lerp_2d(colWeight, rowWeight, + srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], + srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); + alpha = lerp_2d(colWeight, rowWeight, + srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], + srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); + + dstColor[dstCol][RCOMP] = red; + dstColor[dstCol][GCOMP] = green; + dstColor[dstCol][BCOMP] = blue; + dstColor[dstCol][ACOMP] = alpha; } } /** - * Bilinear filtered blit (color only). + * Bilinear filtered blit (color only, non-integer values). */ static void -blit_linear(GLcontext *ctx, +blit_linear(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb, 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_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); const GLint srcHeight = ABS(srcY1 - srcY0); const GLint dstHeight = ABS(dstY1 - dstY0); - const GLfloat dstHeightF = (GLfloat) dstHeight; const GLint srcXpos = MIN2(srcX0, srcX1); const GLint srcYpos = MIN2(srcY0, srcY1); @@ -344,219 +539,207 @@ blit_linear(GLcontext *ctx, GLint srcBufferY0 = -1, srcBufferY1 = -1; GLvoid *dstBuffer; - switch (readRb->DataType) { - case GL_UNSIGNED_BYTE: + mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); + GLuint bpp = _mesa_get_format_bytes(readFormat); + + GLenum pixelType; + + GLubyte *srcMap, *dstMap; + GLint srcRowStride, dstRowStride; + GLuint i; + + + /* Determine datatype for resampling */ + if (_mesa_get_format_max_bits(readFormat) == 8 && + _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { + pixelType = GL_UNSIGNED_BYTE; pixelSize = 4 * sizeof(GLubyte); - break; - case GL_UNSIGNED_SHORT: - pixelSize = 4 * sizeof(GLushort); - break; - case GL_UNSIGNED_INT: - pixelSize = 4 * sizeof(GLuint); - break; - case GL_FLOAT: + } + else { + pixelType = GL_FLOAT; pixelSize = 4 * sizeof(GLfloat); - break; - default: - _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest", - readRb->DataType); - return; } /* Allocate the src/dst row buffers. * Keep two adjacent src rows around for bilinear sampling. */ srcBuffer0 = malloc(pixelSize * srcWidth); - if (!srcBuffer0) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); - return; - } srcBuffer1 = malloc(pixelSize * srcWidth); - if (!srcBuffer1) { - free(srcBuffer0); - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); - return; - } dstBuffer = malloc(pixelSize * dstWidth); - if (!dstBuffer) { - free(srcBuffer0); - free(srcBuffer1); - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); - return; + if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) { + goto fail_no_memory; } - 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); + for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { + gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; + struct gl_renderbuffer_attachment *drawAtt; + struct gl_renderbuffer *drawRb; + mesa_format drawFormat; - if (srcRow1 == srcHeight) { - /* last row fudge */ - srcRow1 = srcRow0; - rowWeight = 0.0; - } + if (idx == BUFFER_NONE) + continue; - if (invertY) { - srcRow0 = srcHeight - 1 - srcRow0; - srcRow1 = srcHeight - 1 - srcRow1; - } + drawAtt = &drawFb->Attachment[idx]; + drawRb = drawAtt->Renderbuffer; + if (!drawRb) + continue; - srcY0 = srcYpos + srcRow0; - srcY1 = srcYpos + srcRow1; + drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); - /* 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 */ - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1); - srcBufferY0 = srcY0; - srcBufferY1 = srcY1; - } - else { - /* get both new rows */ - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY0, srcBuffer0); - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1); - srcBufferY0 = srcY0; - srcBufferY1 = srcY1; - } + /* + * Map src / dst renderbuffers + */ + if ((readRb == drawRb) || + (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, + readFb->FlipY); + if (!srcMap) { + goto fail_no_memory; + } - if (readRb->DataType == GL_UNSIGNED_BYTE) { - resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, - dstBuffer, invertX, rowWeight); + dstMap = srcMap; + dstRowStride = srcRowStride; } else { - _mesa_problem(ctx, "Unsupported color channel type in sw blit"); - break; + /* 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, + readFb->FlipY); + if (!srcMap) { + goto fail_no_memory; + } + ctx->Driver.MapRenderbuffer(ctx, drawRb, + 0, 0, drawRb->Width, drawRb->Height, + GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, + drawFb->FlipY); + if (!dstMap) { + ctx->Driver.UnmapRenderbuffer(ctx, readRb); + goto fail_no_memory; + } } - /* store pixel row in destination */ - drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL); - } - - free(srcBuffer0); - free(srcBuffer1); - free(dstBuffer); -} + for (dstRow = 0; dstRow < dstHeight; dstRow++) { + const GLint dstY = dstYpos + dstRow; + GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; + GLint srcRow0 = MAX2(0, util_ifloor(srcRow)); + GLint srcRow1 = srcRow0 + 1; + GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ + + if (srcRow1 == srcHeight) { + /* last row fudge */ + srcRow1 = srcRow0; + rowWeight = 0.0; + } + if (invertY) { + srcRow0 = srcHeight - 1 - srcRow0; + srcRow1 = srcHeight - 1 - srcRow1; + } -/** - * Simple case: Blit color, depth or stencil with no scaling or flipping. - * XXX we could easily support vertical flipping here. - */ -static void -simple_blit(GLcontext *ctx, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield buffer) -{ - 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; - - /* only one buffer */ - ASSERT(_mesa_bitcount(buffer) == 1); - /* no flipping checks */ - ASSERT(srcX0 < srcX1); - ASSERT(srcY0 < srcY1); - ASSERT(dstX0 < dstX1); - ASSERT(dstY0 < dstY1); - /* size checks */ - ASSERT(srcX1 - srcX0 == dstX1 - dstX0); - ASSERT(srcY1 - srcY0 == dstY1 - dstY0); - - /* determine if copy should be bottom-to-top or top-to-bottom */ - 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; - } + srcY0 = srcYpos + srcRow0; + srcY1 = srcYpos + srcRow1; - 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; - break; - case GL_STENCIL_BUFFER_BIT: - readRb = ctx->ReadBuffer->_StencilBuffer; - drawRb = ctx->DrawBuffer->_StencilBuffer; - comps = 1; - break; - default: - _mesa_problem(ctx, "unexpected buffer in simple_blit()"); - return; - } + /* 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); + } + } + 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; + } - ASSERT(readRb->DataType == drawRb->DataType); + 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); + } - /* 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; - } + /* 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); + } + } + } - /* allocate the row buffer */ - rowBuffer = malloc(bytesPerRow); - if (!rowBuffer) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); - return; + ctx->Driver.UnmapRenderbuffer(ctx, readRb); + if (drawRb != readRb) { + ctx->Driver.UnmapRenderbuffer(ctx, drawRb); + } } - 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; - } + free(srcBuffer0); + free(srcBuffer1); + free(dstBuffer); + return; - free(rowBuffer); +fail_no_memory: + free(srcBuffer0); + free(srcBuffer1); + free(dstBuffer); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); } + /** * Software fallback for glBlitFramebufferEXT(). */ void -_swrast_BlitFramebuffer(GLcontext *ctx, +_swrast_BlitFramebuffer(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) @@ -566,54 +749,68 @@ _swrast_BlitFramebuffer(GLcontext *ctx, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT }; + static const GLenum buffer_enums[3] = { + GL_COLOR, + GL_DEPTH, + GL_STENCIL, + }; GLint i; + /* Page 679 of OpenGL 4.4 spec says: + * "Added BlitFramebuffer to commands affected by conditional rendering in + * section 10.10 (Bug 9562)." + */ if (!_mesa_check_conditional_render(ctx)) - return; /* don't clear */ + return; /* Do not blit */ - if (!ctx->DrawBuffer->_NumColorDrawBuffers) - return; - - if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, + if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1, &dstX0, &dstY0, &dstX1, &dstY1)) { return; } - swrast_render_start(ctx); + if (SWRAST_CONTEXT(ctx)->NewState) + _swrast_validate_derived(ctx); + /* First, try covering whatever buffers possible using the fast 1:1 copy + * path. + */ 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. - */ for (i = 0; i < 3; i++) { if (mask & buffers[i]) { - simple_blit(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, buffers[i]); + if (swrast_fast_copy_pixels(ctx, + readFb, drawFb, + srcX0, srcY0, + srcX1 - srcX0, srcY1 - srcY0, + dstX0, dstY0, + buffer_enums[i])) { + mask &= ~buffers[i]; + } } } + + if (!mask) + return; } - 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]); - } - } + + if (filter == GL_NEAREST) { + for (i = 0; i < 3; i++) { + if (mask & buffers[i]) { + blit_nearest(ctx, readFb, drawFb, 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); - } + } + else { + assert(filter == GL_LINEAR); + if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ + blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1); } } - swrast_render_finish(ctx); }