diff options
Diffstat (limited to 'src/mesa/swrast')
-rw-r--r-- | src/mesa/swrast/s_blit.c | 183 |
1 files changed, 158 insertions, 25 deletions
diff --git a/src/mesa/swrast/s_blit.c b/src/mesa/swrast/s_blit.c index 1063024fb4b..6d0b889c195 100644 --- a/src/mesa/swrast/s_blit.c +++ b/src/mesa/swrast/s_blit.c @@ -423,9 +423,66 @@ 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(struct gl_context *ctx, @@ -456,23 +513,25 @@ blit_linear(struct gl_context *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. @@ -497,6 +556,45 @@ 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) { + _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; @@ -531,36 +629,73 @@ blit_linear(struct gl_context *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); + { + 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); + } + } } free(srcBuffer0); free(srcBuffer1); free(dstBuffer); + + ctx->Driver.UnmapRenderbuffer(ctx, readRb); + if (drawRb != readRb) { + ctx->Driver.UnmapRenderbuffer(ctx, drawRb); + } } + + /** * Software fallback for glBlitFramebufferEXT(). */ @@ -626,10 +761,8 @@ _swrast_BlitFramebuffer(struct gl_context *ctx, else { 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); } } |