summaryrefslogtreecommitdiffstats
path: root/src/mesa/state_tracker
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2010-03-17 10:06:27 -0600
committerBrian Paul <[email protected]>2010-03-17 10:06:27 -0600
commit1bfc314596256b039df59f751d59dac82e3ceba1 (patch)
tree20846471c35be6d876ff647d624a9c49e10b91f8 /src/mesa/state_tracker
parentc4922276831528ad2b25acf816ef3f3dfe3211b7 (diff)
st/mesa: fix glCopyPixels bugs/crashes when src region need clipping
Use the _mesa_clip_readpixels() function to clip the src region against the buffer's bounds. Neatly, the resulting pixel unpack object's SkipPixels/SkipRows fields can be used to determine the position of the region in the destination texture. Fixes crash in progs/samples/copy.c and probably other cases.
Diffstat (limited to 'src/mesa/state_tracker')
-rw-r--r--src/mesa/state_tracker/st_cb_drawpixels.c90
1 files changed, 36 insertions, 54 deletions
diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c
index 43dc8d1b836..7c611cb4ec9 100644
--- a/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -938,39 +938,13 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
enum pipe_format srcFormat, texFormat;
int ptw, pth;
GLboolean invertTex = GL_FALSE;
+ GLint readX, readY, readW, readH;
+ struct gl_pixelstore_attrib unpack = ctx->DefaultPacking;
pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
st_validate_state(st);
- if (srcx < 0) {
- width -= -srcx;
- dstx += -srcx;
- srcx = 0;
- }
-
- if (srcy < 0) {
- height -= -srcy;
- dsty += -srcy;
- srcy = 0;
- }
-
- if (dstx < 0) {
- width -= -dstx;
- srcx += -dstx;
- dstx = 0;
- }
-
- if (dsty < 0) {
- height -= -dsty;
- srcy += -dsty;
- dsty = 0;
- }
-
- if (width < 0 || height < 0)
- return;
-
-
if (type == GL_STENCIL) {
/* can't use texturing to do stencil */
copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
@@ -1003,7 +977,7 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT,
PIPE_TEXTURE_2D,
PIPE_TEXTURE_USAGE_DEPTH_STENCIL);
- assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */
+ assert(texFormat != PIPE_FORMAT_NONE);
}
else {
/* default color format */
@@ -1013,20 +987,26 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
}
}
+ /* Invert src region if needed */
if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
srcy = ctx->ReadBuffer->Height - srcy - height;
-
- if (srcy < 0) {
- height -= -srcy;
- srcy = 0;
- }
-
- if (height < 0)
- return;
-
invertTex = !invertTex;
}
+ /* Clip the read region against the src buffer bounds.
+ * We'll still allocate a temporary buffer/texture for the original
+ * src region size but we'll only read the region which is on-screen.
+ * This may mean that we draw garbage pixels into the dest region, but
+ * that's expected.
+ */
+ readX = srcx;
+ readY = srcy;
+ readW = width;
+ readH = height;
+ _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &unpack);
+ readW = MAX2(0, readW);
+ readH = MAX2(0, readH);
+
/* Need to use POT texture? */
ptw = width;
pth = height;
@@ -1055,7 +1035,6 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
return;
/* Make temporary texture which is a copy of the src region.
- * We'll draw a quad with this texture to draw the dest image.
*/
if (srcFormat == texFormat) {
/* copy source framebuffer surface into mipmap/texture */
@@ -1066,16 +1045,16 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
PIPE_BUFFER_USAGE_GPU_WRITE );
if (pipe->surface_copy) {
pipe->surface_copy(pipe,
- psTex, /* dest */
- 0, 0, /* destx/y */
- psRead,
- srcx, srcy, width, height);
+ psTex, /* dest surf */
+ unpack.SkipPixels, unpack.SkipRows, /* dest pos */
+ psRead, /* src surf */
+ readX, readY, readW, readH); /* src region */
} else {
util_surface_copy(pipe, FALSE,
psTex,
- 0, 0,
+ unpack.SkipPixels, unpack.SkipRows,
psRead,
- srcx, srcy, width, height);
+ readX, readY, readW, readH);
}
if (0) {
@@ -1091,8 +1070,8 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
/* CPU-based fallback/conversion */
struct pipe_transfer *ptRead =
st_cond_flush_get_tex_transfer(st, rbRead->texture, 0, 0, 0,
- PIPE_TRANSFER_READ, srcx, srcy, width,
- height);
+ PIPE_TRANSFER_READ,
+ readX, readY, readW, readH);
struct pipe_transfer *ptTex;
enum pipe_transfer_usage transfer_usage;
@@ -1107,20 +1086,21 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
ptTex = st_cond_flush_get_tex_transfer(st, pt, 0, 0, 0, transfer_usage,
0, 0, width, height);
+ /* copy image from ptRead surface to ptTex surface */
if (type == GL_COLOR) {
/* alternate path using get/put_tile() */
GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
-
- pipe_get_tile_rgba(ptRead, 0, 0, width, height, buf);
- pipe_put_tile_rgba(ptTex, 0, 0, width, height, buf);
-
+ pipe_get_tile_rgba(ptRead, readX, readY, readW, readH, buf);
+ pipe_put_tile_rgba(ptTex, unpack.SkipPixels, unpack.SkipRows,
+ readW, readH, buf);
free(buf);
}
else {
/* GL_DEPTH */
GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint));
- pipe_get_tile_z(ptRead, 0, 0, width, height, buf);
- pipe_put_tile_z(ptTex, 0, 0, width, height, buf);
+ pipe_get_tile_z(ptRead, readX, readY, readW, readH, buf);
+ pipe_put_tile_z(ptTex, unpack.SkipPixels, unpack.SkipRows,
+ readW, readH, buf);
free(buf);
}
@@ -1128,7 +1108,9 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
screen->tex_transfer_destroy(ptTex);
}
- /* draw textured quad */
+ /* OK, the texture 'pt' contains the src image/pixels. Now draw a
+ * textured quad with that texture.
+ */
draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
pt,