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/intel_pixel_read.c | 117 +++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/mesa/drivers/dri/i965/intel_pixel_read.c b/src/mesa/drivers/dri/i965/intel_pixel_read.c index 5765027..16a04fb 100644 --- a/src/mesa/drivers/dri/i965/intel_pixel_read.c +++ b/src/mesa/drivers/dri/i965/intel_pixel_read.c @@ -196,6 +196,118 @@ intel_readpixels_tiled_memcpy(struct gl_context * ctx, ); } +static bool +intel_readpixels_userptr(struct gl_context * ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLvoid * pixels, + const struct gl_pixelstore_attrib *pack) +{ + struct brw_context *brw = brw_context(ctx); + + if (_mesa_is_bufferobj(pack->BufferObj)) + return false; + + struct gl_renderbuffer *rb = NULL; + switch (format) { + case GL_STENCIL_INDEX: + if (0) /* Stencils are W-tiled which is not supported by the blitter */ + rb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + break; + case GL_DEPTH_COMPONENT: + rb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + break; + case GL_DEPTH_STENCIL_EXT: + break; + default: + /* all other formats should be color formats */ + rb = ctx->ReadBuffer->_ColorReadBuffer; + break; + } + if (rb == NULL) + 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 (!_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_format_is_mesa_array_format(dst_format)) + dst_format = _mesa_format_from_array_format(dst_format); + + /* We can safely discard sRGB for the ReadPixels interface */ + 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: incompatible formats for blit (src=%s, dst=%s)\n", + __func__, + _mesa_get_format_name(src_format), + _mesa_get_format_name(dst_format)); + return false; + } + } + + bool dst_flip = false; + int dst_stride = _mesa_image_row_stride(pack, width, format, type); + int size = dst_stride * height; + + if (pack->Invert) { + dst_stride = -dst_stride; + dst_flip = true; + } + + int dst_offset = (GLintptr)pixels & 4095; + dst_offset += _mesa_image_offset(2, pack, width, height, + format, type, 0, 0, 0); + size += dst_offset; + size = ALIGN(size, 4096); + + 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, 1, + dst_stride, + 0); + if (dst) + ok = 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); + intel_miptree_release(&dst); + + brw_bo_map(dst_buffer, MAP_WRITE, PERF_DEBUG(brw, "ReadPixels")); + brw_bo_put(dst_buffer); + + return ok; +} + void intelReadPixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, @@ -244,6 +356,11 @@ intelReadPixels(struct gl_context * ctx, if(ok) return; + ok = intel_readpixels_userptr(ctx, x, y, width, height, + format, type, pixels, pack); + if(ok) + return; + /* glReadPixels() wont dirty the front buffer, so reset the dirty * flag after calling intel_prepare_render(). */ dirty = brw->front_buffer_dirty; -- 2.5.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev