[Mesa-dev] [PATCH v6] i965: Fix ETC2/EAC GetCompressed* functions on Gen7 GPUs
Eleni Maria Stea
estea at igalia.com
Wed Jul 18 12:04:00 UTC 2018
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
More information about the mesa-dev
mailing list