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