<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Oct 10, 2017 at 3:14 PM, Kenneth Graunke <span dir="ltr"><<a href="mailto:kenneth@whitecape.org" target="_blank">kenneth@whitecape.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Topi Pohjolainen <<a href="mailto:topi.pohjolainen@intel.com">topi.pohjolainen@intel.com</a>><br>
<br>
v2:<br>
- Fix return value (s/MESA_FORMAT_NONE/false/) (Anuj)<br>
- Move _mesa_tex_format_from_format_<wbr>and_type() just<br>
in the end avoiding additional if-block (Anuj)<br>
- Explain better the array alignment restriction (Anuj)<br>
- Do not bail out in case of gl_pixelstore_attrib::<wbr>ImageHeight,<br>
it is handled by _mesa_image_offset() automatically (Ken).<br>
- Support 1D_ARRAY by flipping depth, width and y, z (Ken).<br>
<br>
v3:<br>
- Contrary to v2, do not try to handle<br>
gl_pixelstore_attrib::<wbr>ImageHeight. Currently there are no<br>
tests in piglit or cts for it. One could possibly copy or<br>
modify tests/texturing/texsubimage.c. There, however, seems<br>
to be number of corner cases to consider. Moreover, current<br>
meta path applies the packing height for both source and<br>
targets when determining the offset. This would probably<br>
require re-visiting also.<br>
<br>
v4: Rebased on top of merged drm-bacon<br>
<br>
v5 (Jason Ekstrand):<br>
- Move to brw_blorp.c<br>
- Significant refactoring<br>
- Fixed 1-D array textures<br>
- Simplified handling of PBOs vs. CPU data.<br>
- Handle gl_pixelstore_attrib::<wbr>ImageHeight. It turns out there are<br>
piglit tests that cover this. The original version was failing them<br>
because of an error in the way it handled 1-D array textures.<br>
- Add support for texture download<br>
<br>
v6 (Ken): Rebase fixes:<br>
- Use intel_miptree_check_level_<wbr>layer instead of deleted fields<br>
- Update for mesa_format_supports_render[] rename.<br>
- Pass 'false' (read-only) to intel_bufferobj_buffer<br></blockquote><div><br></div><div>Why pass false instead of !read_only?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Cc: Topi Pohjolainen <<a href="mailto:topi.pohjolainen@intel.com">topi.pohjolainen@intel.com</a>><br>
Cc: Kenneth Graunke <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>><br>
Signed-off-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
---<br>
src/mesa/drivers/dri/i965/brw_<wbr>blorp.c | 331 ++++++++++++++++++++++++++++++<wbr>++++<br>
src/mesa/drivers/dri/i965/brw_<wbr>blorp.h | 20 ++<br>
2 files changed, 351 insertions(+)<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c<br>
index 835dbd2af36..5f3e437be3c 100644<br>
--- a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c<br>
+++ b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.c<br>
@@ -24,7 +24,10 @@<br>
#include "main/context.h"<br>
#include "main/teximage.h"<br>
#include "main/blend.h"<br>
+#include "main/bufferobj.h"<br>
+#include "main/enums.h"<br>
#include "main/fbobject.h"<br>
+#include "main/image.h"<br>
#include "main/renderbuffer.h"<br>
#include "main/glformats.h"<br>
<br>
@@ -33,6 +36,7 @@<br>
#include "brw_defines.h"<br>
#include "brw_meta_util.h"<br>
#include "brw_state.h"<br>
+#include "intel_buffer_objects.h"<br>
#include "intel_fbo.h"<br>
#include "common/gen_debug.h"<br>
<br>
@@ -754,6 +758,333 @@ brw_blorp_framebuffer(struct brw_context *brw,<br>
return mask;<br>
}<br>
<br>
+static struct brw_bo *<br>
+blorp_get_client_bo(struct brw_context *brw,<br>
+ unsigned w, unsigned h, unsigned d,<br>
+ GLenum target, GLenum format, GLenum type,<br>
+ const void *pixels,<br>
+ const struct gl_pixelstore_attrib *packing,<br>
+ uint32_t *offset_out, uint32_t *row_stride_out,<br>
+ uint32_t *image_stride_out, bool read_only)<br>
+{<br>
+ /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */<br>
+ const GLuint dims = _mesa_get_texture_dimensions(<wbr>target);<br>
+ const uint32_t first_pixel = _mesa_image_offset(dims, packing, w, h,<br>
+ format, type, 0, 0, 0);<br>
+ const uint32_t last_pixel = _mesa_image_offset(dims, packing, w, h,<br>
+ format, type,<br>
+ d - 1, h - 1, w);<br>
+ const uint32_t stride = _mesa_image_row_stride(<wbr>packing, w, format, type);<br>
+ const uint32_t cpp = _mesa_bytes_per_pixel(format, type);<br>
+ const uint32_t size = last_pixel - first_pixel;<br>
+<br>
+ *row_stride_out = stride;<br>
+ *image_stride_out = _mesa_image_image_stride(<wbr>packing, w, h, format, type);<br>
+<br>
+ if (_mesa_is_bufferobj(packing-><wbr>BufferObj)) {<br>
+ const uint32_t offset = first_pixel + (intptr_t)pixels;<br>
+ if (!read_only && ((offset % cpp) || (stride % cpp))) {<br>
+ perf_debug("Bad PBO alignment; fallback to CPU mapping\n");<br>
+ return false;<br>
+ }<br>
+<br>
+ /* This is a user-provided PBO. We just need to get the BO out */<br>
+ struct intel_buffer_object *intel_pbo =<br>
+ intel_buffer_object(packing-><wbr>BufferObj);<br>
+ struct brw_bo *bo =<br>
+ intel_bufferobj_buffer(brw, intel_pbo, offset, size, false);<br>
+<br>
+ /* We take a reference to the BO so that the caller can just always<br>
+ * unref without having to worry about whether it's a user PBO or one<br>
+ * we created.<br>
+ */<br>
+ brw_bo_reference(bo);<br>
+<br>
+ *offset_out = offset;<br>
+ return bo;<br>
+ } else {<br>
+ /* Someone should have already checked that there is data to upload. */<br>
+ assert(pixels);<br>
+<br>
+ /* Creating a temp buffer currently only works for upload */<br>
+ assert(read_only);<br>
+<br>
+ /* This is not a user-provided PBO. Instead, pixels is a pointer to CPU<br>
+ * data which we need to copy into a BO.<br>
+ */<br>
+ struct brw_bo *bo =<br>
+ brw_bo_alloc(brw->bufmgr, "tmp_tex_subimage_src", size, 64);<br>
+ if (bo == NULL) {<br>
+ perf_debug("intel_texsubimage: temp bo creation failed: size = %u\n",<br>
+ size);<br>
+ return NULL;<br>
+ }<br>
+<br>
+ if (brw_bo_subdata(bo, 0, size, pixels + first_pixel)) {<br>
+ perf_debug("intel_texsubimage: temp bo upload failed\n");<br>
+ brw_bo_unreference(bo);<br>
+ return NULL;<br>
+ }<br>
+<br>
+ *offset_out = 0;<br>
+ return bo;<br>
+ }<br>
+}<br>
+<br>
+/* Consider all the restrictions and determine the format of the source. */<br>
+static mesa_format<br>
+blorp_get_client_format(<wbr>struct brw_context *brw,<br>
+ GLenum format, GLenum type,<br>
+ const struct gl_pixelstore_attrib *packing)<br>
+{<br>
+ if (brw->ctx._ImageTransferState)<br>
+ return MESA_FORMAT_NONE;<br>
+<br>
+ if (packing->SwapBytes || packing->LsbFirst || packing->Invert) {<br>
+ perf_debug("intel_texsubimage_<wbr>blorp: unsupported gl_pixelstore_attrib\n");<br>
+ return MESA_FORMAT_NONE;<br>
+ }<br>
+<br>
+ if (format != GL_RED &&<br>
+ format != GL_RG &&<br>
+ format != GL_RGB &&<br>
+ format != GL_RGBA &&<br>
+ format != GL_ALPHA &&<br>
+ format != GL_RED_INTEGER &&<br>
+ format != GL_RG_INTEGER &&<br>
+ format != GL_RGB_INTEGER &&<br>
+ format != GL_RGBA_INTEGER) {<br>
+ perf_debug("intel_texsubimage_<wbr>blorp: %s not supported",<br>
+ _mesa_enum_to_string(format));<br>
+ return MESA_FORMAT_NONE;<br>
+ }<br>
+<br>
+ return _mesa_tex_format_from_format_<wbr>and_type(&brw->ctx, format, type);<br>
+}<br>
+<br>
+static bool<br>
+need_signed_unsigned_int_<wbr>conversion(mesa_format src_format,<br>
+ mesa_format dst_format)<br>
+{<br>
+ const GLenum src_type = _mesa_get_format_datatype(src_<wbr>format);<br>
+ const GLenum dst_type = _mesa_get_format_datatype(dst_<wbr>format);<br>
+ return (src_type == GL_INT && dst_type == GL_UNSIGNED_INT) ||<br>
+ (src_type == GL_UNSIGNED_INT && dst_type == GL_INT);<br>
+}<br>
+<br>
+bool<br>
+brw_blorp_upload_miptree(<wbr>struct brw_context *brw,<br>
+ struct intel_mipmap_tree *dst_mt,<br>
+ mesa_format dst_format,<br>
+ uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+ uint32_t width, uint32_t height, uint32_t depth,<br>
+ GLenum target, GLenum format, GLenum type,<br>
+ const void *pixels,<br>
+ const struct gl_pixelstore_attrib *packing)<br>
+{<br>
+ const mesa_format src_format =<br>
+ blorp_get_client_format(brw, format, type, packing);<br>
+ if (src_format == MESA_FORMAT_NONE)<br>
+ return false;<br>
+<br>
+ if (!brw->mesa_format_supports_<wbr>render[dst_format]) {<br>
+ perf_debug("intel_texsubimage: can't use %s as render target\n",<br>
+ _mesa_get_format_name(dst_<wbr>format));<br>
+ return false;<br>
+ }<br>
+<br>
+ /* This function relies on blorp_blit to upload the pixel data to the<br>
+ * miptree. But, blorp_blit doesn't support signed to unsigned or<br>
+ * unsigned to signed integer conversions.<br>
+ */<br>
+ if (need_signed_unsigned_int_<wbr>conversion(src_format, dst_format))<br>
+ return false;<br>
+<br>
+ uint32_t src_offset, src_row_stride, src_image_stride;<br>
+ struct brw_bo *src_bo =<br>
+ blorp_get_client_bo(brw, width, height, depth,<br>
+ target, format, type, pixels, packing,<br>
+ &src_offset, &src_row_stride,<br>
+ &src_image_stride, true);<br>
+ if (src_bo == NULL)<br>
+ return false;<br>
+<br>
+ /* Now that source is offset to correct starting point, adjust the<br>
+ * given dimensions to treat 1D arrays as 2D.<br>
+ */<br>
+ if (target == GL_TEXTURE_1D_ARRAY) {<br>
+ assert(depth == 1);<br>
+ assert(z == 0);<br>
+ depth = height;<br>
+ height = 1;<br>
+ z = y;<br>
+ y = 0;<br>
+ src_image_stride = src_row_stride;<br>
+ }<br>
+<br>
+ intel_miptree_check_level_<wbr>layer(dst_mt, level, z + depth - 1);<br>
+<br>
+ bool result = false;<br>
+<br>
+ /* Blit slice-by-slice creating a single-slice miptree for each layer. Even<br>
+ * in case of linear buffers hardware wants image arrays to be aligned by<br>
+ * four rows. This way hardware only gets one image at a time and any<br>
+ * source alignment will do.<br>
+ */<br>
+ for (unsigned i = 0; i < depth; ++i) {<br>
+ struct intel_mipmap_tree *src_mt = intel_miptree_create_for_bo(<br>
+ brw, src_bo, src_format,<br>
+ src_offset + i * src_image_stride,<br>
+ width, height, 1,<br>
+ src_row_stride, 0);<br>
+<br>
+ if (!src_mt) {<br>
+ perf_debug("intel_texsubimage: miptree creation for src failed\n");<br>
+ goto err;<br>
+ }<br>
+<br>
+ /* In case exact match is needed, copy using equivalent UINT formats<br>
+ * preventing hardware from changing presentation for SNORM -1.<br>
+ */<br>
+ if (src_mt->format == dst_format) {<br>
+ brw_blorp_copy_miptrees(brw, src_mt, 0, 0,<br>
+ dst_mt, level, z + i,<br>
+ 0, 0, x, y, width, height);<br>
+ } else {<br>
+ brw_blorp_blit_miptrees(brw, src_mt, 0, 0,<br>
+ src_format, SWIZZLE_XYZW,<br>
+ dst_mt, level, z + i,<br>
+ dst_format,<br>
+ 0, 0, width, height,<br>
+ x, y, x + width, y + height,<br>
+ GL_NEAREST, false, false, false, false);<br>
+ }<br>
+<br>
+ intel_miptree_release(&src_mt)<wbr>;<br>
+ }<br>
+<br>
+ result = true;<br>
+<br>
+err:<br>
+ brw_bo_unreference(src_bo);<br>
+<br>
+ return result;<br>
+}<br>
+<br>
+bool<br>
+brw_blorp_download_miptree(<wbr>struct brw_context *brw,<br>
+ struct intel_mipmap_tree *src_mt,<br>
+ mesa_format src_format, uint32_t src_swizzle,<br>
+ uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+ uint32_t width, uint32_t height, uint32_t depth,<br>
+ GLenum target, GLenum format, GLenum type,<br>
+ bool y_flip, const void *pixels,<br>
+ const struct gl_pixelstore_attrib *packing)<br>
+{<br>
+ const mesa_format dst_format =<br>
+ blorp_get_client_format(brw, format, type, packing);<br>
+ if (dst_format == MESA_FORMAT_NONE)<br>
+ return false;<br>
+<br>
+ if (!brw->mesa_format_supports_<wbr>render[dst_format]) {<br>
+ perf_debug("intel_texsubimage: can't use %s as render target\n",<br>
+ _mesa_get_format_name(dst_<wbr>format));<br>
+ return false;<br>
+ }<br>
+<br>
+ /* This function relies on blorp_blit to download the pixel data from the<br>
+ * miptree. But, blorp_blit doesn't support signed to unsigned or unsigned<br>
+ * to signed integer conversions.<br>
+ */<br>
+ if (need_signed_unsigned_int_<wbr>conversion(src_format, dst_format))<br>
+ return false;<br>
+<br>
+ /* We can't fetch from LUMINANCE or intensity as that would require a<br>
+ * non-trivial swizzle.<br>
+ */<br>
+ switch (_mesa_get_format_base_format(<wbr>src_format)) {<br>
+ case GL_LUMINANCE:<br>
+ case GL_LUMINANCE_ALPHA:<br>
+ case GL_INTENSITY:<br>
+ return false;<br>
+ default:<br>
+ break;<br>
+ }<br>
+<br>
+ /* This pass only works for PBOs */<br>
+ assert(_mesa_is_bufferobj(<wbr>packing->BufferObj));<br>
+<br>
+ uint32_t dst_offset, dst_row_stride, dst_image_stride;<br>
+ struct brw_bo *dst_bo =<br>
+ blorp_get_client_bo(brw, width, height, depth,<br>
+ target, format, type, pixels, packing,<br>
+ &dst_offset, &dst_row_stride,<br>
+ &dst_image_stride, true);<br>
+ if (dst_bo == NULL)<br>
+ return false;<br>
+<br>
+ /* Now that source is offset to correct starting point, adjust the<br>
+ * given dimensions to treat 1D arrays as 2D.<br>
+ */<br>
+ if (target == GL_TEXTURE_1D_ARRAY) {<br>
+ assert(depth == 1);<br>
+ assert(z == 0);<br>
+ depth = height;<br>
+ height = 1;<br>
+ z = y;<br>
+ y = 0;<br>
+ dst_image_stride = dst_row_stride;<br>
+ }<br>
+<br>
+ intel_miptree_check_level_<wbr>layer(src_mt, level, z + depth - 1);<br>
+<br>
+ bool result = false;<br>
+<br>
+ /* Blit slice-by-slice creating a single-slice miptree for each layer. Even<br>
+ * in case of linear buffers hardware wants image arrays to be aligned by<br>
+ * four rows. This way hardware only gets one image at a time and any<br>
+ * source alignment will do.<br>
+ */<br>
+ for (unsigned i = 0; i < depth; ++i) {<br>
+ struct intel_mipmap_tree *dst_mt = intel_miptree_create_for_bo(<br>
+ brw, dst_bo, dst_format,<br>
+ dst_offset + i * dst_image_stride,<br>
+ width, height, 1,<br>
+ dst_row_stride, 0);<br>
+<br>
+ if (!dst_mt) {<br>
+ perf_debug("intel_texsubimage: miptree creation for src failed\n");<br>
+ goto err;<br>
+ }<br>
+<br>
+ /* In case exact match is needed, copy using equivalent UINT formats<br>
+ * preventing hardware from changing presentation for SNORM -1.<br>
+ */<br>
+ if (dst_mt->format == src_format && !y_flip &&<br>
+ src_swizzle == SWIZZLE_XYZW) {<br>
+ brw_blorp_copy_miptrees(brw, src_mt, level, z + i,<br>
+ dst_mt, 0, 0,<br>
+ x, y, 0, 0, width, height);<br>
+ } else {<br>
+ brw_blorp_blit_miptrees(brw, src_mt, level, z + i,<br>
+ src_format, src_swizzle,<br>
+ dst_mt, 0, 0, dst_format,<br>
+ x, y, x + width, y + height,<br>
+ 0, 0, width, height,<br>
+ GL_NEAREST, false, y_flip, false, false);<br>
+ }<br>
+<br>
+ intel_miptree_release(&dst_mt)<wbr>;<br>
+ }<br>
+<br>
+ result = true;<br>
+<br>
+err:<br>
+ brw_bo_unreference(dst_bo);<br>
+<br>
+ return result;<br>
+}<br>
+<br>
static bool<br>
set_write_disables(const struct intel_renderbuffer *irb,<br>
const GLubyte *color_mask, bool *color_write_disable)<br>
diff --git a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h<br>
index cf781ec53cb..c5ded891bbf 100644<br>
--- a/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h<br>
+++ b/src/mesa/drivers/dri/i965/<wbr>brw_blorp.h<br>
@@ -67,6 +67,26 @@ brw_blorp_copy_buffers(struct brw_context *brw,<br>
unsigned dst_offset,<br>
unsigned size);<br>
<br>
+bool<br>
+brw_blorp_upload_miptree(<wbr>struct brw_context *brw,<br>
+ struct intel_mipmap_tree *dst_mt,<br>
+ mesa_format dst_format,<br>
+ uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+ uint32_t width, uint32_t height, uint32_t depth,<br>
+ GLenum target, GLenum format, GLenum type,<br>
+ const void *pixels,<br>
+ const struct gl_pixelstore_attrib *packing);<br>
+<br>
+bool<br>
+brw_blorp_download_miptree(<wbr>struct brw_context *brw,<br>
+ struct intel_mipmap_tree *src_mt,<br>
+ mesa_format src_format, uint32_t src_swizzle,<br>
+ uint32_t level, uint32_t x, uint32_t y, uint32_t z,<br>
+ uint32_t width, uint32_t height, uint32_t depth,<br>
+ GLenum target, GLenum format, GLenum type,<br>
+ bool y_flip, const void *pixels,<br>
+ const struct gl_pixelstore_attrib *packing);<br>
+<br>
void<br>
brw_blorp_clear_color(struct brw_context *brw, struct gl_framebuffer *fb,<br>
GLbitfield mask, bool partial_clear, bool encode_srgb);<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.14.2<br>
<br>
</font></span></blockquote></div><br></div></div>