#include "main/core.h"
#include "main/context.h"
-#include "ir.h"
-#include "ir_uniform.h"
-#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"
+#include "main/uniforms.h"
+#include "compiler/glsl/ir.h"
+#include "compiler/glsl/ir_uniform.h"
+#include "compiler/glsl/glsl_parser_extras.h"
+#include "compiler/glsl/program.h"
+#include "program/hash_table.h"
+#include "util/bitscan.h"
extern "C" void GLAPIENTRY
res_prop = resource_prop_from_uniform_prop(pname);
+ /* We need to first verify that each entry exists as active uniform. If
+ * not, generate error and do not cause any other side effects.
+ *
+ * In the case of and error condition, Page 16 (section 2.3.1 Errors)
+ * of the OpenGL 4.5 spec says:
+ *
+ * "If the generating command modifies values through a pointer argu-
+ * ment, no change is made to these values."
+ */
for (int i = 0; i < uniformCount; i++) {
- res = _mesa_program_resource_find_index(shProg, GL_UNIFORM,
- uniformIndices[i]);
- if (!res) {
+ if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM,
+ uniformIndices[i])) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)");
- break;
+ return;
}
+ }
+ for (int i = 0; i < uniformCount; i++) {
+ res = _mesa_program_resource_find_index(shProg, GL_UNIFORM,
+ uniformIndices[i]);
if (!_mesa_program_resource_prop(shProg, res, uniformIndices[i],
res_prop, ¶ms[i],
"glGetActiveUniformsiv"))
struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location];
+ /* Even though no location is assigned to a built-in uniform and this
+ * function should already have returned NULL, this test makes it explicit
+ * that we are not allowing to update the value of a built-in.
+ */
+ if (uni->builtin)
+ return NULL;
+
if (uni->array_elements == 0) {
if (count > 1) {
_mesa_error(ctx, GL_INVALID_OPERATION,
{
unsigned elements = (uni->type->is_sampler())
? 1 : uni->type->components();
+ const int dmul = uni->type->is_64bit() ? 2 : 1;
+ const int rmul = glsl_base_type_is_64bit(returnType) ? 2 : 1;
/* Calculate the source base address *BEFORE* modifying elements to
* account for the size of the user's buffer.
*/
const union gl_constant_value *const src =
- &uni->storage[offset * elements];
+ &uni->storage[offset * elements * dmul];
assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT ||
- returnType == GLSL_TYPE_UINT);
- /* The three (currently) supported types all have the same size,
- * which is of course the same as their union. That'll change
- * with glGetUniformdv()...
- */
- unsigned bytes = sizeof(src[0]) * elements;
+ returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_DOUBLE);
+
+ /* doubles have a different size than the other 3 types */
+ unsigned bytes = sizeof(src[0]) * elements * rmul;
if (bufSize < 0 || bytes > (unsigned) bufSize) {
_mesa_error( ctx, GL_INVALID_OPERATION,
"glGetnUniform*vARB(out of bounds: bufSize is %d,"
&&
(uni->type->base_type == GLSL_TYPE_INT
|| uni->type->base_type == GLSL_TYPE_UINT
- || uni->type->base_type == GLSL_TYPE_SAMPLER))) {
+ || uni->type->base_type == GLSL_TYPE_SAMPLER
+ || uni->type->base_type == GLSL_TYPE_IMAGE))) {
memcpy(paramsOut, src, bytes);
} else {
union gl_constant_value *const dst =
(union gl_constant_value *) paramsOut;
-
/* This code could be optimized by putting the loop inside the switch
* statements. However, this is not expected to be
* performance-critical code.
*/
for (unsigned i = 0; i < elements; i++) {
+ int sidx = i * dmul;
+ int didx = i * rmul;
+
switch (returnType) {
case GLSL_TYPE_FLOAT:
switch (uni->type->base_type) {
case GLSL_TYPE_UINT:
- dst[i].f = (float) src[i].u;
+ dst[didx].f = (float) src[sidx].u;
break;
case GLSL_TYPE_INT:
case GLSL_TYPE_SAMPLER:
- dst[i].f = (float) src[i].i;
+ case GLSL_TYPE_IMAGE:
+ dst[didx].f = (float) src[sidx].i;
break;
case GLSL_TYPE_BOOL:
- dst[i].f = src[i].i ? 1.0f : 0.0f;
+ dst[didx].f = src[sidx].i ? 1.0f : 0.0f;
+ break;
+ case GLSL_TYPE_DOUBLE: {
+ double tmp;
+ memcpy(&tmp, &src[sidx].f, sizeof(tmp));
+ dst[didx].f = tmp;
break;
+ }
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+ case GLSL_TYPE_DOUBLE:
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_UINT: {
+ double tmp = src[sidx].u;
+ memcpy(&dst[didx].f, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_IMAGE: {
+ double tmp = src[sidx].i;
+ memcpy(&dst[didx].f, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_BOOL: {
+ double tmp = src[sidx].i ? 1.0 : 0.0;
+ memcpy(&dst[didx].f, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_FLOAT: {
+ double tmp = src[sidx].f;
+ memcpy(&dst[didx].f, &tmp, sizeof(tmp));
+ break;
+ }
default:
assert(!"Should not get here.");
break;
}
break;
-
case GLSL_TYPE_INT:
case GLSL_TYPE_UINT:
switch (uni->type->base_type) {
* a floating-point value is rounded to the
* nearest integer..."
*/
- dst[i].i = IROUND(src[i].f);
+ dst[didx].i = IROUND(src[sidx].f);
break;
case GLSL_TYPE_BOOL:
- dst[i].i = src[i].i ? 1 : 0;
+ dst[didx].i = src[sidx].i ? 1 : 0;
break;
+ case GLSL_TYPE_DOUBLE: {
+ double tmp;
+ memcpy(&tmp, &src[sidx].f, sizeof(tmp));
+ dst[didx].i = IROUNDD(tmp);
+ break;
+ }
default:
assert(!"Should not get here.");
break;
case GLSL_TYPE_FLOAT:
printf("%g ", v[i].f);
break;
- case GLSL_TYPE_DOUBLE:
- printf("%g ", *(double* )&v[i * 2].f);
+ case GLSL_TYPE_DOUBLE: {
+ double tmp;
+ memcpy(&tmp, &v[i * 2].f, sizeof(tmp));
+ printf("%g ", tmp);
break;
+ }
default:
assert(!"Should not get here.");
break;
*/
const unsigned components = MAX2(1, uni->type->vector_elements);
const unsigned vectors = MAX2(1, uni->type->matrix_columns);
- const int dmul = uni->type->base_type == GLSL_TYPE_DOUBLE ? 2 : 1;
+ const int dmul = uni->type->is_64bit() ? 2 : 1;
/* Store the data in the driver's requested type in the driver's storage
* areas.
unsigned j;
unsigned v;
- for (j = 0; j < count; j++) {
- for (v = 0; v < vectors; v++) {
- memcpy(dst, src, src_vector_byte_stride);
- src += src_vector_byte_stride;
- dst += store->vector_stride;
+ if (src_vector_byte_stride == store->vector_stride) {
+ if (extra_stride) {
+ for (j = 0; j < count; j++) {
+ memcpy(dst, src, src_vector_byte_stride * vectors);
+ src += src_vector_byte_stride * vectors;
+ dst += store->vector_stride * vectors;
+
+ dst += extra_stride;
+ }
+ } else {
+ /* Unigine Heaven benchmark gets here */
+ memcpy(dst, src, src_vector_byte_stride * vectors * count);
+ src += src_vector_byte_stride * vectors * count;
+ dst += store->vector_stride * vectors * count;
}
+ } else {
+ for (j = 0; j < count; j++) {
+ for (v = 0; v < vectors; v++) {
+ memcpy(dst, src, src_vector_byte_stride);
+ src += src_vector_byte_stride;
+ dst += store->vector_stride;
+ }
- dst += extra_stride;
+ dst += extra_stride;
+ }
}
break;
}
unsigned src_components)
{
unsigned offset;
- int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;
+ int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1;
struct gl_uniform_storage *const uni =
validate_uniform_parameters(ctx, shProg, location, count,
match = (basicType != GLSL_TYPE_DOUBLE);
break;
case GLSL_TYPE_SAMPLER:
- case GLSL_TYPE_IMAGE:
match = (basicType == GLSL_TYPE_INT);
break;
+ case GLSL_TYPE_IMAGE:
+ match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx));
+ break;
default:
match = (basicType == uni->type->base_type);
break;
return;
}
}
+ /* We need to reset the validate flag on changes to samplers in case
+ * two different sampler types are set to the same texture unit.
+ */
+ ctx->_Shader->Validated = GL_FALSE;
}
if (uni->type->is_image()) {
}
}
- uni->initialized = true;
-
_mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
/* If the uniform is a sampler, do the extra magic necessary to propagate
if (uni->type->is_sampler()) {
bool flushed = false;
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
- struct gl_shader *const sh = shProg->_LinkedShaders[i];
+ struct gl_linked_shader *const sh = shProg->_LinkedShaders[i];
/* If the shader stage doesn't use the sampler uniform, skip this.
*/
- if (sh == NULL || !uni->sampler[i].active)
+ if (sh == NULL || !uni->opaque[i].active)
continue;
for (int j = 0; j < count; j++) {
- sh->SamplerUnits[uni->sampler[i].index + offset + j] =
+ sh->SamplerUnits[uni->opaque[i].index + offset + j] =
((unsigned *) values)[j];
}
* been modified.
*/
bool changed = false;
- for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) {
- if ((sh->active_samplers & (1U << j)) != 0
- && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) {
+ GLbitfield mask = sh->active_samplers;
+ while (mask) {
+ const int j = u_bit_scan(&mask);
+ if (prog->SamplerUnits[j] != sh->SamplerUnits[j]) {
changed = true;
break;
}
flushed = true;
}
- memcpy(prog->SamplerUnits,
- sh->SamplerUnits,
- sizeof(sh->SamplerUnits));
-
_mesa_update_shader_textures_used(shProg, prog);
if (ctx->Driver.SamplerUniformChange)
ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
*/
if (uni->type->is_image()) {
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
- if (uni->image[i].active) {
- struct gl_shader *sh = shProg->_LinkedShaders[i];
+ if (uni->opaque[i].active) {
+ struct gl_linked_shader *sh = shProg->_LinkedShaders[i];
for (int j = 0; j < count; j++)
- sh->ImageUnits[uni->image[i].index + offset + j] =
+ sh->ImageUnits[uni->opaque[i].index + offset + j] =
((GLint *) values)[j];
}
}
GLuint cols, GLuint rows,
GLint location, GLsizei count,
GLboolean transpose,
- const GLvoid *values, GLenum type)
+ const GLvoid *values, enum glsl_base_type basicType)
{
unsigned offset;
unsigned vectors;
return;
}
- assert(type == GL_FLOAT || type == GL_DOUBLE);
- size_mul = type == GL_DOUBLE ? 2 : 1;
+ assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE);
+ size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;
assert(!uni->type->is_sampler());
vectors = uni->type->matrix_columns;
}
}
+ /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec
+ * says:
+ *
+ * "If any of the following conditions occur, an INVALID_OPERATION
+ * error is generated by the Uniform* commands, and no uniform values
+ * are changed:
+ *
+ * ...
+ *
+ * - if the uniform declared in the shader is not of type boolean and
+ * the type indicated in the name of the Uniform* command used does
+ * not match the type of the uniform"
+ *
+ * There are no Boolean matrix types, so we do not need to allow
+ * GLSL_TYPE_BOOL here (as _mesa_uniform does).
+ */
+ if (uni->type->base_type != basicType) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)",
+ cols, rows, uni->name, location,
+ glsl_type_name(uni->type->base_type),
+ glsl_type_name(basicType));
+ return;
+ }
+
if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
log_uniform(values, uni->type->base_type, components, vectors, count,
bool(transpose), shProg, location, uni);
elements = components * vectors;
if (!transpose) {
- memcpy(&uni->storage[elements * offset], values,
+ memcpy(&uni->storage[size_mul * elements * offset], values,
sizeof(uni->storage[0]) * elements * count * size_mul);
- } else if (type == GL_FLOAT) {
+ } else if (basicType == GLSL_TYPE_FLOAT) {
/* Copy and transpose the matrix.
*/
const float *src = (const float *)values;
src += elements;
}
} else {
- assert(type == GL_DOUBLE);
+ assert(basicType == GLSL_TYPE_DOUBLE);
const double *src = (const double *)values;
double *dst = (double *)&uni->storage[elements * offset].f;
}
}
- uni->initialized = true;
-
_mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
}
-/**
- * Called via glGetUniformLocation().
- *
- * Returns the uniform index into UniformStorage (also the
- * glGetActiveUniformsiv uniform index), and stores the referenced
- * array offset in *offset, or GL_INVALID_INDEX (-1).
- */
-extern "C" unsigned
-_mesa_get_uniform_location(struct gl_shader_program *shProg,
- const GLchar *name,
- unsigned *out_offset)
-{
- /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says:
- *
- * "The first element of a uniform array is identified using the
- * name of the uniform array appended with "[0]". Except if the last
- * part of the string name indicates a uniform array, then the
- * location of the first element of that array can be retrieved by
- * either using the name of the uniform array, or the name of the
- * uniform array appended with "[0]"."
- *
- * Note: since uniform names are not allowed to use whitespace, and array
- * indices within uniform names are not allowed to use "+", "-", or leading
- * zeros, it follows that each uniform has a unique name up to the possible
- * ambiguity with "[0]" noted above. Therefore we don't need to worry
- * about mal-formed inputs--they will properly fail when we try to look up
- * the uniform name in shProg->UniformHash.
- */
-
- const GLchar *base_name_end;
- long offset = parse_program_resource_name(name, &base_name_end);
- bool array_lookup = offset >= 0;
- char *name_copy;
-
- if (array_lookup) {
- name_copy = (char *) malloc(base_name_end - name + 1);
- memcpy(name_copy, name, base_name_end - name);
- name_copy[base_name_end - name] = '\0';
- } else {
- name_copy = (char *) name;
- offset = 0;
- }
-
- unsigned location = 0;
- const bool found = shProg->UniformHash->get(location, name_copy);
-
- assert(!found
- || strcmp(name_copy, shProg->UniformStorage[location].name) == 0);
-
- /* Free the temporary buffer *before* possibly returning an error.
- */
- if (name_copy != name)
- free(name_copy);
-
- if (!found)
- return GL_INVALID_INDEX;
-
- /* If the uniform is an array, fail if the index is out of bounds.
- * (A negative index is caught above.) This also fails if the uniform
- * is not an array, but the user is trying to index it, because
- * array_elements is zero and offset >= 0.
- */
- if (array_lookup
- && offset >= (long) shProg->UniformStorage[location].array_elements) {
- return GL_INVALID_INDEX;
- }
-
- *out_offset = offset;
- return location;
-}
-
extern "C" bool
_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
char *errMsg, size_t errMsgLength)
{
/* Shader does not have samplers. */
- if (shProg->NumUserUniformStorage == 0)
+ if (shProg->NumUniformStorage == 0)
return true;
if (!shProg->SamplersValidated) {
* - The number of active samplers in the program exceeds the
* maximum number of texture image units allowed."
*/
+
+ GLbitfield mask;
+ GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+ struct gl_linked_shader *shader;
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));
+
+ memset(TexturesUsed, 0, sizeof(TexturesUsed));
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;
+ shader = shProg[idx]->_LinkedShaders[idx];
+ if (!shader || !shader->Program)
+ continue;
- if (!t->is_sampler())
+ mask = shader->Program->SamplersUsed;
+ while (mask) {
+ const int s = u_bit_scan(&mask);
+ GLuint unit = shader->SamplerUnits[s];
+ GLuint tgt = shader->SamplerTargets[s];
+
+ /* FIXME: Samplers are initialized to 0 and Mesa doesn't do a
+ * great job of eliminating unused uniforms currently so for now
+ * don't throw an error if two sampler types both point to 0.
+ */
+ if (unit == 0)
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 (TexturesUsed[unit] & ~(1 << tgt)) {
+ pipeline->InfoLog =
+ ralloc_asprintf(pipeline,
+ "Program %d: "
+ "Texture unit %d is accessed with 2 different types",
+ shProg[idx]->Name, unit);
+ return false;
}
+
+ TexturesUsed[unit] |= (1 << tgt);
}
+
+ active_samplers += shader->num_samplers;
}
if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) {