Gen 7 GPUs store the compressed EAC/ETC2 images in other non-compressed formats that can render. When GetCompressed* functions are called, the pixels are returned in the non-compressed format that is used for the rendering.
With this patch we store both the compressed and non-compressed versions of the image, so that both rendering commands and GetCompressed* commands work. Also, the assertions for GL_MAP_WRITE_BIT and GL_MAP_INVALIDATE_RANGE_BIT in intel_miptree_map_etc function have been removed because when the miptree is mapped for reading (for example from a GetCompress* function) the GL_MAP_WRITE_BIT won't be set (and shouldn't be set). Fixes: the following test in CTS for gen7: KHR-GL45.direct_state_access.textures_compressed_subimage test Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104272 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=81843 v2: fixes issues: a) initialized uninitialized variables (Juan A. Suarez, Andres Gomez) b) fixed race condition where mt and cmt were mapped at the same time c) fixed indentation issues (Andres Gomez) v3: adds bugzilla bug with id: 104272 v4: adds bugzilla bug with id: 81843 v5: replaced the flags with a bitfield, refactoring (Kenneth Graunke) v6: renamed the r8stencil_mt secondary miptree that is now part of the intel_miptree_struct to shadow_mt and used it to store the compressed miptree (Nanley Chery) --- .../drivers/dri/i965/brw_wm_surface_state.c | 8 +- src/mesa/drivers/dri/i965/intel_mipmap_tree.c | 27 +++--- src/mesa/drivers/dri/i965/intel_mipmap_tree.h | 14 ++- src/mesa/drivers/dri/i965/intel_tex.c | 90 ++++++++++++++++++- src/mesa/drivers/dri/i965/intel_tex_image.c | 46 +++++++++- src/mesa/main/texstore.c | 62 ++++++++----- src/mesa/main/texstore.h | 8 ++ 7 files changed, 209 insertions(+), 46 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c index 9397b637c7..2097fabaeb 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c @@ -563,15 +563,15 @@ static void brw_update_texture_surface(struct gl_context *ctx, if (obj->StencilSampling && firstImage->_BaseFormat == GL_DEPTH_STENCIL) { if (devinfo->gen <= 7) { - assert(mt->r8stencil_mt && !mt->stencil_mt->r8stencil_needs_update); - mt = mt->r8stencil_mt; + assert(mt->shadow_mt && !mt->stencil_mt->shadow_needs_update); + mt = mt->shadow_mt; } else { mt = mt->stencil_mt; } format = ISL_FORMAT_R8_UINT; } else if (devinfo->gen <= 7 && mt->format == MESA_FORMAT_S_UINT8) { - assert(mt->r8stencil_mt && !mt->r8stencil_needs_update); - mt = mt->r8stencil_mt; + assert(mt->shadow_mt && !mt->shadow_needs_update); + mt = mt->shadow_mt; format = ISL_FORMAT_R8_UINT; } diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c index 7b1f0896ae..6d07fede52 100644 --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c @@ -719,8 +719,12 @@ miptree_create(struct brw_context *brw, } } - mt->etc_format = (_mesa_is_format_color_format(format) && mt_fmt != format) ? - format : MESA_FORMAT_NONE; + if (!(flags & MIPTREE_CREATE_ETC)) { + mt->etc_format = (_mesa_is_format_color_format(format) && + mt_fmt != format) ? format : MESA_FORMAT_NONE; + } else { + mt->etc_format = MESA_FORMAT_NONE; + } if (!(flags & MIPTREE_CREATE_NO_AUX)) intel_miptree_choose_aux_usage(brw, mt); @@ -1214,7 +1218,7 @@ intel_miptree_release(struct intel_mipmap_tree **mt) brw_bo_unreference((*mt)->bo); intel_miptree_release(&(*mt)->stencil_mt); - intel_miptree_release(&(*mt)->r8stencil_mt); + intel_miptree_release(&(*mt)->shadow_mt); intel_miptree_aux_buffer_free((*mt)->aux_buf); free_aux_state_map((*mt)->aux_state); @@ -2426,7 +2430,7 @@ intel_miptree_finish_write(struct brw_context *brw, switch (mt->aux_usage) { case ISL_AUX_USAGE_NONE: if (mt->format == MESA_FORMAT_S_UINT8 && devinfo->gen <= 7) - mt->r8stencil_needs_update = true; + mt->shadow_needs_update = true; break; case ISL_AUX_USAGE_MCS: @@ -2919,9 +2923,9 @@ intel_update_r8stencil(struct brw_context *brw, assert(src->surf.size > 0); - if (!mt->r8stencil_mt) { + if (!mt->shadow_mt) { assert(devinfo->gen > 6); /* Handle MIPTREE_LAYOUT_GEN6_HIZ_STENCIL */ - mt->r8stencil_mt = make_surface( + mt->shadow_mt = make_surface( brw, src->target, MESA_FORMAT_R_UINT8, @@ -2935,13 +2939,13 @@ intel_update_r8stencil(struct brw_context *brw, ISL_TILING_Y0_BIT, ISL_SURF_USAGE_TEXTURE_BIT, BO_ALLOC_BUSY, 0, NULL); - assert(mt->r8stencil_mt); + assert(mt->shadow_mt); } - if (src->r8stencil_needs_update == false) + if (src->shadow_needs_update == false) return; - struct intel_mipmap_tree *dst = mt->r8stencil_mt; + struct intel_mipmap_tree *dst = mt->shadow_mt; for (int level = src->first_level; level <= src->last_level; level++) { const unsigned depth = src->surf.dim == ISL_SURF_DIM_3D ? @@ -2961,7 +2965,7 @@ intel_update_r8stencil(struct brw_context *brw, } brw_cache_flush_for_read(brw, dst->bo); - src->r8stencil_needs_update = false; + src->shadow_needs_update = false; } static void * @@ -3333,9 +3337,6 @@ intel_miptree_map_etc(struct brw_context *brw, assert(mt->format == MESA_FORMAT_R8G8B8X8_UNORM); } - assert(map->mode & GL_MAP_WRITE_BIT); - assert(map->mode & GL_MAP_INVALIDATE_RANGE_BIT); - intel_miptree_access_raw(brw, mt, level, slice, true); map->stride = _mesa_format_row_stride(mt->etc_format, map->w); diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h index bb7df7ad23..5f4cdd28d8 100644 --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h @@ -74,6 +74,7 @@ struct intel_texture_image; * without transcoding back. This flag to intel_miptree_map() gets you that. */ #define BRW_MAP_DIRECT_BIT 0x80000000 +#define BRW_MAP_ETC_BIT 0x40000000 struct intel_miptree_map { /** Bitfield of GL_MAP_*_BIT and BRW_MAP_*_BIT. */ @@ -302,8 +303,8 @@ struct intel_mipmap_tree * * \see intel_update_r8stencil() */ - struct intel_mipmap_tree *r8stencil_mt; - bool r8stencil_needs_update; + struct intel_mipmap_tree *shadow_mt; + bool shadow_needs_update; /** * \brief CCS, MCS, or HiZ auxiliary buffer. @@ -377,6 +378,15 @@ enum intel_miptree_create_flags { * that the miptree will be created with mt->aux_usage == NONE. */ MIPTREE_CREATE_NO_AUX = 1 << 1, + + /** Create a second miptree for the compressed pixels (Gen7 only) + * + * On Gen7, we need to store 2 miptrees for some compressed + * formats so we can handle rendering as well as getting the + * compressed image data. This flag indicates that the miptree + * is expected to hold compressed data for the latter case. + */ + MIPTREE_CREATE_ETC = 1 << 2, }; struct intel_mipmap_tree *intel_miptree_create(struct brw_context *brw, diff --git a/src/mesa/drivers/dri/i965/intel_tex.c b/src/mesa/drivers/dri/i965/intel_tex.c index 0650b6e629..922c6aa4bc 100644 --- a/src/mesa/drivers/dri/i965/intel_tex.c +++ b/src/mesa/drivers/dri/i965/intel_tex.c @@ -66,6 +66,8 @@ intel_alloc_texture_image_buffer(struct gl_context *ctx, struct intel_texture_image *intel_image = intel_texture_image(image); struct gl_texture_object *texobj = image->TexObject; struct intel_texture_object *intel_texobj = intel_texture_object(texobj); + struct gen_device_info *devinfo = &brw->screen->devinfo; + mesa_format fmt = image->TexFormat; assert(image->Border == 0); @@ -110,6 +112,38 @@ intel_alloc_texture_image_buffer(struct gl_context *ctx, image->Width, image->Height, image->Depth, intel_image->mt); } + if (devinfo->gen < 8 && _mesa_is_format_etc2(fmt)) { + if (intel_texobj->mt->shadow_mt && + intel_miptree_match_image(intel_texobj->mt->shadow_mt, + image)) { + intel_miptree_reference(&intel_texobj->mt->shadow_mt, + intel_image->mt->shadow_mt); + DBG("%s: alloc obj %p level %d %dx%dx%d using object's miptree %p\n", + __func__, texobj, image->Level, + image->Width, image->Height, image->Depth, + intel_texobj->mt->shadow_mt); + } else { + intel_image->mt->shadow_mt = intel_miptree_create_for_teximage(brw, + intel_texobj, + intel_image, + MIPTREE_CREATE_ETC); + if (!intel_image->mt->shadow_mt) + return false; + /* Even if the object currently has a mipmap tree associated + * with it, this one is a more likely candidate to represent the + * whole object since our level didn't fit what was there + * before, and any lower levels would fit into our miptree. + */ + intel_miptree_reference(&intel_texobj->mt->shadow_mt, + intel_image->mt->shadow_mt); + + DBG("%s: alloc obj %p level %d %dx%dx%d using new miptree %p\n", + __func__, texobj, image->Level, + image->Width, image->Height, image->Depth, + intel_image->mt->shadow_mt); + } + } + intel_texobj->needs_validate = true; return true; @@ -128,6 +162,7 @@ intel_alloc_texture_storage(struct gl_context *ctx, GLsizei height, GLsizei depth) { struct brw_context *brw = brw_context(ctx); + struct gen_device_info *devinfo = &brw->screen->devinfo; struct intel_texture_object *intel_texobj = intel_texture_object(texobj); struct gl_texture_image *first_image = texobj->Image[0][0]; int num_samples = intel_quantize_num_samples(brw->screen, @@ -136,6 +171,9 @@ intel_alloc_texture_storage(struct gl_context *ctx, int face; int level; + mesa_format fmt = first_image->TexFormat; + bool is_fake_etc = (devinfo->gen < 8) && _mesa_is_format_etc2(fmt); + /* If the object's current miptree doesn't match what we need, make a new * one. */ @@ -157,6 +195,24 @@ intel_alloc_texture_storage(struct gl_context *ctx, } } + if (is_fake_etc) { + if (!intel_texobj->mt->shadow_mt || + !intel_miptree_match_image(intel_texobj->mt->shadow_mt, + first_image) || + intel_texobj->mt->shadow_mt->last_level != levels -1) { + intel_miptree_release(&intel_texobj->mt->shadow_mt); + intel_get_image_dims(first_image, &width, &height, &depth); + intel_texobj->mt->shadow_mt = intel_miptree_create(brw, + texobj->Target, + first_image->TexFormat, + 0, levels - 1, + width, height, + depth, + MAX2(num_samples, 1), + MIPTREE_CREATE_ETC); + } + } + for (face = 0; face < numFaces; face++) { for (level = 0; level < levels; level++) { struct gl_texture_image *image = texobj->Image[face][level]; @@ -169,6 +225,9 @@ intel_alloc_texture_storage(struct gl_context *ctx, return false; intel_miptree_reference(&intel_image->mt, intel_texobj->mt); + if (is_fake_etc) + intel_miptree_reference(&intel_image->mt->shadow_mt, + intel_texobj->mt->shadow_mt); } } @@ -212,8 +271,11 @@ intel_map_texture_image(struct gl_context *ctx, GLint *out_stride) { struct brw_context *brw = brw_context(ctx); + struct gen_device_info *devinfo = &brw->screen->devinfo; + mesa_format fmt = tex_image->TexFormat; struct intel_texture_image *intel_image = intel_texture_image(tex_image); struct intel_mipmap_tree *mt = intel_image->mt; + struct intel_mipmap_tree *cmt = intel_image->mt->shadow_mt; ptrdiff_t stride; /* Our texture data is always stored in a miptree. */ @@ -229,6 +291,20 @@ intel_map_texture_image(struct gl_context *ctx, if (tex_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) slice = tex_image->Face; + if (devinfo->gen < 8) { + if ((!(mode & GL_MAP_WRITE_BIT) && _mesa_is_format_etc2(fmt)) || + (mode & BRW_MAP_ETC_BIT)) { + assert(cmt); + intel_miptree_map(brw, cmt, + tex_image->Level + tex_image->TexObject->MinLevel, + slice + tex_image->TexObject->MinLayer, + x, y, w, h, mode, + (void **)map, &stride); + *out_stride = stride; + return; + } + } + intel_miptree_map(brw, mt, tex_image->Level + tex_image->TexObject->MinLevel, slice + tex_image->TexObject->MinLayer, @@ -245,13 +321,21 @@ intel_unmap_texture_image(struct gl_context *ctx, struct brw_context *brw = brw_context(ctx); struct intel_texture_image *intel_image = intel_texture_image(tex_image); struct intel_mipmap_tree *mt = intel_image->mt; + struct intel_mipmap_tree *cmt = intel_image->mt->shadow_mt; if (tex_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) slice = tex_image->Face; - intel_miptree_unmap(brw, mt, - tex_image->Level + tex_image->TexObject->MinLevel, - slice + tex_image->TexObject->MinLayer); + if (cmt) { + intel_miptree_unmap(brw, cmt, + tex_image->Level + tex_image->TexObject->MinLevel, + slice + tex_image->TexObject->MinLayer); + } + if (mt) { + intel_miptree_unmap(brw, mt, + tex_image->Level + tex_image->TexObject->MinLevel, + slice + tex_image->TexObject->MinLayer); + } } static GLboolean diff --git a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c index 3d948381f4..710d93cd06 100644 --- a/src/mesa/drivers/dri/i965/intel_tex_image.c +++ b/src/mesa/drivers/dri/i965/intel_tex_image.c @@ -857,7 +857,7 @@ flush_astc_denorms(struct gl_context *ctx, GLuint dims, for (int slice = 0; slice < store.CopySlices; slice++) { /* Map dest texture buffer */ - GLubyte *dstMap; + GLubyte *dstMap = NULL; GLint dstRowStride; ctx->Driver.MapTextureImage(ctx, texImage, slice + zoffset, xoffset, yoffset, width, height, @@ -901,6 +901,48 @@ flush_astc_denorms(struct gl_context *ctx, GLuint dims, } } +static void +intel_store_compressed_texsubimage(struct gl_context *ctx, GLuint dims, + struct gl_texture_image *intelImage, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, + GLsizei depth, GLenum format, + GLsizei imageSize, const GLvoid *data) +{ + struct compressed_pixelstore store; + struct brw_context *brw = (struct brw_context*) ctx; + const struct gen_device_info *devinfo = &brw->screen->devinfo; + GLbitfield mode = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT; + + if (dims == 1) { + _mesa_problem(ctx, "Unexpected 1D compressed texsubimage call"); + return; + } + + _mesa_compute_compressed_pixelstore(dims, intelImage->TexFormat, + width, height, depth, + &ctx->Unpack, &store); + + /* Get pointer to src pixels (may be in a pbo which we'll map here) */ + data = _mesa_validate_pbo_compressed_teximage(ctx, dims, imageSize, data, + &ctx->Unpack, + "glCompressedTexSubImage"); + if (!data) + return; + + _mesa_upload_compressed_texsubimage(ctx, dims, &store, intelImage, + xoffset, yoffset, zoffset, + width, height, mode, data); + + if ((devinfo->gen < 8) && _mesa_is_format_etc2(intelImage->TexFormat)) { + _mesa_upload_compressed_texsubimage(ctx, dims, &store, intelImage, + xoffset, yoffset, zoffset, + width, height, + mode | BRW_MAP_ETC_BIT, data); + } + + _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack); +} static void intelCompressedTexSubImage(struct gl_context *ctx, GLuint dims, @@ -911,7 +953,7 @@ intelCompressedTexSubImage(struct gl_context *ctx, GLuint dims, GLsizei imageSize, const GLvoid *data) { /* Upload the compressed data blocks */ - _mesa_store_compressed_texsubimage(ctx, dims, texImage, + intel_store_compressed_texsubimage(ctx, dims, texImage, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); diff --git a/src/mesa/main/texstore.c b/src/mesa/main/texstore.c index 31163f6771..7ceb590dce 100644 --- a/src/mesa/main/texstore.c +++ b/src/mesa/main/texstore.c @@ -1322,16 +1322,15 @@ _mesa_compute_compressed_pixelstore(GLuint dims, mesa_format texFormat, void _mesa_store_compressed_texsubimage(struct gl_context *ctx, GLuint dims, struct gl_texture_image *texImage, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, + GLint xoffset, GLint yoffset, + GLint zoffset, + GLsizei width, GLsizei height, + GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) { struct compressed_pixelstore store; - GLint dstRowStride; - GLint i, slice; - GLubyte *dstMap; - const GLubyte *src; + GLbitfield mode = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT; if (dims == 1) { _mesa_problem(ctx, "Unexpected 1D compressed texsubimage call"); @@ -1349,41 +1348,60 @@ _mesa_store_compressed_texsubimage(struct gl_context *ctx, GLuint dims, if (!data) return; - src = (const GLubyte *) data + store.SkipBytes; + _mesa_upload_compressed_texsubimage(ctx, dims, &store, texImage, + xoffset, yoffset, zoffset, + width, height, mode, data); + + _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack); +} + +void +_mesa_upload_compressed_texsubimage(struct gl_context *ctx, GLuint dims, + struct compressed_pixelstore *store, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, + GLint zoffset, + GLsizei width, GLsizei height, + GLbitfield mode, const GLvoid *data) +{ + GLint i, slice, dstRowStride; + GLubyte *dstMap = NULL; - for (slice = 0; slice < store.CopySlices; slice++) { + if (!data) + return; + + const GLubyte *src = (const GLubyte *) data + store->SkipBytes; + + for (slice = 0; slice < store->CopySlices; slice++) { /* Map dest texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, slice + zoffset, - xoffset, yoffset, width, height, - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT, + xoffset, yoffset, width, height, mode, &dstMap, &dstRowStride); - if (dstMap) { - /* copy rows of blocks */ - if (dstRowStride == store.TotalBytesPerRow && - dstRowStride == store.CopyBytesPerRow) { - memcpy(dstMap, src, store.CopyBytesPerRow * store.CopyRowsPerSlice); - src += store.CopyBytesPerRow * store.CopyRowsPerSlice; + if (dstRowStride == store->TotalBytesPerRow && + dstRowStride == store->CopyBytesPerRow) { + memcpy(dstMap, src, + store->CopyBytesPerRow * store->CopyRowsPerSlice); + src += store->CopyBytesPerRow * store->CopyRowsPerSlice; } else { - for (i = 0; i < store.CopyRowsPerSlice; i++) { - memcpy(dstMap, src, store.CopyBytesPerRow); + for (i = 0; i < store->CopyRowsPerSlice; i++) { + memcpy(dstMap, src, store->CopyBytesPerRow); dstMap += dstRowStride; - src += store.TotalBytesPerRow; + src += store->TotalBytesPerRow; } } ctx->Driver.UnmapTextureImage(ctx, texImage, slice + zoffset); /* advance to next slice */ - src += store.TotalBytesPerRow * (store.TotalRowsPerSlice - store.CopyRowsPerSlice); + src += store->TotalBytesPerRow * + (store->TotalRowsPerSlice - store->CopyRowsPerSlice); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage%uD", dims); } } - - _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack); } diff --git a/src/mesa/main/texstore.h b/src/mesa/main/texstore.h index 2fef7ba7d7..d40230e885 100644 --- a/src/mesa/main/texstore.h +++ b/src/mesa/main/texstore.h @@ -158,6 +158,14 @@ struct compressed_pixelstore { int CopySlices; }; +extern void +_mesa_upload_compressed_texsubimage(struct gl_context *ctx, GLuint dims, + struct compressed_pixelstore *store, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, + GLint zoffset, + GLsizei width, GLsizei height, + GLbitfield mode, const GLvoid *data); extern void _mesa_compute_compressed_pixelstore(GLuint dims, mesa_format texFormat, -- 2.18.0 _______________________________________________ mesa-dev mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/mesa-dev
