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 | 368 ++++++++++++++++++++++++++-- 1 file changed, 353 insertions(+), 15 deletions(-) diff --git a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c index a1d14ed02b..334e323d74 100644 --- a/src/mesa/drivers/dri/i965/intel_tex_image.c +++ b/src/mesa/drivers/dri/i965/intel_tex_image.c @@ -8,6 +8,7 @@ #include "main/glformats.h" #include "main/image.h" #include "main/pbo.h" +#include "main/readpix.h" #include "main/renderbuffer.h" #include "main/texcompress.h" #include "main/texgetimage.h" @@ -25,6 +26,7 @@ #include "intel_fbo.h" #include "intel_image.h" #include "intel_tiled_memcpy.h" +#include "brw_blorp.h" #include "brw_context.h" #define FILE_DEBUG_FLAG DEBUG_TEXTURE @@ -493,6 +495,343 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, return true; } +#if 0 +static bool +intel_gettexsubimage_userptr(struct gl_context *ctx, + GLint x, GLint y, GLint z, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLvoid * pixels, + struct gl_texture_image *texImage) +{ + struct brw_context *brw = brw_context(ctx); + struct intel_texture_image *image = intel_texture_image(texImage); + const struct gl_pixelstore_attrib *pack = &ctx->Pack; + + if (_mesa_is_bufferobj(pack->BufferObj)) + 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 != + _mesa_get_format_base_format(texImage->TexFormat)) + return false; + + struct intel_mipmap_tree *src = image->mt; + if (format == GL_STENCIL_INDEX && src->stencil_mt) + src = src->stencil_mt; + + mesa_format src_format = src->format; + if (!brw->screen->mesa_format_supports_texture[src_format]) + return false; + + mesa_format dst_format = _mesa_format_from_format_and_type(format, type); + if (_mesa_format_is_mesa_array_format(dst_format)) + dst_format = _mesa_format_from_array_format(dst_format); + if (!brw->mesa_format_supports_render[dst_format]) { + dst_format= _mesa_format_fallback_rgbx_to_rgba(dst_format); + if (!brw->mesa_format_supports_render[dst_format]) + return false; + } + + switch (format) { + case GL_DEPTH_STENCIL_EXT: + case GL_STENCIL_INDEX: + if (src_format != dst_format) /* XXX blorp! */ + return false; + default: + break; + } + + const int dimensions = + _mesa_get_texture_dimensions(texImage->TexObject->Target); + pixels = _mesa_image_address(dimensions, pack, pixels, width, height, + format, type, 0, 0, 0); + int size = _mesa_image_offset(dimensions, pack, width, height, + format, type, depth-1, height-1, width); + + int dst_offset = (GLintptr)pixels & 4095; + size = 2*ALIGN(size + dst_offset, 4096); + + struct brw_bo *dst_buffer = + brw_bo_alloc_userptr(brw->bufmgr, "getteximage(userptr)", + (void *)((GLintptr)pixels & ~4095), + size, 0); + if (!dst_buffer) + return false; + + bool dst_flip = false; + int dst_stride = _mesa_image_row_stride(pack, width, format, type); + if (pack->Invert) { + dst_stride = -dst_stride; + dst_flip = true; + } + + int image_height = pack->ImageHeight == 0 ? height : pack->ImageHeight; + 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; + } + + struct intel_mipmap_tree *dst = + intel_miptree_create_for_bo(brw, + dst_buffer, + dst_format, + dst_offset, + width, image_height * depth, 1, + dst_stride, + MIPTREE_LAYOUT_DISABLE_AUX); + if (!dst) { + brw_bo_unreference(dst_buffer); + return false; + } + + int src_level = texImage->Level + texImage->TexObject->MinLevel; + int src_slice = texImage->Face + texImage->TexObject->MinLayer + z; + + bool blit = intel_miptree_blit_compatible_formats(src_format, dst_format); + for (z = 0; depth--; z++) { + if (!(blit && 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))) + brw_blorp_blit_miptrees(brw, + src, src_level, src_slice + z, + src_format, SWIZZLE_XYZW, + dst, 0, 0, dst_format, + x, y, width, height, + 0, z * image_height, width, height, + GL_NEAREST, false, dst_flip, + false, false); + } + intel_miptree_release(&dst); + + intel_batchbuffer_flush(brw); + brw_bo_wait_rendering(dst_buffer); + brw_bo_unreference(dst_buffer); + + return true; +} +#endif + +static int +get_texture_swizzle(const struct gl_texture_image *tex) +{ + if (tex->_BaseFormat == GL_LUMINANCE || + tex->_BaseFormat == GL_INTENSITY) + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE); + + if (tex->_BaseFormat == GL_LUMINANCE_ALPHA) + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_W); + + if (tex->_BaseFormat == GL_ALPHA) + return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_W); + + if (tex->_BaseFormat == GL_RGB) + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ONE); + + return SWIZZLE_XYZW; +} + +static bool +need_signed_unsigned_int_conversion(mesa_format mesaFormat, + GLenum format, GLenum type) +{ + const GLenum mesaFormatType = _mesa_get_format_datatype(mesaFormat); + const bool is_format_integer = _mesa_is_enum_format_integer(format); + return (mesaFormatType == GL_INT && + is_format_integer && + (type == GL_UNSIGNED_INT || + type == GL_UNSIGNED_SHORT || + type == GL_UNSIGNED_BYTE)) || + (mesaFormatType == GL_UNSIGNED_INT && + is_format_integer && + (type == GL_INT || + type == GL_SHORT || + type == GL_BYTE)); +} + +static bool +intel_gettexsubimage_pbo(struct gl_context *ctx, + GLint x, GLint y, GLint z, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLvoid *pixels, + struct gl_texture_image *tex) +{ + struct brw_context *brw = brw_context(ctx); + struct intel_texture_image *image = intel_texture_image(tex); + const struct gl_pixelstore_attrib *pack = &ctx->Pack; + bool ok = false; + + if (ctx->_ImageTransferState) + return false; + + if (pack->SwapBytes || pack->LsbFirst) { + DBG("%s: bad packing params\n", __func__); + return false; + } + + if (format == GL_COLOR_INDEX) + return false; + + if (_mesa_need_rgb_to_luminance_conversion(tex->_BaseFormat, format)) + return false; + + struct intel_mipmap_tree *src = image->mt; + if (format == GL_STENCIL_INDEX && src->stencil_mt) + src = src->stencil_mt; + + if (need_signed_unsigned_int_conversion(src->format, format, type)) + return false; + + mesa_format dst_format = _mesa_format_from_format_and_type(format, type); + if (_mesa_format_is_mesa_array_format(dst_format)) + dst_format = _mesa_format_from_array_format(dst_format); + dst_format = _mesa_get_srgb_format_linear(dst_format); + + if (!brw->mesa_format_supports_render[dst_format]) { + dst_format = _mesa_format_fallback_rgbx_to_rgba(dst_format); + if (!brw->mesa_format_supports_render[dst_format]) + return false; + } + + bool dst_flip = false; + int dst_stride = _mesa_image_row_stride(pack, width, format, type); + if (pack->Invert) { + dst_stride = -dst_stride; + dst_flip = true; + } + + int image_height = pack->ImageHeight == 0 ? height : pack->ImageHeight; + int full_height = image_height * (depth - 1) + height; + int bpp = _mesa_bytes_per_pixel(format, type); + pixels += (pack->SkipImages * image_height + pack->SkipRows) * dst_stride; + pixels += pack->SkipPixels * bpp; + int dst_size = (full_height - 1) * dst_stride + width * bpp; + + struct brw_bo *dst_buffer; + int dst_offset; + if (_mesa_is_bufferobj(pack->BufferObj)) { + dst_offset = (GLintptr)pixels; + if ((dst_offset | dst_stride) % bpp) + return false; + + dst_buffer = intel_bufferobj_buffer(brw, + intel_buffer_object(pack->BufferObj), + dst_offset, + dst_size, + false); + } else { + dst_offset = (GLintptr)pixels & 4095; + if ((dst_offset | dst_stride) % bpp) + return false; + + dst_buffer = brw_bo_alloc_userptr(brw->bufmgr, "readpixels", + (void *)((GLintptr)pixels & -4096), + ALIGN(dst_size + dst_offset, 4096), 0); + } + if (!dst_buffer) + return false; + + if (tex->TexObject->Target == GL_TEXTURE_1D_ARRAY) { + assert(depth == 1); + assert(z == 0); + depth = height; + height = 1; + image_height = 1; + z = y; + y = 0; + } + + struct intel_mipmap_tree *dst = + intel_miptree_create_for_bo(brw, + dst_buffer, + dst_format, + dst_offset, + width, full_height, 1, + dst_stride, + MIPTREE_LAYOUT_TILING_NONE | + MIPTREE_LAYOUT_DISABLE_AUX); + if (!dst) + goto err_dst_buffer; + + assert(dst->surf.tiling == ISL_TILING_LINEAR); + + int src_level = tex->Level + tex->TexObject->MinLevel; + int src_slice = tex->Face + tex->TexObject->MinLayer + z; + + /* blorp restrictions; see try_blorp_blit() */ + mesa_format src_format = src->format; + switch (format) { + case GL_STENCIL_INDEX: + if (src_format != dst_format) + goto err_dst_mt; + + /* fallthrough */ + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_EXT: + if ((src_format == MESA_FORMAT_Z24_UNORM_X8_UINT) != + (dst_format == MESA_FORMAT_Z24_UNORM_X8_UINT)) + goto err_dst_mt; + + if (_mesa_get_format_base_format(src_format) == GL_DEPTH_STENCIL || + _mesa_get_format_base_format(dst_format) == GL_DEPTH_STENCIL) + goto err_dst_mt; + + src_format = MESA_FORMAT_NONE; + dst_format = MESA_FORMAT_NONE; + break; + + default: + break; + } + + for (z = 0; depth--; z++) { + if (!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)) { + brw_blorp_blit_miptrees(brw, + src, src_level, src_slice + z, + src_format, get_texture_swizzle(tex), + dst, 0, 0, dst_format, + x, y, x + width, y + height, + 0, z * image_height, width, z * image_height + height, + GL_NEAREST, false, dst_flip, + false, false); + } + } + if (!_mesa_is_bufferobj(pack->BufferObj)) { + intel_batchbuffer_flush(brw); + brw_bo_wait_rendering(dst_buffer); + } + + ok = true; +err_dst_mt: + intel_miptree_release(&dst); +err_dst_buffer: + if (!_mesa_is_bufferobj(pack->BufferObj)) + brw_bo_unreference(dst_buffer); + return ok; +} + static void intel_get_tex_sub_image(struct gl_context *ctx, GLint xoffset, GLint yoffset, GLint zoffset, @@ -501,33 +840,32 @@ intel_get_tex_sub_image(struct gl_context *ctx, struct gl_texture_image *texImage) { struct brw_context *brw = brw_context(ctx); - bool ok; DBG("%s\n", __func__); - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - if (_mesa_meta_pbo_GetTexSubImage(ctx, 3, texImage, - xoffset, yoffset, zoffset, - width, height, depth, format, type, - pixels, &ctx->Pack)) { + if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + if (intel_gettexsubimage_tiled_memcpy(ctx, texImage, xoffset, yoffset, + width, height, + format, type, pixels, &ctx->Pack)) + return; + } + + if (intel_gettexsubimage_pbo(ctx, xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, texImage)) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* Flush to guarantee coherency between the render cache and other * caches the PBO could potentially be bound to after this point. * See the related comment in intelReadPixels() for a more detailed * explanation. */ brw_emit_mi_flush(brw); - return; } - - perf_debug("%s: fallback to CPU mapping in PBO case\n", __func__); + return; } - ok = intel_gettexsubimage_tiled_memcpy(ctx, texImage, xoffset, yoffset, - width, height, - format, type, pixels, &ctx->Pack); - - if(ok) - return; + perf_debug("%s: fallback to CPU mapping%s\n", __func__, + _mesa_is_bufferobj(ctx->Pack.BufferObj) ? " for PBO" : ""); _mesa_meta_GetTexSubImage(ctx, xoffset, yoffset, zoffset, width, height, depth, -- 2.13.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev