While it is preferrable to use a fast manual detiling method for LLC (does not require synchronisation with a busy GPU and for accessing main memory both the CPU and GPU have the same bandwidth), if we don't have such a path then using the GPU to perform the blit is far preferable to a coherent mmapping.
Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk> --- src/mesa/drivers/dri/i965/Makefile.sources | 1 + src/mesa/drivers/dri/i965/intel_pixel.h | 7 + src/mesa/drivers/dri/i965/intel_pixel_pbo.c | 252 +++++++++++++++++++++++++++ src/mesa/drivers/dri/i965/intel_pixel_read.c | 38 ++-- 4 files changed, 280 insertions(+), 18 deletions(-) create mode 100644 src/mesa/drivers/dri/i965/intel_pixel_pbo.c diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/dri/i965/Makefile.sources index 425c883de8..a5550876cd 100644 --- a/src/mesa/drivers/dri/i965/Makefile.sources +++ b/src/mesa/drivers/dri/i965/Makefile.sources @@ -101,6 +101,7 @@ i965_FILES = \ intel_pixel_draw.c \ intel_pixel.h \ intel_pixel_read.c \ + intel_pixel_pbo.c \ intel_screen.c \ intel_screen.h \ intel_state.c \ diff --git a/src/mesa/drivers/dri/i965/intel_pixel.h b/src/mesa/drivers/dri/i965/intel_pixel.h index f5b931f5c1..c3d90d3297 100644 --- a/src/mesa/drivers/dri/i965/intel_pixel.h +++ b/src/mesa/drivers/dri/i965/intel_pixel.h @@ -58,4 +58,11 @@ void intelBitmap(struct gl_context * ctx, const struct gl_pixelstore_attrib *unpack, const GLubyte * pixels); +bool intel_readpixels_pbo(struct gl_context * ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels); + #endif diff --git a/src/mesa/drivers/dri/i965/intel_pixel_pbo.c b/src/mesa/drivers/dri/i965/intel_pixel_pbo.c new file mode 100644 index 0000000000..4e212ee92f --- /dev/null +++ b/src/mesa/drivers/dri/i965/intel_pixel_pbo.c @@ -0,0 +1,252 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "main/enums.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "main/fbobject.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/readpix.h" +#include "main/state.h" +#include "main/glformats.h" + +#include "brw_blorp.h" +#include "brw_context.h" +#include "intel_screen.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_buffer_objects.h" +#include "intel_buffers.h" +#include "intel_fbo.h" +#include "intel_mipmap_tree.h" +#include "intel_pixel.h" +#include "intel_buffer_objects.h" + +#define FILE_DEBUG_FLAG DEBUG_PIXEL + + +static int +get_texture_swizzle(const struct intel_renderbuffer *irb) +{ + if (irb->Base.Base._BaseFormat == GL_LUMINANCE || + irb->Base.Base._BaseFormat == GL_INTENSITY) + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE); + + if (irb->Base.Base._BaseFormat == GL_LUMINANCE_ALPHA) + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_W); + + if (irb->Base.Base._BaseFormat == GL_ALPHA) + return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_W); + + if (irb->Base.Base._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)); +} + +bool +intel_readpixels_pbo(struct gl_context * ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels) +{ + struct brw_context *brw = brw_context(ctx); + bool ok = false; + + struct gl_renderbuffer *rb; + switch (format) { + case GL_STENCIL_INDEX: + rb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_EXT: + rb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + break; + case GL_COLOR_INDEX: + rb = NULL; + break; + default: + /* all other formats should be color formats */ + rb = ctx->ReadBuffer->_ColorReadBuffer; + break; + } + if (!rb) + return false; + + if (pack->SwapBytes || pack->LsbFirst) { + DBG("%s: bad packing params\n", __func__); + return false; + } + + if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) { + DBG("%s: non-trivial conversion required\n", __func__); + return false; + } + + struct intel_renderbuffer *irb = intel_renderbuffer(rb); + struct intel_mipmap_tree *src = irb->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 bpp = _mesa_bytes_per_pixel(format, type); + pixels += pack->SkipRows * dst_stride + pack->SkipPixels * bpp; + int dst_size = dst_stride * (height - 1) + 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; + + struct intel_mipmap_tree *dst = + intel_miptree_create_for_bo(brw, + dst_buffer, + dst_format, + dst_offset, + width, height, 1, + dst_stride, + MIPTREE_LAYOUT_TILING_NONE | + MIPTREE_LAYOUT_DISABLE_AUX); + if (!dst) + goto err_dst_buffer; + + if (!rb->Name) { + dst_flip = !dst_flip; + y = rb->Height - y - height; + } + + assert(dst->surf.tiling == ISL_TILING_LINEAR); + if (!intel_miptree_blit(brw, + src, irb->mt_level, irb->mt_layer, x, y, false, + dst, 0, 0, 0, 0, dst_flip, + width, height, GL_COPY)) { + mesa_format src_format = irb->Base.Base.Format; + + /* blorp restrictions; see try_blorp_blit() */ + 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; + } + + brw_blorp_blit_miptrees(brw, + src, irb->mt_level, irb->mt_layer, + src_format, get_texture_swizzle(irb), + dst, 0, 0, dst_format, + x, y, x + width, y + height, + 0, 0, width, 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; +} diff --git a/src/mesa/drivers/dri/i965/intel_pixel_read.c b/src/mesa/drivers/dri/i965/intel_pixel_read.c index 56ae678573..398a8b686d 100644 --- a/src/mesa/drivers/dri/i965/intel_pixel_read.c +++ b/src/mesa/drivers/dri/i965/intel_pixel_read.c @@ -34,10 +34,12 @@ #include "main/glformats.h" #include "drivers/common/meta.h" +#include "brw_blorp.h" #include "brw_context.h" #include "intel_screen.h" #include "intel_batchbuffer.h" #include "intel_blit.h" +#include "intel_buffer_objects.h" #include "intel_buffers.h" #include "intel_fbo.h" #include "intel_mipmap_tree.h" @@ -205,16 +207,26 @@ intelReadPixels(struct gl_context * ctx, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid * pixels) { - bool ok; - struct brw_context *brw = brw_context(ctx); bool dirty; DBG("%s\n", __func__); - if (_mesa_is_bufferobj(pack->BufferObj)) { - if (_mesa_meta_pbo_GetTexSubImage(ctx, 2, NULL, x, y, 0, width, height, 1, - format, type, pixels, pack)) { + /* Reading pixels wont dirty the front buffer, so reset the dirty + * flag after calling intel_prepare_render(). */ + dirty = brw->front_buffer_dirty; + intel_prepare_render(brw); + brw->front_buffer_dirty = dirty; + + if (!_mesa_is_bufferobj(pack->BufferObj)) { + if (intel_readpixels_tiled_memcpy(ctx, x, y, width, height, + format, type, pixels, pack)) + return; + } + + if (intel_readpixels_pbo(ctx, x, y, width, height, + format, type, pack, pixels)) { + if (_mesa_is_bufferobj(pack->BufferObj)) { /* _mesa_meta_pbo_GetTexSubImage() implements PBO transfers by * binding the user-provided BO as a fake framebuffer and rendering * to it. This breaks the invariant of the GL that nothing is able @@ -236,22 +248,12 @@ intelReadPixels(struct gl_context * ctx, * flush here unconditionally. */ brw_emit_mi_flush(brw); - return; } - - perf_debug("%s: fallback to CPU mapping in PBO case\n", __func__); + return; } - /* Reading pixels wont dirty the front buffer, so reset the dirty - * flag after calling intel_prepare_render(). */ - dirty = brw->front_buffer_dirty; - intel_prepare_render(brw); - brw->front_buffer_dirty = dirty; - - ok = intel_readpixels_tiled_memcpy(ctx, x, y, width, height, - format, type, pixels, pack); - if(ok) - return; + perf_debug("%s: fallback to CPU mapping%s\n", __func__, + _mesa_is_bufferobj(pack->BufferObj) ? " for PBO" : ""); /* Update Mesa state before calling _mesa_readpixels(). * XXX this may not be needed since ReadPixels no longer uses the -- 2.13.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev