st/mesa: rework blit_copy_pixels to use pipe->blit

There were 2 issues with it:
- resource_copy_region doesn't allow different sample counts of both src
  and dst, which can occur if we blit between a window and a FBO, and
  the window has an MSAA colorbuffer and the FBO doesn't.
  (this was the main motivation for using pipe->blit)
- blitting from or to a non-zero layer/slice/face was broken, because
  rtt_face and rtt_slice were ignored.

blit_copy_pixels is now used even if the formats and orientation of
framebuffers don't match.

Reviewed-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
Marek Olšák
2013-05-30 21:34:06 +02:00
parent 4d59258856
commit 79e421260a

View File

@@ -1308,29 +1308,38 @@ st_get_color_read_renderbuffer(struct gl_context *ctx)
} }
/** Do the src/dest regions overlap? */ /**
static GLboolean * \return TRUE if two regions overlap, FALSE otherwise
regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY, */
GLsizei width, GLsizei height) static boolean
regions_overlap(int srcX0, int srcY0,
int srcX1, int srcY1,
int dstX0, int dstY0,
int dstX1, int dstY1)
{ {
if (srcX + width <= dstX || if (MAX2(srcX0, srcX1) < MIN2(dstX0, dstX1))
dstX + width <= srcX || return FALSE; /* src completely left of dst */
srcY + height <= dstY ||
dstY + height <= srcY) if (MAX2(dstX0, dstX1) < MIN2(srcX0, srcX1))
return GL_FALSE; return FALSE; /* dst completely left of src */
else
return GL_TRUE; if (MAX2(srcY0, srcY1) < MIN2(dstY0, dstY1))
return FALSE; /* src completely above dst */
if (MAX2(dstY0, dstY1) < MIN2(srcY0, srcY1))
return FALSE; /* dst completely above src */
return TRUE; /* some overlap */
} }
/** /**
* Try to do a glCopyPixels for simple cases with a blit by calling * Try to do a glCopyPixels for simple cases with a blit by calling
* pipe->resource_copy_region(). * pipe->blit().
* *
* We can do this when we're copying color pixels (depth/stencil * We can do this when we're copying color pixels (depth/stencil
* eventually) with no pixel zoom, no pixel transfer ops, no * eventually) with no pixel zoom, no pixel transfer ops, no
* per-fragment ops, the src/dest regions don't overlap and the * per-fragment ops, and the src/dest regions don't overlap.
* src/dest pixel formats are the same.
*/ */
static GLboolean static GLboolean
blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
@@ -1339,8 +1348,9 @@ blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
{ {
struct st_context *st = st_context(ctx); struct st_context *st = st_context(ctx);
struct pipe_context *pipe = st->pipe; struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct gl_pixelstore_attrib pack, unpack; struct gl_pixelstore_attrib pack, unpack;
GLint readX, readY, readW, readH; GLint readX, readY, readW, readH, drawX, drawY, drawW, drawH;
if (type == GL_COLOR && if (type == GL_COLOR &&
ctx->Pixel.ZoomX == 1.0 && ctx->Pixel.ZoomX == 1.0 &&
@@ -1354,11 +1364,9 @@ blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
!ctx->FragmentProgram.Enabled && !ctx->FragmentProgram.Enabled &&
!ctx->VertexProgram.Enabled && !ctx->VertexProgram.Enabled &&
!ctx->Shader.CurrentFragmentProgram && !ctx->Shader.CurrentFragmentProgram &&
st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) &&
ctx->DrawBuffer->_NumColorDrawBuffers == 1 && ctx->DrawBuffer->_NumColorDrawBuffers == 1 &&
!ctx->Query.CondRenderQuery) { !ctx->Query.CondRenderQuery) {
struct st_renderbuffer *rbRead, *rbDraw; struct st_renderbuffer *rbRead, *rbDraw;
GLint drawX, drawY;
/* /*
* Clip the read region against the src buffer bounds. * Clip the read region against the src buffer bounds.
@@ -1385,29 +1393,65 @@ blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
readX = readX - pack.SkipPixels + unpack.SkipPixels; readX = readX - pack.SkipPixels + unpack.SkipPixels;
readY = readY - pack.SkipRows + unpack.SkipRows; readY = readY - pack.SkipRows + unpack.SkipRows;
drawW = readW;
drawH = readH;
rbRead = st_get_color_read_renderbuffer(ctx); rbRead = st_get_color_read_renderbuffer(ctx);
rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
if ((rbRead != rbDraw || /* Flip src/dst position depending on the orientation of buffers. */
!regions_overlap(readX, readY, drawX, drawY, readW, readH)) && if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
rbRead->Base.Format == rbDraw->Base.Format) { readY = rbRead->Base.Height - readY;
struct pipe_box srcBox; readH = -readH;
}
/* flip src/dst position if needed */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { /* We can't flip the destination for pipe->blit, so we only adjust
/* both buffers will have the same orientation */ * its position and flip the source.
readY = ctx->ReadBuffer->Height - readY - readH; */
drawY = ctx->DrawBuffer->Height - drawY - readH; drawY = rbDraw->Base.Height - drawY - drawH;
readY += readH;
readH = -readH;
}
if (rbRead != rbDraw ||
!regions_overlap(readX, readY, readX + readW, readY + readH,
drawX, drawY, drawX + drawW, drawY + drawH)) {
struct pipe_blit_info blit;
memset(&blit, 0, sizeof(blit));
blit.src.resource = rbRead->texture;
blit.src.level = rbRead->rtt_level;
blit.src.format = rbRead->texture->format;
blit.src.box.x = readX;
blit.src.box.y = readY;
blit.src.box.z = rbRead->rtt_face + rbRead->rtt_slice;
blit.src.box.width = readW;
blit.src.box.height = readH;
blit.src.box.depth = 1;
blit.dst.resource = rbDraw->texture;
blit.dst.level = rbDraw->rtt_level;
blit.dst.format = rbDraw->texture->format;
blit.dst.box.x = drawX;
blit.dst.box.y = drawY;
blit.dst.box.z = rbDraw->rtt_face + rbDraw->rtt_slice;
blit.dst.box.width = drawW;
blit.dst.box.height = drawH;
blit.dst.box.depth = 1;
blit.mask = PIPE_MASK_RGBA;
blit.filter = PIPE_TEX_FILTER_NEAREST;
if (screen->is_format_supported(screen, blit.src.format,
blit.src.resource->target,
blit.src.resource->nr_samples,
PIPE_BIND_SAMPLER_VIEW) &&
screen->is_format_supported(screen, blit.dst.format,
blit.dst.resource->target,
blit.dst.resource->nr_samples,
PIPE_BIND_RENDER_TARGET)) {
pipe->blit(pipe, &blit);
return GL_TRUE;
} }
u_box_2d(readX, readY, readW, readH, &srcBox);
pipe->resource_copy_region(pipe,
rbDraw->texture,
rbDraw->rtt_level, drawX, drawY, 0,
rbRead->texture,
rbRead->rtt_level, &srcBox);
return GL_TRUE;
} }
} }