mesa: Validate sampler settings using uniform storage
Rather than looking at the settings in individual assembly programs, look at the settings in the top-level uniform values. The old code was flawed because examining each shader stage in isolation could allow inconsitent usage across stages (e.g., bind unit 0 to a sampler2D in the vertex shader and sampler1DShadow in the fragment shader). Signed-off-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
@@ -927,62 +927,6 @@ _mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
|
|||||||
ctx->Driver.UseProgram(ctx, shProg);
|
ctx->Driver.UseProgram(ctx, shProg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate a program's samplers.
|
|
||||||
* Specifically, check that there aren't two samplers of different types
|
|
||||||
* pointing to the same texture unit.
|
|
||||||
* \return GL_TRUE if valid, GL_FALSE if invalid
|
|
||||||
*/
|
|
||||||
static GLboolean
|
|
||||||
validate_samplers(const struct gl_program *prog, char *errMsg)
|
|
||||||
{
|
|
||||||
static const char *targetName[] = {
|
|
||||||
"TEXTURE_BUFFER",
|
|
||||||
"TEXTURE_2D_ARRAY",
|
|
||||||
"TEXTURE_1D_ARRAY",
|
|
||||||
"TEXTURE_EXTERNAL",
|
|
||||||
"TEXTURE_CUBE",
|
|
||||||
"TEXTURE_3D",
|
|
||||||
"TEXTURE_RECT",
|
|
||||||
"TEXTURE_2D",
|
|
||||||
"TEXTURE_1D",
|
|
||||||
};
|
|
||||||
GLint targetUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
|
|
||||||
GLbitfield samplersUsed = prog->SamplersUsed;
|
|
||||||
GLuint i;
|
|
||||||
|
|
||||||
STATIC_ASSERT(Elements(targetName) == NUM_TEXTURE_TARGETS);
|
|
||||||
|
|
||||||
if (samplersUsed == 0x0)
|
|
||||||
return GL_TRUE;
|
|
||||||
|
|
||||||
for (i = 0; i < Elements(targetUsed); i++)
|
|
||||||
targetUsed[i] = -1;
|
|
||||||
|
|
||||||
/* walk over bits which are set in 'samplers' */
|
|
||||||
while (samplersUsed) {
|
|
||||||
GLuint unit;
|
|
||||||
gl_texture_index target;
|
|
||||||
GLint sampler = _mesa_ffs(samplersUsed) - 1;
|
|
||||||
assert(sampler >= 0);
|
|
||||||
assert(sampler < Elements(prog->SamplerUnits));
|
|
||||||
unit = prog->SamplerUnits[sampler];
|
|
||||||
target = prog->SamplerTargets[sampler];
|
|
||||||
if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
|
|
||||||
_mesa_snprintf(errMsg, 100,
|
|
||||||
"Texture unit %d is accessed both as %s and %s",
|
|
||||||
unit, targetName[targetUsed[unit]], targetName[target]);
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
|
||||||
targetUsed[unit] = target;
|
|
||||||
samplersUsed ^= (1 << sampler);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do validation of the given shader program.
|
* Do validation of the given shader program.
|
||||||
* \param errMsg returns error message if validation fails.
|
* \param errMsg returns error message if validation fails.
|
||||||
@@ -1018,12 +962,8 @@ validate_shader_program(const struct gl_shader_program *shProg,
|
|||||||
* Check: any two active samplers in the current program object are of
|
* Check: any two active samplers in the current program object are of
|
||||||
* different types, but refer to the same texture image unit,
|
* different types, but refer to the same texture image unit,
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < Elements(shProg->_LinkedShaders); i++) {
|
if (!_mesa_sampler_uniforms_are_valid(shProg, errMsg, 100))
|
||||||
if (shProg->_LinkedShaders[i]
|
return GL_FALSE;
|
||||||
&& !validate_samplers(shProg->_LinkedShaders[i]->Program, errMsg)) {
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GL_TRUE;
|
return GL_TRUE;
|
||||||
}
|
}
|
||||||
|
@@ -933,3 +933,46 @@ _mesa_get_uniform_location(struct gl_context *ctx,
|
|||||||
|
|
||||||
return _mesa_uniform_merge_location_offset(location, offset);
|
return _mesa_uniform_merge_location_offset(location, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" bool
|
||||||
|
_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
|
||||||
|
char *errMsg, size_t errMsgLength)
|
||||||
|
{
|
||||||
|
const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
|
||||||
|
|
||||||
|
memset(unit_types, 0, sizeof(unit_types));
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < shProg->NumUserUniformStorage; i++) {
|
||||||
|
const struct gl_uniform_storage *const storage =
|
||||||
|
&shProg->UniformStorage[i];
|
||||||
|
const glsl_type *const t = (storage->type->is_array())
|
||||||
|
? storage->type->fields.array : storage->type;
|
||||||
|
|
||||||
|
if (!t->is_sampler())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const unsigned count = MAX2(1, storage->type->array_size());
|
||||||
|
for (unsigned j = 0; j < count; j++) {
|
||||||
|
const unsigned unit = storage->storage[j].i;
|
||||||
|
|
||||||
|
/* The types of the samplers associated with a particular texture
|
||||||
|
* unit must be an exact match. Page 74 (page 89 of the PDF) of the
|
||||||
|
* OpenGL 3.3 core spec says:
|
||||||
|
*
|
||||||
|
* "It is not allowed to have variables of different sampler
|
||||||
|
* types pointing to the same texture image unit within a program
|
||||||
|
* object."
|
||||||
|
*/
|
||||||
|
if (unit_types[unit] == NULL) {
|
||||||
|
unit_types[unit] = t;
|
||||||
|
} else if (unit_types[unit] != t) {
|
||||||
|
_mesa_snprintf(errMsg, errMsgLength,
|
||||||
|
"Texture unit %d is accessed both as %s and %s",
|
||||||
|
unit, unit_types[unit]->name, t->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@@ -214,6 +214,9 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
|
|||||||
extern void
|
extern void
|
||||||
_mesa_update_shader_textures_used(struct gl_program *prog);
|
_mesa_update_shader_textures_used(struct gl_program *prog);
|
||||||
|
|
||||||
|
extern bool
|
||||||
|
_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
|
||||||
|
char *errMsg, size_t errMsgLength);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
_mesa_init_shader_uniform_dispatch(struct _glapi_table *exec);
|
_mesa_init_shader_uniform_dispatch(struct _glapi_table *exec);
|
||||||
|
Reference in New Issue
Block a user