X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_blit.c;h=6d0b889c1950b44560e900f0f6109d8a9992585d;hb=2b0aa3fb21386051976bf3c45e6455fc45d69bb3;hp=4a95c222d5681e21a19b819e1f974ad5a7122ce3;hpb=1f713059934c2365a42aadfdca49213b36a7de90;p=mesa.git diff --git a/src/mesa/swrast/s_blit.c b/src/mesa/swrast/s_blit.c index 4a95c222d56..6d0b889c195 100644 --- a/src/mesa/swrast/s_blit.c +++ b/src/mesa/swrast/s_blit.c @@ -24,8 +24,11 @@ #include "main/glheader.h" +#include "main/condrender.h" #include "main/image.h" #include "main/macros.h" +#include "main/format_unpack.h" +#include "main/format_pack.h" #include "s_context.h" @@ -102,10 +105,10 @@ 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, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLenum buffer) + GLbitfield buffer) { struct gl_renderbuffer *readRb, *drawRb; @@ -121,10 +124,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; + GLubyte *srcMap, *dstMap; + GLint srcRowStride, dstRowStride; GLint dstRow; - GLint comps, pixelSize; + GLint pixelSize; GLvoid *srcBuffer, *dstBuffer; GLint prevY = -1; @@ -137,42 +148,43 @@ blit_nearest(GLcontext *ctx, case GL_COLOR_BUFFER_BIT: readRb = ctx->ReadBuffer->_ColorReadBuffer; drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; - comps = 4; + + if (readRb->Format == drawRb->Format) { + mode = DIRECT; + pixelSize = _mesa_get_format_bytes(readRb->Format); + } else { + mode = UNPACK_RGBA_FLOAT; + pixelSize = 16; + } + 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; + + /* 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_Z32_FLOAT || + readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) { + 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; + readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + 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: @@ -196,23 +208,78 @@ blit_nearest(GLcontext *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; + } + + 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; + } + 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); + 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; + } + } + /* allocate the src/dst row buffers */ - srcBuffer = _mesa_malloc(pixelSize * srcWidth); + srcBuffer = malloc(pixelSize * srcWidth); if (!srcBuffer) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } - dstBuffer = _mesa_malloc(pixelSize * dstWidth); + dstBuffer = malloc(pixelSize * dstWidth); if (!dstBuffer) { - _mesa_free(srcBuffer); + free(srcBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } for (dstRow = 0; dstRow < dstHeight; dstRow++) { - const GLint dstY = dstYpos + dstRow; GLint srcRow = (dstRow * srcHeight) / dstHeight; - GLint srcY; + GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; ASSERT(srcRow >= 0); ASSERT(srcRow < srcHeight); @@ -221,28 +288,74 @@ blit_nearest(GLcontext *ctx, srcRow = srcHeight - 1 - srcRow; } - srcY = srcYpos + srcRow; - /* get pixel row from source and resample to match dest width */ - if (prevY != srcY) { - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY, srcBuffer); + 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 = srcY; + prevY = srcRow; } /* store pixel row in destination */ - drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL); + 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; + } } - _mesa_free(srcBuffer); - _mesa_free(dstBuffer); + free(srcBuffer); + free(dstBuffer); + + ctx->Driver.UnmapRenderbuffer(ctx, readRb); + if (drawRb != readRb) { + ctx->Driver.UnmapRenderbuffer(ctx, drawRb); + } } #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) { @@ -310,12 +423,69 @@ resample_linear_row_ub(GLint srcWidth, GLint dstWidth, } +/** + * 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; + const GLfloat dstWidthF = (GLfloat) dstWidth; + GLint dstCol; + + for (dstCol = 0; dstCol < dstWidth; dstCol++) { + const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF; + GLint srcCol0 = 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); + + 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, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) { @@ -343,47 +513,88 @@ blit_linear(GLcontext *ctx, GLint srcBufferY0 = -1, srcBufferY1 = -1; GLvoid *dstBuffer; - switch (readRb->DataType) { - case GL_UNSIGNED_BYTE: + gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); + gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); + GLuint bpp = _mesa_get_format_bytes(readFormat); + + GLenum pixelType; + + GLubyte *srcMap, *dstMap; + GLint srcRowStride, dstRowStride; + + + /* 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 = _mesa_malloc(pixelSize * srcWidth); + srcBuffer0 = malloc(pixelSize * srcWidth); if (!srcBuffer0) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } - srcBuffer1 = _mesa_malloc(pixelSize * srcWidth); + srcBuffer1 = malloc(pixelSize * srcWidth); if (!srcBuffer1) { - _mesa_free(srcBuffer0); + free(srcBuffer0); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } - dstBuffer = _mesa_malloc(pixelSize * dstWidth); + dstBuffer = malloc(pixelSize * dstWidth); if (!dstBuffer) { - _mesa_free(srcBuffer0); - _mesa_free(srcBuffer1); + free(srcBuffer0); + free(srcBuffer1); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); 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) { + _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. + */ + ctx->Driver.MapRenderbuffer(ctx, readRb, + 0, 0, readRb->Width, readRb->Height, + GL_MAP_READ_BIT, &srcMap, &srcRowStride); + if (!srcMap) { + _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); + _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; @@ -418,198 +629,141 @@ blit_linear(GLcontext *ctx, srcBuffer0 = srcBuffer1; srcBuffer1 = tmp; /* get y1 row */ - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1); + { + 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 */ - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY0, srcBuffer0); - readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1); + { + 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; } - if (readRb->DataType == GL_UNSIGNED_BYTE) { + if (pixelType == GL_UNSIGNED_BYTE) { resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, dstBuffer, invertX, rowWeight); } else { - _mesa_problem(ctx, "Unsupported color channel type in sw blit"); - break; + resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, + dstBuffer, invertX, rowWeight); } /* store pixel row in destination */ - drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL); - } - - _mesa_free(srcBuffer0); - _mesa_free(srcBuffer1); - _mesa_free(dstBuffer); -} - - -/** - * 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, - GLenum 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; - } - - 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; + { + 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); + } + } } - ASSERT(readRb->DataType == drawRb->DataType); + free(srcBuffer0); + free(srcBuffer1); + free(dstBuffer); - /* 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; - } - - /* allocate the row buffer */ - rowBuffer = _mesa_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; - } - - _mesa_free(rowBuffer); } + /** * Software fallback for glBlitFramebufferEXT(). */ void -_swrast_BlitFramebuffer(GLcontext *ctx, +_swrast_BlitFramebuffer(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - static const GLint buffers[3] = { + static const GLbitfield buffers[3] = { GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT }; + static const GLenum buffer_enums[3] = { + GL_COLOR, + GL_DEPTH, + GL_STENCIL, + }; GLint i; - if (!ctx->DrawBuffer->_NumColorDrawBuffers) - return; - if (!_mesa_clip_blit(ctx, &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, + 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, 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, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1); } } - swrast_render_finish(ctx); }