Similar to glReadPixels, using the GPU to blit back into the client's buffer is preferrable to using a coherent mmaping (but not manual detiling for several reasons).
Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk> --- src/mesa/drivers/dri/i965/intel_tex_image.c | 129 ++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c index d0a4555..2589d77 100644 --- a/src/mesa/drivers/dri/i965/intel_tex_image.c +++ b/src/mesa/drivers/dri/i965/intel_tex_image.c @@ -6,6 +6,7 @@ #include "main/bufferobj.h" #include "main/context.h" #include "main/formats.h" +#include "main/glformats.h" #include "main/image.h" #include "main/pbo.h" #include "main/renderbuffer.h" @@ -460,6 +461,124 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, ); } +static bool +intel_gettexsubimage_userptr(struct gl_context *ctx, + struct gl_texture_image *texImage, + GLint x, GLint y, GLint z, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLvoid * pixels, + const struct gl_pixelstore_attrib *pack) +{ + struct brw_context *brw = brw_context(ctx); + struct intel_texture_image *image = intel_texture_image(texImage); + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) + return false; + + if (ctx->_ImageTransferState) + return false; + + if (pack->SwapBytes || pack->LsbFirst) { + DBG("%s: bad packing params\n", __func__); + return false; + } + + /* Don't allow conversion between formats as the internal storage of the + * image (image->mt->format) may itself not match the original and + * allow false transforms. + */ + if (texImage->_BaseFormat != format) + return false; + + struct intel_mipmap_tree *src = image->mt; + if (format == GL_STENCIL_INDEX && src->stencil_mt) + src = src->stencil_mt; + + if (!_mesa_format_matches_format_and_type(src->format, format, type, 0)) { + mesa_format src_format = src->format; + mesa_format dst_format = _mesa_format_from_format_and_type(format, type); + + if (_mesa_get_format_base_format(dst_format) != texImage->_BaseFormat) + return false; + + if (_mesa_format_is_mesa_array_format(dst_format)) + dst_format = _mesa_format_from_array_format(dst_format); + + src_format = _mesa_get_srgb_format_linear(src_format); + dst_format = _mesa_get_srgb_format_linear(dst_format); + + if (!intel_miptree_blit_compatible_formats(src_format, dst_format)) { + DBG("%s: bad format for blit\n", __func__); + return false; + } + } + + int src_level = texImage->Level + texImage->TexObject->MinLevel; + int src_slice = texImage->Face + texImage->TexObject->MinLayer; + + bool dst_flip = false; + int dst_stride = _mesa_image_row_stride(pack, width, format, type); + int image_height = pack->ImageHeight == 0 ? height : pack->ImageHeight; + int full_height = image_height * (depth - 1) + height; + int size = dst_stride * full_height; + + if (pack->Invert) { + dst_stride = -dst_stride; + dst_flip = true; + } + + int dst_offset = (GLintptr)pixels & 4095; + dst_offset += _mesa_image_offset(3, pack, width, height, + format, type, 0, 0, 0); + size += dst_offset; + size = ALIGN(size, 4096); + + if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { + assert(depth == 1); + assert(z == 0); + depth = height; + height = 1; + image_height = 1; + z = y; + y = 0; + } + + brw_bo *dst_buffer = + brw_bo_create_userptr(&brw->batch, "readpixels", + (void *)((GLintptr)pixels & ~4095), + size, 0); + if (dst_buffer == NULL) + return false; + + bool ok = false; + struct intel_mipmap_tree *dst = + intel_miptree_create_for_bo(brw, + dst_buffer, + src->format, + dst_offset, + width, height, depth, + dst_stride, + 0); + if (dst) { + do { + ok = intel_miptree_blit(brw, + src, src_level, src_slice + z, + x, y, false, + dst, 0, 0, + 0, z * image_height, dst_flip, + width, height, GL_COPY); + z++; + } while (--depth && ok); + } + intel_miptree_release(&dst); + + brw_bo_map(dst_buffer, MAP_WRITE, PERF_DEBUG(brw, "ReadPixels")); + brw_bo_put(dst_buffer); + + return ok; +} + static void intel_get_tex_sub_image(struct gl_context *ctx, GLint xoffset, GLint yoffset, GLint zoffset, @@ -496,6 +615,16 @@ intel_get_tex_sub_image(struct gl_context *ctx, if(ok) return; + ok = intel_gettexsubimage_userptr(ctx, texImage, + 0, 0, 0, + texImage->Width, + texImage->Height, + texImage->Depth, + format, type, pixels, &ctx->Pack); + + if(ok) + return; + _mesa_meta_GetTexSubImage(ctx, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels, texImage); -- 2.5.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev