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) --- src/mesa/drivers/dri/i965/intel_mipmap_tree.c | 10 +- src/mesa/drivers/dri/i965/intel_mipmap_tree.h | 10 ++ src/mesa/drivers/dri/i965/intel_tex.c | 106 +++++++++++++++--- src/mesa/drivers/dri/i965/intel_tex.h | 1 - src/mesa/drivers/dri/i965/intel_tex_image.c | 46 +++++++- src/mesa/drivers/dri/i965/intel_tex_obj.h | 8 ++ src/mesa/main/texstore.c | 51 ++++++--- src/mesa/main/texstore.h | 8 +- 8 files changed, 197 insertions(+), 43 deletions(-) diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c index 7d1fa96b91..cc807977de 100644 --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c @@ -733,9 +733,10 @@ miptree_create(struct brw_context *brw, mesa_format etc_format = MESA_FORMAT_NONE; uint32_t alloc_flags = 0; - format = intel_lower_compressed_format(brw, format); - - etc_format = (format != tex_format) ? tex_format : MESA_FORMAT_NONE; + if (!(flags & MIPTREE_CREATE_ETC)) { + format = intel_lower_compressed_format(brw, format); + etc_format = (format != tex_format) ? tex_format : MESA_FORMAT_NONE; + } if (flags & MIPTREE_CREATE_BUSY) alloc_flags |= BO_ALLOC_BUSY; @@ -3372,9 +3373,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 42f73ba1f9..9e7a401229 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. */ @@ -380,6 +381,15 @@ enum intel_miptree_create_flags { * that the miptree will be created with mt->aux_usage == NONE. */ MIPTREE_CREATE_NO_AUX = 1 << 2, + + /** 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 << 3, }; 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..3a94fa7477 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,33 @@ 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->cmt && + intel_miptree_match_image(intel_texobj->cmt, image)) { + intel_miptree_reference(&intel_image->cmt, intel_texobj->cmt); + 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->cmt); + } else { + intel_image->cmt = intel_miptree_create_for_teximage(brw, + intel_texobj, + intel_image, + MIPTREE_CREATE_ETC); + if (!intel_image->cmt) + 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->cmt, intel_image->cmt); + + 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->cmt); + } + } intel_texobj->needs_validate = true; return true; @@ -128,6 +157,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 +166,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 +190,22 @@ intel_alloc_texture_storage(struct gl_context *ctx, } } + if (is_fake_etc) { + if (!intel_texobj->cmt || + !intel_miptree_match_image(intel_texobj->cmt, first_image) || + intel_texobj->cmt->last_level != levels - 1) { + intel_miptree_release(&intel_texobj->cmt); + + intel_get_image_dims(first_image, &width, &height, &depth); + intel_texobj->cmt = 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 +218,8 @@ 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->cmt, intel_texobj->cmt); } } @@ -181,7 +232,6 @@ intel_alloc_texture_storage(struct gl_context *ctx, return true; } - static void intel_free_texture_image_buffer(struct gl_context * ctx, struct gl_texture_image *texImage) @@ -191,6 +241,7 @@ intel_free_texture_image_buffer(struct gl_context * ctx, DBG("%s\n", __func__); intel_miptree_release(&intelImage->mt); + intel_miptree_release(&intelImage->cmt); _swrast_free_texture_image_buffer(ctx, texImage); } @@ -204,37 +255,52 @@ intel_free_texture_image_buffer(struct gl_context * ctx, */ static void intel_map_texture_image(struct gl_context *ctx, - struct gl_texture_image *tex_image, - GLuint slice, - GLuint x, GLuint y, GLuint w, GLuint h, - GLbitfield mode, - GLubyte **map, - GLint *out_stride) + struct gl_texture_image *tex_image, + GLuint slice, + GLuint x, GLuint y, GLuint w, GLuint h, + GLbitfield mode, + GLubyte **map, + 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->cmt; ptrdiff_t stride; /* Our texture data is always stored in a miptree. */ assert(mt); /* Check that our caller wasn't confused about how to map a 1D texture. */ - assert(tex_image->TexObject->Target != GL_TEXTURE_1D_ARRAY || - h == 1); + assert(tex_image->TexObject->Target != GL_TEXTURE_1D_ARRAY || h == 1); - /* intel_miptree_map operates on a unified "slice" number that references the - * cube face, since it's all just slices to the miptree code. + /* intel_miptree_map operates on a unified "slice" number that references + * the cube face, since it's all just slices to the miptree code. */ 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, x, y, w, h, mode, (void **)map, &stride); - *out_stride = stride; } @@ -243,15 +309,25 @@ intel_unmap_texture_image(struct gl_context *ctx, struct gl_texture_image *tex_image, GLuint slice) { 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->cmt; 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.h b/src/mesa/drivers/dri/i965/intel_tex.h index 4c48875f82..1131ea6009 100644 --- a/src/mesa/drivers/dri/i965/intel_tex.h +++ b/src/mesa/drivers/dri/i965/intel_tex.h @@ -54,5 +54,4 @@ intel_miptree_create_for_teximage(struct brw_context *brw, void intel_finalize_mipmap_tree(struct brw_context *brw, struct gl_texture_object *tex_obj); - #endif diff --git a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c index fae179214d..5cb8adcb7e 100644 --- a/src/mesa/drivers/dri/i965/intel_tex_image.c +++ b/src/mesa/drivers/dri/i965/intel_tex_image.c @@ -860,7 +860,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, @@ -904,6 +904,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, @@ -914,7 +956,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/drivers/dri/i965/intel_tex_obj.h b/src/mesa/drivers/dri/i965/intel_tex_obj.h index 526f5ceb47..ce4b7a0d36 100644 --- a/src/mesa/drivers/dri/i965/intel_tex_obj.h +++ b/src/mesa/drivers/dri/i965/intel_tex_obj.h @@ -50,6 +50,11 @@ struct intel_texture_object */ struct intel_mipmap_tree *mt; + /* This miptree is used to store the compressed ETC2/EAC pixels + * on Gen 7 GPUs for GetCompressed* functions to work. + */ + struct intel_mipmap_tree *cmt; + /** * Set when mipmap trees in the texture images of this texture object * might not all be the mipmap tree above. @@ -79,6 +84,9 @@ struct intel_texture_image * Else there is no image data. */ struct intel_mipmap_tree *mt; + + /* Stores the ETC2 formatted image on Gen7 GPUs */ + struct intel_mipmap_tree *cmt; }; static inline struct intel_texture_object * diff --git a/src/mesa/main/texstore.c b/src/mesa/main/texstore.c index 31163f6771..b441e15852 100644 --- a/src/mesa/main/texstore.c +++ b/src/mesa/main/texstore.c @@ -1328,10 +1328,7 @@ _mesa_store_compressed_texsubimage(struct gl_context *ctx, GLuint dims, 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 +1346,59 @@ _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); - for (slice = 0; slice < store.CopySlices; slice++) { + _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; + + 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, + 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..4b197e1641 100644 --- a/src/mesa/main/texstore.h +++ b/src/mesa/main/texstore.h @@ -148,7 +148,6 @@ _mesa_store_compressed_texsubimage(struct gl_context *ctx, GLuint dims, GLenum format, GLsizei imageSize, const GLvoid *data); - struct compressed_pixelstore { int SkipBytes; int CopyBytesPerRow; @@ -158,6 +157,13 @@ 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.17.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev