aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/swrast/s_blit.c
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/swrast/s_blit.c')
-rw-r--r--mesalib/src/mesa/swrast/s_blit.c352
1 files changed, 182 insertions, 170 deletions
diff --git a/mesalib/src/mesa/swrast/s_blit.c b/mesalib/src/mesa/swrast/s_blit.c
index 803ad2e89..1063024fb 100644
--- a/mesalib/src/mesa/swrast/s_blit.c
+++ b/mesalib/src/mesa/swrast/s_blit.c
@@ -27,6 +27,8 @@
#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"
@@ -122,10 +124,18 @@ blit_nearest(struct gl_context *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;
@@ -138,42 +148,43 @@ blit_nearest(struct gl_context *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:
@@ -197,6 +208,62 @@ 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;
+ }
+
+ 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 = malloc(pixelSize * srcWidth);
if (!srcBuffer) {
@@ -211,9 +278,8 @@ blit_nearest(struct gl_context *ctx,
}
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);
@@ -222,21 +288,67 @@ blit_nearest(struct gl_context *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;
+ }
}
free(srcBuffer);
free(dstBuffer);
+
+ ctx->Driver.UnmapRenderbuffer(ctx, readRb);
+ if (drawRb != readRb) {
+ ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
+ }
}
@@ -449,117 +561,6 @@ blit_linear(struct gl_context *ctx,
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(struct gl_context *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);
-
- /* 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;
- 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;
- }
-
- ASSERT(readRb->DataType == drawRb->DataType);
-
- /* 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 = malloc(bytesPerRow);
- if (!rowBuffer) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
- return;
- }
-
- 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(rowBuffer);
-}
-
-
/**
* Software fallback for glBlitFramebufferEXT().
*/
@@ -574,6 +575,11 @@ _swrast_BlitFramebuffer(struct gl_context *ctx,
GL_DEPTH_BUFFER_BIT,
GL_STENCIL_BUFFER_BIT
};
+ static const GLenum buffer_enums[3] = {
+ GL_COLOR,
+ GL_DEPTH,
+ GL_STENCIL,
+ };
GLint i;
if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
@@ -584,41 +590,47 @@ _swrast_BlitFramebuffer(struct gl_context *ctx,
if (SWRAST_CONTEXT(ctx)->NewState)
_swrast_validate_derived(ctx);
- swrast_render_start(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;
+ }
+
+ 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 {
- 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);
}