mesa: (more) correctly handle incomplete depth textures

according to GL spec, incomplete shadow samplers should return 0

this is technically possible for drivers to do using a RGBA texture in
the sense that somehow it's been working, but it's broken at the gallium-level
for what drivers should be expecting to see in such circumstances given
that such scenarios have been binding a RGBA texture to use with shadow samplers

instead, we can give drivers a fallback Z32 texture to avoid format/sampler
mismatches and complying with expected behavior

see also KHR-GL46.incomplete_texture_access.sampler for driver-specific testing

Reviewed-by: Emma Anholt <emma@anholt.net>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20817>
This commit is contained in:
Mike Blumenkrantz
2023-01-20 14:53:32 -05:00
committed by Marge Bot
parent 818cc30852
commit 0c6e56c391
6 changed files with 37 additions and 22 deletions

View File

@@ -2413,7 +2413,7 @@ struct gl_shared_state
struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS];
/** Fallback texture used when a bound texture is incomplete */
struct gl_texture_object *FallbackTex[NUM_TEXTURE_TARGETS];
struct gl_texture_object *FallbackTex[NUM_TEXTURE_TARGETS][2]; /**< [color, depth] */
/**
* \name Thread safety and statechange notification for texture

View File

@@ -335,8 +335,10 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)
/* Free the dummy/fallback texture objects */
for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
if (shared->FallbackTex[i])
_mesa_delete_texture_object(ctx, shared->FallbackTex[i]);
for (unsigned j = 0; j < ARRAY_SIZE(shared->FallbackTex[0]); j++) {
if (shared->FallbackTex[i][j])
_mesa_delete_texture_object(ctx, shared->FallbackTex[i][j]);
}
}
/*

View File

@@ -974,14 +974,15 @@ _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj)
/**
* Return pointer to a default/fallback texture of the given type/target.
* The texture is an RGBA texture with all texels = (0,0,0,1).
* The texture is an RGBA texture with all texels = (0,0,0,1) OR
* a depth texture that returns 0.
* That's the value a GLSL sampler should get when sampling from an
* incomplete texture.
*/
struct gl_texture_object *
_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex, bool is_depth)
{
if (!ctx->Shared->FallbackTex[tex]) {
if (!ctx->Shared->FallbackTex[tex][is_depth]) {
/* create fallback texture now */
const GLsizei width = 1, height = 1;
GLsizei depth = 1;
@@ -1067,9 +1068,14 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
texObj->Sampler.Attrib.state.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
texObj->Sampler.Attrib.state.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
texFormat = st_ChooseTextureFormat(ctx, target,
GL_RGBA, GL_RGBA,
GL_UNSIGNED_BYTE);
if (is_depth)
texFormat = st_ChooseTextureFormat(ctx, target,
GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT,
GL_NONE);
else
texFormat = st_ChooseTextureFormat(ctx, target,
GL_RGBA, GL_RGBA,
GL_UNSIGNED_BYTE);
/* need a loop here just for cube maps */
for (face = 0; face < numFaces; face++) {
@@ -1083,24 +1089,29 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
(dims > 1) ? height : 1,
(dims > 2) ? depth : 1,
0, /* border */
GL_RGBA, texFormat);
is_depth ? GL_DEPTH_COMPONENT : GL_RGBA, texFormat);
_mesa_update_texture_object_swizzle(ctx, texObj);
st_TexImage(ctx, dims, texImage,
GL_RGBA, GL_UNSIGNED_BYTE, texel,
&ctx->DefaultPacking);
if (is_depth)
st_TexImage(ctx, dims, texImage,
GL_DEPTH_COMPONENT, GL_FLOAT, texel,
&ctx->DefaultPacking);
else
st_TexImage(ctx, dims, texImage,
GL_RGBA, GL_UNSIGNED_BYTE, texel,
&ctx->DefaultPacking);
}
_mesa_test_texobj_completeness(ctx, texObj);
assert(texObj->_BaseComplete);
assert(texObj->_MipmapComplete);
ctx->Shared->FallbackTex[tex] = texObj;
ctx->Shared->FallbackTex[tex][is_depth] = texObj;
/* Complete the driver's operation in case another context will also
* use the same fallback texture. */
st_glFinish(ctx);
}
return ctx->Shared->FallbackTex[tex];
return ctx->Shared->FallbackTex[tex][is_depth];
}

View File

@@ -186,7 +186,7 @@ extern void
_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj);
extern struct gl_texture_object *
_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex);
_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex, bool is_depth);
extern GLuint
_mesa_total_texture_memory(struct gl_context *ctx);

View File

@@ -704,7 +704,7 @@ update_single_program_texture(struct gl_context *ctx, struct gl_program *prog,
* Mesa implements this by creating a hidden texture object with a pixel of
* that value.
*/
texObj = _mesa_get_fallback_texture(ctx, target_index);
texObj = _mesa_get_fallback_texture(ctx, target_index, !!(prog->ShadowSamplers & BITFIELD_BIT(unit)));
assert(texObj);
return texObj;
@@ -870,7 +870,7 @@ fix_missing_textures_for_atifs(struct gl_context *ctx,
if (!ctx->Texture.Unit[unit]._Current) {
struct gl_texture_object *texObj =
_mesa_get_fallback_texture(ctx, target_index);
_mesa_get_fallback_texture(ctx, target_index, false);
_mesa_reference_texobj(&ctx->Texture.Unit[unit]._Current, texObj);
BITSET_SET(enabled_texture_units, unit);
ctx->Texture._MaxEnabledTexImageUnit =

View File

@@ -944,10 +944,12 @@ st_destroy_context(struct st_context *st)
* context.
*/
for (unsigned i = 0; i < NUM_TEXTURE_TARGETS; i++) {
struct gl_texture_object *stObj =
ctx->Shared->FallbackTex[i];
if (stObj) {
st_texture_release_context_sampler_view(st, stObj);
for (unsigned j = 0; j < ARRAY_SIZE(ctx->Shared->FallbackTex[0]); j++) {
struct gl_texture_object *stObj =
ctx->Shared->FallbackTex[i][j];
if (stObj) {
st_texture_release_context_sampler_view(st, stObj);
}
}
}