Most drivers have been creating fake/wrapper renderbuffers when a texture image is attached to an FBO. But that's not a requirement of core Mesa.
So an FBO attachment that points into a texture may not have a (fake) renderbuffer. This caused the new glReadPixels code to fail when reading from a buffer that's actually a texture. Now, we check the attachment point to see if it's a real renderbuffer or a texture image and call the corresponding MapRenderbuffer() or MapTextureImage() function. This fixes a bunch of piglit fbo failures when using the non-DRI swrast driver. --- src/mesa/swrast/s_readpix.c | 242 ++++++++++++++++++++++++++++++------------- 1 files changed, 171 insertions(+), 71 deletions(-) diff --git a/src/mesa/swrast/s_readpix.c b/src/mesa/swrast/s_readpix.c index 50422db..45d07d2 100644 --- a/src/mesa/swrast/s_readpix.c +++ b/src/mesa/swrast/s_readpix.c @@ -25,6 +25,7 @@ #include "main/glheader.h" #include "main/colormac.h" +#include "main/fbobject.h" #include "main/feedback.h" #include "main/formats.h" #include "main/format_unpack.h" @@ -40,6 +41,95 @@ #include "s_span.h" #include "s_stencil.h" + +/** + * Map a framebuffer attachment. An attachment may either be a renderbuffer + * or a texture image. Check the attachment type and map the corresponding + * image. + * Note: This might be moved out of swrast someday. + */ +static void +map_attachment(struct gl_context *ctx, + struct gl_renderbuffer_attachment *att, + GLuint x, GLuint y, GLuint w, GLuint h, + GLbitfield mode, + GLubyte **mapOut, GLint *rowStrideOut) +{ + if (att->Type == GL_TEXTURE) { + struct gl_texture_image *texImage = _mesa_get_attachment_teximage(att); + assert(texImage); + ctx->Driver.MapTextureImage(ctx, texImage, + att->Zoffset, + x, y, w, h, mode, + mapOut, rowStrideOut); + } + else if (att->Type == GL_RENDERBUFFER) { + assert(att->Renderbuffer); + ctx->Driver.MapRenderbuffer(ctx, att->Renderbuffer, + x, y, w, h, mode, + mapOut, rowStrideOut); + } + else { + *mapOut = NULL; + *rowStrideOut = 0; + _mesa_warning(NULL, "invalid attachment in map_attachment()"); + } +} + + +/** + * Unmap a framebuffer attachment. + * Note: This might be moved out of swrast someday. + */ +static void +unmap_attachment(struct gl_context *ctx, + struct gl_renderbuffer_attachment *att) +{ + if (att->Type == GL_TEXTURE) { + struct gl_texture_image *texImage = _mesa_get_attachment_teximage(att); + assert(texImage); + ctx->Driver.UnmapTextureImage(ctx, texImage, att->Zoffset); + } + else if (att->Type == GL_RENDERBUFFER) { + assert(att->Renderbuffer); + ctx->Driver.UnmapRenderbuffer(ctx, att->Renderbuffer); + } + else { + _mesa_warning(NULL, "invalid attachment in unmap_attachment()"); + } +} + + +/** + * Get the format of a framebuffer attachment, which may either be a + * renderbuffer or texture image. We shouldn't get here if there's no + * attachment at all. + * Note: This might be moved out of swrast someday. + */ +static gl_format +get_attachment_format(const struct gl_renderbuffer_attachment *att) +{ + if (att->Type == GL_TEXTURE) { + const struct gl_texture_image *texImage = + _mesa_get_attachment_teximage_const(att); + assert(texImage); + if (texImage) + return texImage->TexFormat; + } + else if (att->Type == GL_RENDERBUFFER) { + assert(att->Renderbuffer); + if (att->Renderbuffer) + return att->Renderbuffer->Format; + } + else { + _mesa_warning(NULL, "invalid attachment in get_attachment_format()"); + } + /* we should normally never get here */ + return MESA_FORMAT_NONE; +} + + + /** * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the * mapping. @@ -52,7 +142,8 @@ fast_read_depth_pixels( struct gl_context *ctx, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer_attachment *depthAtt = &fb->Attachment[BUFFER_DEPTH]; + gl_format depthFormat = get_attachment_format(depthAtt); GLubyte *map, *dst; int stride, dstStride, j; @@ -62,15 +153,15 @@ fast_read_depth_pixels( struct gl_context *ctx, if (packing->SwapBytes) return GL_FALSE; - if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_INT) + if (_mesa_get_format_datatype(depthFormat) != GL_UNSIGNED_INT) return GL_FALSE; - if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) || + if (!((type == GL_UNSIGNED_SHORT && depthFormat == MESA_FORMAT_Z16) || type == GL_UNSIGNED_INT)) return GL_FALSE; - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); + map_attachment(ctx, depthAtt, x, y, width, height, GL_MAP_READ_BIT, + &map, &stride); dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, @@ -78,16 +169,17 @@ fast_read_depth_pixels( struct gl_context *ctx, for (j = 0; j < height; j++) { if (type == GL_UNSIGNED_INT) { - _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst); + _mesa_unpack_uint_z_row(depthFormat, width, map, (GLuint *)dst); } else { - ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16); + ASSERT(type == GL_UNSIGNED_SHORT && depthFormat == MESA_FORMAT_Z16); memcpy(dst, map, width * 2); } map += stride; dst += dstStride; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); + + unmap_attachment(ctx, depthAtt); return GL_TRUE; } @@ -103,19 +195,12 @@ read_depth_pixels( struct gl_context *ctx, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer_attachment *depthAtt = &fb->Attachment[BUFFER_DEPTH]; + gl_format depthFormat = get_attachment_format(depthAtt); GLint j; GLubyte *dst, *map; int dstStride, stride; - if (!rb) - return; - - /* clipping should have been done already */ - ASSERT(x >= 0); - ASSERT(y >= 0); - ASSERT(x + width <= (GLint) rb->Width); - ASSERT(y + height <= (GLint) rb->Height); /* width should never be > MAX_WIDTH since we did clipping earlier */ ASSERT(width <= MAX_WIDTH); @@ -126,20 +211,20 @@ read_depth_pixels( struct gl_context *ctx, dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_DEPTH_COMPONENT, type, 0, 0); - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); + map_attachment(ctx, depthAtt, x, y, width, height, GL_MAP_READ_BIT, + &map, &stride); /* General case (slower) */ for (j = 0; j < height; j++, y++) { GLfloat depthValues[MAX_WIDTH]; - _mesa_unpack_float_z_row(rb->Format, width, map, depthValues); + _mesa_unpack_float_z_row(depthFormat, width, map, depthValues); _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing); dst += dstStride; map += stride; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); + unmap_attachment(ctx, depthAtt); } @@ -154,26 +239,24 @@ read_stencil_pixels( struct gl_context *ctx, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct gl_renderbuffer_attachment *stencilAtt = &fb->Attachment[BUFFER_STENCIL]; + gl_format stencilFormat = get_attachment_format(stencilAtt); GLint j; GLubyte *map; GLint stride; - if (!rb) - return; - /* width should never be > MAX_WIDTH since we did clipping earlier */ ASSERT(width <= MAX_WIDTH); - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); + map_attachment(ctx, stencilAtt, x, y, width, height, GL_MAP_READ_BIT, + &map, &stride); /* process image row by row */ for (j = 0; j < height; j++) { GLvoid *dest; GLstencil stencil[MAX_WIDTH]; - _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil); + _mesa_unpack_ubyte_stencil_row(stencilFormat, width, map, stencil); dest = _mesa_image_address2d(packing, pixels, width, height, GL_STENCIL_INDEX, type, j, 0); @@ -182,7 +265,7 @@ read_stencil_pixels( struct gl_context *ctx, map += stride; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); + unmap_attachment(ctx, stencilAtt); } static GLboolean @@ -194,11 +277,14 @@ fast_read_rgba_pixels_memcpy( struct gl_context *ctx, const struct gl_pixelstore_attrib *packing, GLbitfield transferOps ) { - struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer_attachment *colorAtt = + &fb->Attachment[fb->_ColorReadBufferIndex]; + gl_format colorFormat = get_attachment_format(colorAtt); GLubyte *dst, *map; int dstStride, stride, j, texelBytes; - if (!_mesa_format_matches_format_and_type(rb->Format, format, type)) + if (!_mesa_format_matches_format_and_type(colorFormat, format, type)) return GL_FALSE; /* check for things we can't handle here */ @@ -211,17 +297,18 @@ fast_read_rgba_pixels_memcpy( struct gl_context *ctx, dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); - texelBytes = _mesa_get_format_bytes(rb->Format); + map_attachment(ctx, colorAtt, x, y, width, height, GL_MAP_READ_BIT, + &map, &stride); + + texelBytes = _mesa_get_format_bytes(colorFormat); for (j = 0; j < height; j++) { memcpy(dst, map, width * texelBytes); dst += dstStride; map += stride; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); + unmap_attachment(ctx, colorAtt); return GL_TRUE; } @@ -235,7 +322,10 @@ slow_read_rgba_pixels( struct gl_context *ctx, const struct gl_pixelstore_attrib *packing, GLbitfield transferOps ) { - struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer_attachment *colorAtt = + &fb->Attachment[fb->_ColorReadBufferIndex]; + gl_format colorFormat = get_attachment_format(colorAtt); GLfloat rgba[MAX_WIDTH][4]; GLubyte *dst, *map; int dstStride, stride, j; @@ -244,12 +334,13 @@ slow_read_rgba_pixels( struct gl_context *ctx, dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); + map_attachment(ctx, colorAtt, x, y, width, height, GL_MAP_READ_BIT, + &map, &stride); + + colorFormat = _mesa_get_srgb_format_linear(colorFormat); for (j = 0; j < height; j++) { - _mesa_unpack_rgba_row(_mesa_get_srgb_format_linear(rb->Format), - width, map, rgba); + _mesa_unpack_rgba_row(colorFormat, width, map, rgba); _mesa_pack_rgba_span_float(ctx, width, rgba, format, type, dst, packing, transferOps); @@ -257,7 +348,7 @@ slow_read_rgba_pixels( struct gl_context *ctx, map += stride; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); + unmap_attachment(ctx, colorAtt); return GL_TRUE; } @@ -308,29 +399,34 @@ fast_read_depth_stencil_pixels(struct gl_context *ctx, GLubyte *dst, int dstStride) { struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; - struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct gl_renderbuffer_attachment *depthAtt = &fb->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *stencilAtt = &fb->Attachment[BUFFER_STENCIL]; + gl_format depthFormat = get_attachment_format(depthAtt); GLubyte *map; int stride, i; - if (rb != stencilRb) + /* The attachments must either share depth/stencil renderbuffers + * or texture objects. + */ + if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer || + depthAtt->Texture != stencilAtt->Texture) return GL_FALSE; - if (rb->Format != MESA_FORMAT_Z24_S8 && - rb->Format != MESA_FORMAT_S8_Z24) + if (depthFormat != MESA_FORMAT_Z24_S8 && + depthFormat != MESA_FORMAT_S8_Z24) return GL_FALSE; - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); + map_attachment(ctx, depthAtt, x, y, width, height, GL_MAP_READ_BIT, + &map, &stride); for (i = 0; i < height; i++) { - _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width, + _mesa_unpack_uint_24_8_depth_stencil_row(depthFormat, width, map, (GLuint *)dst); map += stride; dst += dstStride; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); + unmap_attachment(ctx, depthAtt); return GL_TRUE; } @@ -348,24 +444,26 @@ fast_read_depth_stencil_pixels_separate(struct gl_context *ctx, uint32_t *dst, int dstStride) { struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; - struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct gl_renderbuffer_attachment *depthAtt = &fb->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *stencilAtt = &fb->Attachment[BUFFER_STENCIL]; + gl_format depthFormat = get_attachment_format(depthAtt); + gl_format stencilFormat = get_attachment_format(stencilAtt); GLubyte *depthMap, *stencilMap; int depthStride, stencilStride, i, j; - if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_INT) + if (_mesa_get_format_datatype(depthFormat) != GL_UNSIGNED_INT) return GL_FALSE; - ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, - GL_MAP_READ_BIT, &depthMap, &depthStride); - ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, - GL_MAP_READ_BIT, &stencilMap, &stencilStride); + map_attachment(ctx, depthAtt, x, y, width, height, GL_MAP_READ_BIT, + &depthMap, &depthStride); + map_attachment(ctx, stencilAtt, x, y, width, height, GL_MAP_READ_BIT, + &stencilMap, &stencilStride); for (j = 0; j < height; j++) { GLstencil stencilVals[MAX_WIDTH]; - _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst); - _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, + _mesa_unpack_uint_z_row(depthFormat, width, depthMap, dst); + _mesa_unpack_ubyte_stencil_row(stencilFormat, width, stencilMap, stencilVals); for (i = 0; i < width; i++) { @@ -377,8 +475,8 @@ fast_read_depth_stencil_pixels_separate(struct gl_context *ctx, dst += dstStride / 4; } - ctx->Driver.UnmapRenderbuffer(ctx, depthRb); - ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); + unmap_attachment(ctx, depthAtt); + unmap_attachment(ctx, stencilAtt); return GL_TRUE; } @@ -392,22 +490,24 @@ slow_read_depth_stencil_pixels_separate(struct gl_context *ctx, GLubyte *dst, int dstStride) { struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; - struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct gl_renderbuffer_attachment *depthAtt = &fb->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *stencilAtt = &fb->Attachment[BUFFER_STENCIL]; + gl_format depthFormat = get_attachment_format(depthAtt); + gl_format stencilFormat = get_attachment_format(stencilAtt); GLubyte *depthMap, *stencilMap; int depthStride, stencilStride, j; - ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, - GL_MAP_READ_BIT, &depthMap, &depthStride); - ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, - GL_MAP_READ_BIT, &stencilMap, &stencilStride); + map_attachment(ctx, depthAtt, x, y, width, height, GL_MAP_READ_BIT, + &depthMap, &depthStride); + map_attachment(ctx, stencilAtt, x, y, width, height, GL_MAP_READ_BIT, + &stencilMap, &stencilStride); for (j = 0; j < height; j++) { GLstencil stencilVals[MAX_WIDTH]; GLfloat depthVals[MAX_WIDTH]; - _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals); - _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, + _mesa_unpack_float_z_row(depthFormat, width, depthMap, depthVals); + _mesa_unpack_ubyte_stencil_row(stencilFormat, width, stencilMap, stencilVals); _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst, @@ -418,8 +518,8 @@ slow_read_depth_stencil_pixels_separate(struct gl_context *ctx, dst += dstStride; } - ctx->Driver.UnmapRenderbuffer(ctx, depthRb); - ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); + unmap_attachment(ctx, depthAtt); + unmap_attachment(ctx, stencilAtt); } -- 1.7.3.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev