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]; struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS];
/** Fallback texture used when a bound texture is incomplete */ /** 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 * \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 */ /* Free the dummy/fallback texture objects */
for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
if (shared->FallbackTex[i]) for (unsigned j = 0; j < ARRAY_SIZE(shared->FallbackTex[0]); j++) {
_mesa_delete_texture_object(ctx, shared->FallbackTex[i]); 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. * 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 * That's the value a GLSL sampler should get when sampling from an
* incomplete texture. * incomplete texture.
*/ */
struct gl_texture_object * 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 */ /* create fallback texture now */
const GLsizei width = 1, height = 1; const GLsizei width = 1, height = 1;
GLsizei depth = 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.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
texObj->Sampler.Attrib.state.mag_img_filter = PIPE_TEX_FILTER_NEAREST; texObj->Sampler.Attrib.state.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
texFormat = st_ChooseTextureFormat(ctx, target, if (is_depth)
GL_RGBA, GL_RGBA, texFormat = st_ChooseTextureFormat(ctx, target,
GL_UNSIGNED_BYTE); 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 */ /* need a loop here just for cube maps */
for (face = 0; face < numFaces; face++) { 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 > 1) ? height : 1,
(dims > 2) ? depth : 1, (dims > 2) ? depth : 1,
0, /* border */ 0, /* border */
GL_RGBA, texFormat); is_depth ? GL_DEPTH_COMPONENT : GL_RGBA, texFormat);
_mesa_update_texture_object_swizzle(ctx, texObj); _mesa_update_texture_object_swizzle(ctx, texObj);
st_TexImage(ctx, dims, texImage, if (is_depth)
GL_RGBA, GL_UNSIGNED_BYTE, texel, st_TexImage(ctx, dims, texImage,
&ctx->DefaultPacking); 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); _mesa_test_texobj_completeness(ctx, texObj);
assert(texObj->_BaseComplete); assert(texObj->_BaseComplete);
assert(texObj->_MipmapComplete); 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 /* Complete the driver's operation in case another context will also
* use the same fallback texture. */ * use the same fallback texture. */
st_glFinish(ctx); 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); _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj);
extern struct gl_texture_object * 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 extern GLuint
_mesa_total_texture_memory(struct gl_context *ctx); _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 * Mesa implements this by creating a hidden texture object with a pixel of
* that value. * 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); assert(texObj);
return texObj; return texObj;
@ -870,7 +870,7 @@ fix_missing_textures_for_atifs(struct gl_context *ctx,
if (!ctx->Texture.Unit[unit]._Current) { if (!ctx->Texture.Unit[unit]._Current) {
struct gl_texture_object *texObj = 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); _mesa_reference_texobj(&ctx->Texture.Unit[unit]._Current, texObj);
BITSET_SET(enabled_texture_units, unit); BITSET_SET(enabled_texture_units, unit);
ctx->Texture._MaxEnabledTexImageUnit = ctx->Texture._MaxEnabledTexImageUnit =

View file

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