X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Funiform_query.cpp;h=3108d348d6fa90f88137c97cae6ef1419a331504;hb=e70d0d22a2dccc1df2c88890a2964491cdafac94;hp=d36f5067cbd890db80dafe1e941bb0b8ef66a092;hpb=0ed3bffc0850758924c86509b6135dbe2f017a52;p=mesa.git diff --git a/src/mesa/main/uniform_query.cpp b/src/mesa/main/uniform_query.cpp index d36f5067cbd..3108d348d6f 100644 --- a/src/mesa/main/uniform_query.cpp +++ b/src/mesa/main/uniform_query.cpp @@ -28,15 +28,14 @@ #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 "util/bitscan.h" extern "C" void GLAPIENTRY @@ -46,6 +45,7 @@ _mesa_GetActiveUniform(GLuint program, GLuint index, { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; + struct gl_program_resource *res; if (maxLength < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(maxLength < 0)"); @@ -56,26 +56,51 @@ _mesa_GetActiveUniform(GLuint program, GLuint index, if (!shProg) return; - if (index >= shProg->NumUserUniformStorage) { + res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg, + GL_UNIFORM, index); + + if (!res) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); return; } - const struct gl_uniform_storage *const uni = &shProg->UniformStorage[index]; - - if (nameOut) { - _mesa_get_uniform_name(uni, maxLength, length, nameOut); - } - - if (size) { - /* array_elements is zero for non-arrays, but the API requires that 1 be - * returned. - */ - *size = MAX2(1, uni->array_elements); - } + if (nameOut) + _mesa_get_program_resource_name(shProg, GL_UNIFORM, index, maxLength, + length, nameOut, "glGetActiveUniform"); + if (type) + _mesa_program_resource_prop((struct gl_shader_program *) shProg, + res, index, GL_TYPE, (GLint*) type, + "glGetActiveUniform"); + if (size) + _mesa_program_resource_prop((struct gl_shader_program *) shProg, + res, index, GL_ARRAY_SIZE, (GLint*) size, + "glGetActiveUniform"); +} - if (type) { - *type = uni->type->gl_type; +static GLenum +resource_prop_from_uniform_prop(GLenum uni_prop) +{ + switch (uni_prop) { + case GL_UNIFORM_TYPE: + return GL_TYPE; + case GL_UNIFORM_SIZE: + return GL_ARRAY_SIZE; + case GL_UNIFORM_NAME_LENGTH: + return GL_NAME_LENGTH; + case GL_UNIFORM_BLOCK_INDEX: + return GL_BLOCK_INDEX; + case GL_UNIFORM_OFFSET: + return GL_OFFSET; + case GL_UNIFORM_ARRAY_STRIDE: + return GL_ARRAY_STRIDE; + case GL_UNIFORM_MATRIX_STRIDE: + return GL_MATRIX_STRIDE; + case GL_UNIFORM_IS_ROW_MAJOR: + return GL_IS_ROW_MAJOR; + case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: + return GL_ATOMIC_COUNTER_BUFFER_INDEX; + default: + return 0; } } @@ -88,7 +113,8 @@ _mesa_GetActiveUniformsiv(GLuint program, { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; - GLsizei i; + struct gl_program_resource *res; + GLenum res_prop; if (uniformCount < 0) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -100,80 +126,33 @@ _mesa_GetActiveUniformsiv(GLuint program, if (!shProg) return; - for (i = 0; i < uniformCount; i++) { - GLuint index = uniformIndices[i]; + res_prop = resource_prop_from_uniform_prop(pname); - if (index >= shProg->NumUserUniformStorage) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)"); - return; + /* 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++) { + if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM, + uniformIndices[i])) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)"); + return; } } - for (i = 0; i < uniformCount; i++) { - GLuint index = uniformIndices[i]; - const struct gl_uniform_storage *uni = &shProg->UniformStorage[index]; - - switch (pname) { - case GL_UNIFORM_TYPE: - params[i] = uni->type->gl_type; - break; - - case GL_UNIFORM_SIZE: - /* array_elements is zero for non-arrays, but the API requires that 1 be - * returned. - */ - params[i] = MAX2(1, uni->array_elements); - break; - - case GL_UNIFORM_NAME_LENGTH: - params[i] = strlen(uni->name) + 1; - - /* Page 61 (page 73 of the PDF) in section 2.11 of the OpenGL ES 3.0 - * spec says: - * - * "If the active uniform is an array, the uniform name returned - * in name will always be the name of the uniform array appended - * with "[0]"." - */ - if (uni->array_elements != 0) - params[i] += 3; - break; - - case GL_UNIFORM_BLOCK_INDEX: - params[i] = uni->block_index; - break; - - case GL_UNIFORM_OFFSET: - params[i] = uni->offset; - break; - - case GL_UNIFORM_ARRAY_STRIDE: - params[i] = uni->array_stride; - break; - - case GL_UNIFORM_MATRIX_STRIDE: - params[i] = uni->matrix_stride; - break; - - case GL_UNIFORM_IS_ROW_MAJOR: - 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; + 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")) break; - - default: - goto invalid_enum; - } } - - return; - - invalid_enum: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)"); } static struct gl_uniform_storage * @@ -200,10 +179,10 @@ validate_uniform_parameters(struct gl_context *ctx, /* Check that the given location is in bounds of uniform remap table. * Unlinked programs will have NumUniformRemapTable == 0, so we can take - * the shProg->LinkStatus check out of the main path. + * the shProg->data->LinkStatus check out of the main path. */ if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) { - if (!shProg->LinkStatus) + if (!shProg->data->LinkStatus) _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); else @@ -214,7 +193,7 @@ validate_uniform_parameters(struct gl_context *ctx, } if (location == -1) { - if (!shProg->LinkStatus) + if (!shProg->data->LinkStatus) _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); @@ -257,11 +236,18 @@ validate_uniform_parameters(struct gl_context *ctx, 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, - "%s(count > 1 for non-array, location=%d)", - caller, location); + "%s(count = %u for non-array \"%s\"@%d)", + caller, count, uni->name, location); return NULL; } @@ -336,20 +322,20 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, { 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," @@ -367,36 +353,74 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, && (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) { @@ -418,11 +442,17 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, * 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; @@ -469,6 +499,12 @@ log_uniform(const void *values, enum glsl_base_type basicType, case GLSL_TYPE_FLOAT: printf("%g ", v[i].f); break; + 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; @@ -529,11 +565,12 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, */ const unsigned components = MAX2(1, uni->type->vector_elements); const unsigned vectors = MAX2(1, uni->type->matrix_columns); + 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 src_vector_byte_stride = components * 4; + unsigned src_vector_byte_stride = components * 4 * dmul; for (i = 0; i < uni->num_driver_storage; i++) { struct gl_uniform_driver_storage *const store = &uni->driver_storage[i]; @@ -541,7 +578,7 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, const unsigned extra_stride = store->element_stride - (vectors * store->vector_stride); const uint8_t *src = - (uint8_t *) (&uni->storage[array_index * (components * vectors)].i); + (uint8_t *) (&uni->storage[array_index * (dmul * components * vectors)].i); #if 0 printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u " @@ -557,14 +594,31 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, 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; } @@ -597,6 +651,46 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, } } + +/** + * Return printable string for a given GLSL_TYPE_x + */ +static const char * +glsl_type_name(enum glsl_base_type type) +{ + switch (type) { + case GLSL_TYPE_UINT: + return "uint"; + case GLSL_TYPE_INT: + return "int"; + case GLSL_TYPE_FLOAT: + return "float"; + case GLSL_TYPE_DOUBLE: + return "double"; + case GLSL_TYPE_BOOL: + return "bool"; + case GLSL_TYPE_SAMPLER: + return "sampler"; + case GLSL_TYPE_IMAGE: + return "image"; + case GLSL_TYPE_ATOMIC_UINT: + return "atomic_uint"; + case GLSL_TYPE_STRUCT: + return "struct"; + case GLSL_TYPE_INTERFACE: + return "interface"; + case GLSL_TYPE_ARRAY: + return "array"; + case GLSL_TYPE_VOID: + return "void"; + case GLSL_TYPE_ERROR: + return "error"; + default: + return "other"; + } +} + + /** * Called via glUniform*() functions. */ @@ -608,6 +702,7 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, unsigned src_components) { unsigned offset; + int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, count, @@ -615,27 +710,50 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, if (uni == NULL) return; + if (uni->type->is_matrix()) { + /* Can't set matrix uniforms (like mat4) with glUniform */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform%u(uniform \"%s\"@%d is matrix)", + src_components, uni->name, location); + return; + } + /* Verify that the types are compatible. */ const unsigned components = uni->type->is_sampler() ? 1 : uni->type->vector_elements; + if (components != src_components) { + /* glUniformN() must match float/vecN type */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform%u(\"%s\"@%u has %u components, not %u)", + src_components, uni->name, location, + components, src_components); + return; + } + bool match; switch (uni->type->base_type) { case GLSL_TYPE_BOOL: - match = true; + 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; } - if (uni->type->is_matrix() || components != src_components || !match) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); + if (!match) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform%u(\"%s\"@%d is %s, not %s)", + src_components, uni->name, location, + glsl_type_name(uni->type->base_type), + glsl_type_name(basicType)); return; } @@ -674,6 +792,10 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, 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()) { @@ -710,8 +832,8 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, /* Store the data in the "actual type" backing storage for the uniform. */ if (!uni->type->is_boolean()) { - memcpy(&uni->storage[components * offset], values, - sizeof(uni->storage[0]) * components * count); + memcpy(&uni->storage[size_mul * components * offset], values, + sizeof(uni->storage[0]) * components * count * size_mul); } else { const union gl_constant_value *src = (const union gl_constant_value *) values; @@ -727,8 +849,6 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, } } - 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 @@ -737,15 +857,15 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, 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]; } @@ -757,9 +877,10 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, * been modified. */ bool changed = false; - for (unsigned j = 0; j < Elements(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; } @@ -771,10 +892,6 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, 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); @@ -787,11 +904,11 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, */ 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]; } } @@ -808,13 +925,14 @@ extern "C" void _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, GLuint cols, GLuint rows, GLint location, GLsizei count, - GLboolean transpose, const GLfloat *values) + GLboolean transpose, + const GLvoid *values, enum glsl_base_type basicType) { unsigned offset; unsigned vectors; unsigned components; unsigned elements; - + int size_mul; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, count, &offset, "glUniformMatrix"); @@ -827,6 +945,9 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, return; } + 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; components = uni->type->vector_elements; @@ -851,8 +972,33 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, } } + /* 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, GLSL_TYPE_FLOAT, components, vectors, count, + log_uniform(values, uni->type->base_type, components, vectors, count, bool(transpose), shProg, location, uni); } @@ -878,12 +1024,12 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, elements = components * vectors; if (!transpose) { - memcpy(&uni->storage[elements * offset], values, - sizeof(uni->storage[0]) * elements * count); - } else { + memcpy(&uni->storage[size_mul * elements * offset], values, + sizeof(uni->storage[0]) * elements * count * size_mul); + } else if (basicType == GLSL_TYPE_FLOAT) { /* Copy and transpose the matrix. */ - const float *src = values; + const float *src = (const float *)values; float *dst = &uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { @@ -896,91 +1042,33 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, dst += elements; src += elements; } - } - - 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); + assert(basicType == GLSL_TYPE_DOUBLE); + const double *src = (const double *)values; + double *dst = (double *)&uni->storage[elements * offset].f; - if (!found) - return GL_INVALID_INDEX; + for (int i = 0; i < count; i++) { + for (unsigned r = 0; r < rows; r++) { + for (unsigned c = 0; c < cols; c++) { + dst[(c * components) + r] = src[c + (r * vectors)]; + } + } - /* 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; + dst += elements; + src += elements; + } } - *out_offset = offset; - return location; + _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); } + 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->data->NumUniformStorage == 0) return true; if (!shProg->SamplersValidated) { @@ -1009,52 +1097,51 @@ _mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline) * - 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) {