#include "program/hash_table.h"
#include "../glsl/program.h"
#include "../glsl/ir_uniform.h"
+#include "../glsl/glsl_parser_extras.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "uniforms.h"
extern "C" void GLAPIENTRY
-_mesa_GetActiveUniform(GLhandleARB program, GLuint index,
- GLsizei maxLength, GLsizei *length, GLint *size,
- GLenum *type, GLcharARB *nameOut)
+_mesa_GetActiveUniform(GLuint program, GLuint index,
+ GLsizei maxLength, GLsizei *length, GLint *size,
+ GLenum *type, GLcharARB *nameOut)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_shader_program *shProg =
if (uniformCount < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glGetUniformIndices(uniformCount < 0)");
+ "glGetActiveUniformsiv(uniformCount < 0)");
return;
}
params[i] = uni->row_major;
break;
+ case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX:
+ if (!ctx->Extensions.ARB_shader_atomic_counters)
+ goto invalid_enum;
+ params[i] = uni->atomic_buffer_index;
+ break;
+
default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)");
- return;
+ goto invalid_enum;
}
}
+
+ return;
+
+ invalid_enum:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)");
}
-static bool
+static struct gl_uniform_storage *
validate_uniform_parameters(struct gl_context *ctx,
struct gl_shader_program *shProg,
GLint location, GLsizei count,
- unsigned *loc,
unsigned *array_index,
const char *caller,
bool negative_one_is_not_valid)
{
if (!shProg || !shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller);
- return false;
+ return NULL;
}
if (location == -1) {
caller, location);
}
- return false;
+ return NULL;
}
/* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec:
*/
if (count < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller);
- return false;
+ return NULL;
}
/* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
if (location < -1) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
caller, location);
- return false;
+ return NULL;
}
- _mesa_uniform_split_location_offset(location, loc, array_index);
-
- if (*loc >= shProg->NumUserUniformStorage) {
+ /* Check that the given location is in bounds of uniform remap table. */
+ if (location >= (GLint) shProg->NumUniformRemapTable) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
caller, location);
- return false;
+ return NULL;
}
- if (shProg->UniformStorage[*loc].array_elements == 0 && count > 1) {
+ /* If the driver storage pointer in remap table is -1, we ignore silently.
+ *
+ * GL_ARB_explicit_uniform_location spec says:
+ * "What happens if Uniform* is called with an explicitly defined
+ * uniform location, but that uniform is deemed inactive by the
+ * linker?
+ *
+ * RESOLVED: The call is ignored for inactive uniform variables and
+ * no error is generated."
+ *
+ */
+ if (shProg->UniformRemapTable[location] ==
+ INACTIVE_UNIFORM_EXPLICIT_LOCATION)
+ return NULL;
+
+ unsigned loc;
+ _mesa_uniform_split_location_offset(shProg, location, &loc, array_index);
+ struct gl_uniform_storage *const uni = &shProg->UniformStorage[loc];
+
+ if (uni->array_elements == 0 && count > 1) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(count > 1 for non-array, location=%d)",
caller, location);
- return false;
+ return NULL;
}
/* If the uniform is an array, check that array_index is in bounds.
* If not an array, check that array_index is zero.
* array_index is unsigned so no need to check for less than zero.
*/
- unsigned limit = shProg->UniformStorage[*loc].array_elements;
- if (limit == 0)
- limit = 1;
+ const unsigned limit = MAX2(uni->array_elements, 1);
if (*array_index >= limit) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
caller, location);
- return false;
+ return NULL;
}
- return true;
+ return uni;
}
/**
{
struct gl_shader_program *shProg =
_mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv");
- struct gl_uniform_storage *uni;
- unsigned loc, offset;
+ unsigned offset;
- if (!validate_uniform_parameters(ctx, shProg, location, 1,
- &loc, &offset, "glGetUniform", true))
+ struct gl_uniform_storage *const uni =
+ validate_uniform_parameters(ctx, shProg, location, 1,
+ &offset, "glGetUniform", true);
+ if (uni == NULL)
return;
- uni = &shProg->UniformStorage[loc];
-
{
unsigned elements = (uni->type->is_sampler())
? 1 : uni->type->components();
static void
log_program_parameters(const struct gl_shader_program *shProg)
{
- static const char *stages[] = {
- "vertex", "fragment", "geometry"
- };
-
- assert(Elements(stages) == MESA_SHADER_TYPES);
-
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
if (shProg->_LinkedShaders[i] == NULL)
continue;
const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program;
printf("Program %d %s shader parameters:\n",
- shProg->Name, stages[i]);
+ shProg->Name, _mesa_shader_stage_to_string(i));
for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) {
printf("%s: %p %f %f %f %f\n",
prog->Parameters->Parameters[j].Name,
GLint location, GLsizei count,
const GLvoid *values, GLenum type)
{
- unsigned loc, offset;
+ unsigned offset;
unsigned components;
unsigned src_components;
enum glsl_base_type basicType;
- struct gl_uniform_storage *uni;
- if (!validate_uniform_parameters(ctx, shProg, location, count,
- &loc, &offset, "glUniform", false))
+ struct gl_uniform_storage *const uni =
+ validate_uniform_parameters(ctx, shProg, location, count,
+ &offset, "glUniform", false);
+ if (uni == NULL)
return;
- uni = &shProg->UniformStorage[loc];
-
/* Verify that the types are compatible.
*/
switch (type) {
match = true;
break;
case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_IMAGE:
match = (basicType == GLSL_TYPE_INT);
break;
default:
return;
}
- if (ctx->Shader.Flags & GLSL_UNIFORMS) {
+ if (ctx->_Shader->Flags & GLSL_UNIFORMS) {
log_uniform(values, basicType, components, 1, count,
false, shProg, location, uni);
}
}
}
+ if (uni->type->is_image()) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ const int unit = ((GLint *) values)[i];
+
+ /* check that the image unit is legal */
+ if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glUniform1i(invalid image unit index for uniform %d)",
+ location);
+ return;
+ }
+ }
+ }
+
/* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
*
* "When loading N elements starting at an arbitrary position k in a
if (uni->type->is_sampler()) {
int i;
- for (i = 0; i < count; i++) {
- shProg->SamplerUnits[uni->sampler + offset + i] =
- ((unsigned *) values)[i];
- }
-
bool flushed = false;
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
struct gl_shader *const sh = shProg->_LinkedShaders[i];
+ int j;
- /* If the shader stage doesn't use any samplers, don't bother
- * checking if any samplers have changed.
+ /* If the shader stage doesn't use the sampler uniform, skip this.
*/
- if (sh == NULL || sh->active_samplers == 0)
+ if (sh == NULL || !uni->sampler[i].active)
continue;
+ for (j = 0; j < count; j++) {
+ sh->SamplerUnits[uni->sampler[i].index + offset + j] =
+ ((unsigned *) values)[j];
+ }
+
struct gl_program *const prog = sh->Program;
- assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits));
+ assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits));
/* Determine if any of the samplers used by this shader stage have
* been modified.
bool changed = false;
for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) {
if ((sh->active_samplers & (1U << j)) != 0
- && (prog->SamplerUnits[j] != shProg->SamplerUnits[j])) {
+ && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) {
changed = true;
break;
}
}
memcpy(prog->SamplerUnits,
- shProg->SamplerUnits,
- sizeof(shProg->SamplerUnits));
+ sh->SamplerUnits,
+ sizeof(sh->SamplerUnits));
_mesa_update_shader_textures_used(shProg, prog);
if (ctx->Driver.SamplerUniformChange)
}
}
}
+
+ /* If the uniform is an image, update the mapping from image
+ * uniforms to image units present in the shader data structure.
+ */
+ if (uni->type->is_image()) {
+ int i, j;
+
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (uni->image[i].active) {
+ struct gl_shader *sh = shProg->_LinkedShaders[i];
+
+ for (j = 0; j < count; j++)
+ sh->ImageUnits[uni->image[i].index + offset + j] =
+ ((GLint *) values)[j];
+ }
+ }
+
+ ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;
+ }
}
/**
GLint location, GLsizei count,
GLboolean transpose, const GLfloat *values)
{
- unsigned loc, offset;
+ unsigned offset;
unsigned vectors;
unsigned components;
unsigned elements;
- struct gl_uniform_storage *uni;
- if (!validate_uniform_parameters(ctx, shProg, location, count,
- &loc, &offset, "glUniformMatrix", false))
+ struct gl_uniform_storage *const uni =
+ validate_uniform_parameters(ctx, shProg, location, count,
+ &offset, "glUniformMatrix", false);
+ if (uni == NULL)
return;
- uni = &shProg->UniformStorage[loc];
if (!uni->type->is_matrix()) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUniformMatrix(non-matrix uniform)");
}
}
- if (ctx->Shader.Flags & GLSL_UNIFORMS) {
+ if (ctx->_Shader->Flags & GLSL_UNIFORMS) {
log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count,
bool(transpose), shProg, location, uni);
}
return true;
}
+
+extern "C" bool
+_mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline)
+{
+ /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+ * OpenGL 4.1 spec says:
+ *
+ * "[INVALID_OPERATION] is generated by any command that transfers
+ * vertices to the GL if:
+ *
+ * ...
+ *
+ * - Any two active samplers in the current program object are of
+ * different types, but refer to the same texture image unit.
+ *
+ * - The number of active samplers in the program exceeds the
+ * maximum number of texture image units allowed."
+ */
+ unsigned active_samplers = 0;
+ const struct gl_shader_program **shProg =
+ (const struct gl_shader_program **) pipeline->CurrentProgram;
+
+ const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+ memset(unit_types, 0, sizeof(unit_types));
+
+ for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) {
+ if (!shProg[idx])
+ continue;
+
+ for (unsigned i = 0; i < shProg[idx]->NumUserUniformStorage; i++) {
+ const struct gl_uniform_storage *const storage =
+ &shProg[idx]->UniformStorage[i];
+ const glsl_type *const t = (storage->type->is_array())
+ ? storage->type->fields.array : storage->type;
+
+ if (!t->is_sampler())
+ continue;
+
+ active_samplers++;
+
+ 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) {
+ pipeline->InfoLog =
+ ralloc_asprintf(pipeline,
+ "Texture unit %d is accessed both as %s "
+ "and %s",
+ unit, unit_types[unit]->name, t->name);
+ return false;
+ }
+ }
+ }
+ }
+
+ if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) {
+ pipeline->InfoLog =
+ ralloc_asprintf(pipeline,
+ "the number of active samplers %d exceed the "
+ "maximum %d",
+ active_samplers, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ return false;
+ }
+
+ return true;
+}