1af69d88dSmrg/* 2af69d88dSmrg * Mesa 3-D graphics library 3af69d88dSmrg * 4af69d88dSmrg * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. 5af69d88dSmrg * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. 6af69d88dSmrg * Copyright © 2010, 2011 Intel Corporation 7af69d88dSmrg * 8af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 9af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 10af69d88dSmrg * to deal in the Software without restriction, including without limitation 11af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 13af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 14af69d88dSmrg * 15af69d88dSmrg * The above copyright notice and this permission notice shall be included 16af69d88dSmrg * in all copies or substantial portions of the Software. 17af69d88dSmrg * 18af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 25af69d88dSmrg */ 26af69d88dSmrg 27af69d88dSmrg#include <stdlib.h> 2801e04c3fSmrg#include <inttypes.h> /* for PRIx64 macro */ 2901e04c3fSmrg#include <math.h> 30af69d88dSmrg 31af69d88dSmrg#include "main/context.h" 327ec681f3Smrg#include "main/draw_validate.h" 33af69d88dSmrg#include "main/shaderapi.h" 34af69d88dSmrg#include "main/shaderobj.h" 3501e04c3fSmrg#include "main/uniforms.h" 3601e04c3fSmrg#include "compiler/glsl/ir.h" 3701e04c3fSmrg#include "compiler/glsl/ir_uniform.h" 3801e04c3fSmrg#include "compiler/glsl/glsl_parser_extras.h" 3901e04c3fSmrg#include "compiler/glsl/program.h" 4001e04c3fSmrg#include "util/bitscan.h" 41af69d88dSmrg 42af69d88dSmrg 437ec681f3Smrg/* This is one of the few glGet that can be called from the app thread safely. 447ec681f3Smrg * Only these conditions must be met: 457ec681f3Smrg * - There are no unfinished glLinkProgram and glDeleteProgram calls 467ec681f3Smrg * for the program object. This assures that the program object is immutable. 477ec681f3Smrg * - glthread=true for GL errors to be passed to the driver thread safely 487ec681f3Smrg * 497ec681f3Smrg * Program objects can be looked up from any thread because they are part 507ec681f3Smrg * of the multi-context shared state. 517ec681f3Smrg */ 527ec681f3Smrgextern "C" void 537ec681f3Smrg_mesa_GetActiveUniform_impl(GLuint program, GLuint index, 547ec681f3Smrg GLsizei maxLength, GLsizei *length, GLint *size, 557ec681f3Smrg GLenum *type, GLcharARB *nameOut, bool glthread) 56af69d88dSmrg{ 57af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 5801e04c3fSmrg struct gl_shader_program *shProg; 5901e04c3fSmrg struct gl_program_resource *res; 60af69d88dSmrg 6101e04c3fSmrg if (maxLength < 0) { 627ec681f3Smrg _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, 637ec681f3Smrg "glGetActiveUniform(maxLength < 0)"); 64af69d88dSmrg return; 6501e04c3fSmrg } 66af69d88dSmrg 677ec681f3Smrg shProg = _mesa_lookup_shader_program_err_glthread(ctx, program, glthread, 687ec681f3Smrg "glGetActiveUniform"); 6901e04c3fSmrg if (!shProg) 70af69d88dSmrg return; 71af69d88dSmrg 7201e04c3fSmrg res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg, 7301e04c3fSmrg GL_UNIFORM, index); 74af69d88dSmrg 7501e04c3fSmrg if (!res) { 767ec681f3Smrg _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, 777ec681f3Smrg "glGetActiveUniform(index)"); 7801e04c3fSmrg return; 79af69d88dSmrg } 80af69d88dSmrg 8101e04c3fSmrg if (nameOut) 8201e04c3fSmrg _mesa_get_program_resource_name(shProg, GL_UNIFORM, index, maxLength, 837ec681f3Smrg length, nameOut, glthread, 847ec681f3Smrg "glGetActiveUniform"); 8501e04c3fSmrg if (type) 8601e04c3fSmrg _mesa_program_resource_prop((struct gl_shader_program *) shProg, 8701e04c3fSmrg res, index, GL_TYPE, (GLint*) type, 887ec681f3Smrg glthread, "glGetActiveUniform"); 8901e04c3fSmrg if (size) 9001e04c3fSmrg _mesa_program_resource_prop((struct gl_shader_program *) shProg, 9101e04c3fSmrg res, index, GL_ARRAY_SIZE, (GLint*) size, 927ec681f3Smrg glthread, "glGetActiveUniform"); 937ec681f3Smrg} 947ec681f3Smrg 957ec681f3Smrgextern "C" void GLAPIENTRY 967ec681f3Smrg_mesa_GetActiveUniform(GLuint program, GLuint index, 977ec681f3Smrg GLsizei maxLength, GLsizei *length, GLint *size, 987ec681f3Smrg GLenum *type, GLcharARB *nameOut) 997ec681f3Smrg{ 1007ec681f3Smrg _mesa_GetActiveUniform_impl(program, index, maxLength, length, size, 1017ec681f3Smrg type, nameOut, false); 10201e04c3fSmrg} 103af69d88dSmrg 10401e04c3fSmrgstatic GLenum 10501e04c3fSmrgresource_prop_from_uniform_prop(GLenum uni_prop) 10601e04c3fSmrg{ 10701e04c3fSmrg switch (uni_prop) { 10801e04c3fSmrg case GL_UNIFORM_TYPE: 10901e04c3fSmrg return GL_TYPE; 11001e04c3fSmrg case GL_UNIFORM_SIZE: 11101e04c3fSmrg return GL_ARRAY_SIZE; 11201e04c3fSmrg case GL_UNIFORM_NAME_LENGTH: 11301e04c3fSmrg return GL_NAME_LENGTH; 11401e04c3fSmrg case GL_UNIFORM_BLOCK_INDEX: 11501e04c3fSmrg return GL_BLOCK_INDEX; 11601e04c3fSmrg case GL_UNIFORM_OFFSET: 11701e04c3fSmrg return GL_OFFSET; 11801e04c3fSmrg case GL_UNIFORM_ARRAY_STRIDE: 11901e04c3fSmrg return GL_ARRAY_STRIDE; 12001e04c3fSmrg case GL_UNIFORM_MATRIX_STRIDE: 12101e04c3fSmrg return GL_MATRIX_STRIDE; 12201e04c3fSmrg case GL_UNIFORM_IS_ROW_MAJOR: 12301e04c3fSmrg return GL_IS_ROW_MAJOR; 12401e04c3fSmrg case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: 12501e04c3fSmrg return GL_ATOMIC_COUNTER_BUFFER_INDEX; 12601e04c3fSmrg default: 12701e04c3fSmrg return 0; 128af69d88dSmrg } 129af69d88dSmrg} 130af69d88dSmrg 131af69d88dSmrgextern "C" void GLAPIENTRY 132af69d88dSmrg_mesa_GetActiveUniformsiv(GLuint program, 133af69d88dSmrg GLsizei uniformCount, 134af69d88dSmrg const GLuint *uniformIndices, 135af69d88dSmrg GLenum pname, 136af69d88dSmrg GLint *params) 137af69d88dSmrg{ 138af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 139af69d88dSmrg struct gl_shader_program *shProg; 14001e04c3fSmrg struct gl_program_resource *res; 14101e04c3fSmrg GLenum res_prop; 142af69d88dSmrg 143af69d88dSmrg if (uniformCount < 0) { 144af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 145af69d88dSmrg "glGetActiveUniformsiv(uniformCount < 0)"); 146af69d88dSmrg return; 147af69d88dSmrg } 148af69d88dSmrg 14901e04c3fSmrg shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); 15001e04c3fSmrg if (!shProg) 15101e04c3fSmrg return; 15201e04c3fSmrg 15301e04c3fSmrg res_prop = resource_prop_from_uniform_prop(pname); 154af69d88dSmrg 15501e04c3fSmrg /* We need to first verify that each entry exists as active uniform. If 15601e04c3fSmrg * not, generate error and do not cause any other side effects. 15701e04c3fSmrg * 15801e04c3fSmrg * In the case of and error condition, Page 16 (section 2.3.1 Errors) 15901e04c3fSmrg * of the OpenGL 4.5 spec says: 16001e04c3fSmrg * 16101e04c3fSmrg * "If the generating command modifies values through a pointer argu- 16201e04c3fSmrg * ment, no change is made to these values." 16301e04c3fSmrg */ 16401e04c3fSmrg for (int i = 0; i < uniformCount; i++) { 16501e04c3fSmrg if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM, 16601e04c3fSmrg uniformIndices[i])) { 16701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)"); 16801e04c3fSmrg return; 169af69d88dSmrg } 170af69d88dSmrg } 171af69d88dSmrg 17201e04c3fSmrg for (int i = 0; i < uniformCount; i++) { 17301e04c3fSmrg res = _mesa_program_resource_find_index(shProg, GL_UNIFORM, 17401e04c3fSmrg uniformIndices[i]); 17501e04c3fSmrg if (!_mesa_program_resource_prop(shProg, res, uniformIndices[i], 17601e04c3fSmrg res_prop, ¶ms[i], 1777ec681f3Smrg false, "glGetActiveUniformsiv")) 178af69d88dSmrg break; 179af69d88dSmrg } 180af69d88dSmrg} 181af69d88dSmrg 182af69d88dSmrgstatic struct gl_uniform_storage * 18301e04c3fSmrgvalidate_uniform_parameters(GLint location, GLsizei count, 18401e04c3fSmrg unsigned *array_index, 18501e04c3fSmrg struct gl_context *ctx, 18601e04c3fSmrg struct gl_shader_program *shProg, 18701e04c3fSmrg const char *caller) 188af69d88dSmrg{ 18901e04c3fSmrg if (shProg == NULL) { 190af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); 191af69d88dSmrg return NULL; 192af69d88dSmrg } 193af69d88dSmrg 194af69d88dSmrg /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec: 195af69d88dSmrg * 196af69d88dSmrg * "If a negative number is provided where an argument of type sizei or 197af69d88dSmrg * sizeiptr is specified, the error INVALID_VALUE is generated." 198af69d88dSmrg */ 199af69d88dSmrg if (count < 0) { 200af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller); 201af69d88dSmrg return NULL; 202af69d88dSmrg } 203af69d88dSmrg 20401e04c3fSmrg /* Check that the given location is in bounds of uniform remap table. 20501e04c3fSmrg * Unlinked programs will have NumUniformRemapTable == 0, so we can take 20601e04c3fSmrg * the shProg->data->LinkStatus check out of the main path. 20701e04c3fSmrg */ 20801e04c3fSmrg if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) { 20901e04c3fSmrg if (!shProg->data->LinkStatus) 21001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", 21101e04c3fSmrg caller); 21201e04c3fSmrg else 21301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", 21401e04c3fSmrg caller, location); 21501e04c3fSmrg 21601e04c3fSmrg return NULL; 21701e04c3fSmrg } 21801e04c3fSmrg 21901e04c3fSmrg if (location == -1) { 22001e04c3fSmrg if (!shProg->data->LinkStatus) 22101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", 22201e04c3fSmrg caller); 22301e04c3fSmrg 224af69d88dSmrg return NULL; 225af69d88dSmrg } 226af69d88dSmrg 227af69d88dSmrg /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 228af69d88dSmrg * 229af69d88dSmrg * "If any of the following conditions occur, an INVALID_OPERATION 230af69d88dSmrg * error is generated by the Uniform* commands, and no uniform values 231af69d88dSmrg * are changed: 232af69d88dSmrg * 233af69d88dSmrg * ... 234af69d88dSmrg * 235af69d88dSmrg * - if no variable with a location of location exists in the 236af69d88dSmrg * program object currently in use and location is not -1, 237af69d88dSmrg * - if count is greater than one, and the uniform declared in the 238af69d88dSmrg * shader is not an array variable, 239af69d88dSmrg */ 240af69d88dSmrg if (location < -1 || !shProg->UniformRemapTable[location]) { 241af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", 242af69d88dSmrg caller, location); 243af69d88dSmrg return NULL; 244af69d88dSmrg } 245af69d88dSmrg 246af69d88dSmrg /* If the driver storage pointer in remap table is -1, we ignore silently. 247af69d88dSmrg * 248af69d88dSmrg * GL_ARB_explicit_uniform_location spec says: 249af69d88dSmrg * "What happens if Uniform* is called with an explicitly defined 250af69d88dSmrg * uniform location, but that uniform is deemed inactive by the 251af69d88dSmrg * linker? 252af69d88dSmrg * 253af69d88dSmrg * RESOLVED: The call is ignored for inactive uniform variables and 254af69d88dSmrg * no error is generated." 255af69d88dSmrg * 256af69d88dSmrg */ 257af69d88dSmrg if (shProg->UniformRemapTable[location] == 258af69d88dSmrg INACTIVE_UNIFORM_EXPLICIT_LOCATION) 259af69d88dSmrg return NULL; 260af69d88dSmrg 261af69d88dSmrg struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location]; 262af69d88dSmrg 26301e04c3fSmrg /* Even though no location is assigned to a built-in uniform and this 26401e04c3fSmrg * function should already have returned NULL, this test makes it explicit 26501e04c3fSmrg * that we are not allowing to update the value of a built-in. 26601e04c3fSmrg */ 26701e04c3fSmrg if (uni->builtin) 268af69d88dSmrg return NULL; 269af69d88dSmrg 27001e04c3fSmrg if (uni->array_elements == 0) { 27101e04c3fSmrg if (count > 1) { 27201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 27301e04c3fSmrg "%s(count = %u for non-array \"%s\"@%d)", 27401e04c3fSmrg caller, count, uni->name, location); 27501e04c3fSmrg return NULL; 27601e04c3fSmrg } 277af69d88dSmrg 27801e04c3fSmrg assert((location - uni->remap_location) == 0); 27901e04c3fSmrg *array_index = 0; 28001e04c3fSmrg } else { 28101e04c3fSmrg /* The array index specified by the uniform location is just the uniform 28201e04c3fSmrg * location minus the base location of of the uniform. 28301e04c3fSmrg */ 28401e04c3fSmrg *array_index = location - uni->remap_location; 28501e04c3fSmrg 28601e04c3fSmrg /* If the uniform is an array, check that array_index is in bounds. 28701e04c3fSmrg * array_index is unsigned so no need to check for less than zero. 28801e04c3fSmrg */ 28901e04c3fSmrg if (*array_index >= uni->array_elements) { 29001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", 29101e04c3fSmrg caller, location); 29201e04c3fSmrg return NULL; 29301e04c3fSmrg } 294af69d88dSmrg } 295af69d88dSmrg return uni; 296af69d88dSmrg} 297af69d88dSmrg 298af69d88dSmrg/** 299af69d88dSmrg * Called via glGetUniform[fiui]v() to get the current value of a uniform. 300af69d88dSmrg */ 301af69d88dSmrgextern "C" void 302af69d88dSmrg_mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, 303af69d88dSmrg GLsizei bufSize, enum glsl_base_type returnType, 304af69d88dSmrg GLvoid *paramsOut) 305af69d88dSmrg{ 306af69d88dSmrg struct gl_shader_program *shProg = 307af69d88dSmrg _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv"); 308af69d88dSmrg unsigned offset; 309af69d88dSmrg 310af69d88dSmrg struct gl_uniform_storage *const uni = 31101e04c3fSmrg validate_uniform_parameters(location, 1, &offset, 31201e04c3fSmrg ctx, shProg, "glGetUniform"); 31301e04c3fSmrg if (uni == NULL) { 31401e04c3fSmrg /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1 31501e04c3fSmrg * spec says: 31601e04c3fSmrg * 31701e04c3fSmrg * "The error INVALID_OPERATION is generated if program has not been 31801e04c3fSmrg * linked successfully, or if location is not a valid location for 31901e04c3fSmrg * program." 32001e04c3fSmrg * 32101e04c3fSmrg * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec 32201e04c3fSmrg * says: 32301e04c3fSmrg * 32401e04c3fSmrg * "If the value of location is -1, the Uniform* commands will 32501e04c3fSmrg * silently ignore the data passed in, and the current uniform 32601e04c3fSmrg * values will not be changed." 32701e04c3fSmrg * 32801e04c3fSmrg * Allowing -1 for the location parameter of glUniform allows 32901e04c3fSmrg * applications to avoid error paths in the case that, for example, some 33001e04c3fSmrg * uniform variable is removed by the compiler / linker after 33101e04c3fSmrg * optimization. In this case, the new value of the uniform is dropped 33201e04c3fSmrg * on the floor. For the case of glGetUniform, there is nothing 33301e04c3fSmrg * sensible to do for a location of -1. 33401e04c3fSmrg * 33501e04c3fSmrg * If the location was -1, validate_unfirom_parameters will return NULL 33601e04c3fSmrg * without raising an error. Raise the error here. 33701e04c3fSmrg */ 33801e04c3fSmrg if (location == -1) { 33901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniform(location=%d)", 34001e04c3fSmrg location); 34101e04c3fSmrg } 34201e04c3fSmrg 343af69d88dSmrg return; 34401e04c3fSmrg } 345af69d88dSmrg 346af69d88dSmrg { 34701e04c3fSmrg unsigned elements = uni->type->components(); 3487ec681f3Smrg unsigned components = uni->type->vector_elements; 3497ec681f3Smrg 35001e04c3fSmrg const int rmul = glsl_base_type_is_64bit(returnType) ? 2 : 1; 35101e04c3fSmrg int dmul = (uni->type->is_64bit()) ? 2 : 1; 35201e04c3fSmrg 35301e04c3fSmrg if ((uni->type->is_sampler() || uni->type->is_image()) && 35401e04c3fSmrg !uni->is_bindless) { 35501e04c3fSmrg /* Non-bindless samplers/images are represented using unsigned integer 35601e04c3fSmrg * 32-bit, while bindless handles are 64-bit. 35701e04c3fSmrg */ 35801e04c3fSmrg dmul = 1; 35901e04c3fSmrg } 360af69d88dSmrg 361af69d88dSmrg /* Calculate the source base address *BEFORE* modifying elements to 362af69d88dSmrg * account for the size of the user's buffer. 363af69d88dSmrg */ 36401e04c3fSmrg const union gl_constant_value *src; 36501e04c3fSmrg if (ctx->Const.PackedDriverUniformStorage && 36601e04c3fSmrg (uni->is_bindless || !uni->type->contains_opaque())) { 3677ec681f3Smrg unsigned dword_elements = elements; 3687ec681f3Smrg 3697ec681f3Smrg /* 16-bit uniforms are packed. */ 3707ec681f3Smrg if (glsl_base_type_is_16bit(uni->type->base_type)) { 3717ec681f3Smrg dword_elements = DIV_ROUND_UP(components, 2) * 3727ec681f3Smrg uni->type->matrix_columns; 3737ec681f3Smrg } 3747ec681f3Smrg 37501e04c3fSmrg src = (gl_constant_value *) uni->driver_storage[0].data + 3767ec681f3Smrg (offset * dword_elements * dmul); 37701e04c3fSmrg } else { 37801e04c3fSmrg src = &uni->storage[offset * elements * dmul]; 37901e04c3fSmrg } 380af69d88dSmrg 381af69d88dSmrg assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT || 38201e04c3fSmrg returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_DOUBLE || 38301e04c3fSmrg returnType == GLSL_TYPE_UINT64 || returnType == GLSL_TYPE_INT64); 38401e04c3fSmrg 38501e04c3fSmrg /* doubles have a different size than the other 3 types */ 38601e04c3fSmrg unsigned bytes = sizeof(src[0]) * elements * rmul; 387af69d88dSmrg if (bufSize < 0 || bytes > (unsigned) bufSize) { 38801e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 38901e04c3fSmrg "glGetnUniform*vARB(out of bounds: bufSize is %d," 39001e04c3fSmrg " but %u bytes are required)", bufSize, bytes); 39101e04c3fSmrg return; 392af69d88dSmrg } 393af69d88dSmrg 394af69d88dSmrg /* If the return type and the uniform's native type are "compatible," 395af69d88dSmrg * just memcpy the data. If the types are not compatible, perform a 396af69d88dSmrg * slower convert-and-copy process. 397af69d88dSmrg */ 39801e04c3fSmrg if (returnType == uni->type->base_type || 39901e04c3fSmrg ((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT) && 40001e04c3fSmrg (uni->type->is_sampler() || uni->type->is_image())) || 40101e04c3fSmrg (returnType == GLSL_TYPE_UINT64 && uni->is_bindless)) { 40201e04c3fSmrg memcpy(paramsOut, src, bytes); 403af69d88dSmrg } else { 40401e04c3fSmrg union gl_constant_value *const dst = 40501e04c3fSmrg (union gl_constant_value *) paramsOut; 40601e04c3fSmrg /* This code could be optimized by putting the loop inside the switch 40701e04c3fSmrg * statements. However, this is not expected to be 40801e04c3fSmrg * performance-critical code. 40901e04c3fSmrg */ 41001e04c3fSmrg for (unsigned i = 0; i < elements; i++) { 41101e04c3fSmrg int sidx = i * dmul; 41201e04c3fSmrg int didx = i * rmul; 41301e04c3fSmrg 4147ec681f3Smrg if (glsl_base_type_is_16bit(uni->type->base_type)) { 4157ec681f3Smrg unsigned column = i / components; 4167ec681f3Smrg unsigned row = i % components; 4177ec681f3Smrg sidx = column * align(components, 2) + row; 4187ec681f3Smrg } 4197ec681f3Smrg 42001e04c3fSmrg switch (returnType) { 42101e04c3fSmrg case GLSL_TYPE_FLOAT: 42201e04c3fSmrg switch (uni->type->base_type) { 4237ec681f3Smrg case GLSL_TYPE_FLOAT16: 4247ec681f3Smrg dst[didx].f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 4257ec681f3Smrg break; 42601e04c3fSmrg case GLSL_TYPE_UINT: 42701e04c3fSmrg dst[didx].f = (float) src[sidx].u; 42801e04c3fSmrg break; 42901e04c3fSmrg case GLSL_TYPE_INT: 43001e04c3fSmrg case GLSL_TYPE_SAMPLER: 43101e04c3fSmrg case GLSL_TYPE_IMAGE: 43201e04c3fSmrg dst[didx].f = (float) src[sidx].i; 43301e04c3fSmrg break; 43401e04c3fSmrg case GLSL_TYPE_BOOL: 43501e04c3fSmrg dst[didx].f = src[sidx].i ? 1.0f : 0.0f; 43601e04c3fSmrg break; 43701e04c3fSmrg case GLSL_TYPE_DOUBLE: { 43801e04c3fSmrg double tmp; 43901e04c3fSmrg memcpy(&tmp, &src[sidx].f, sizeof(tmp)); 44001e04c3fSmrg dst[didx].f = tmp; 44101e04c3fSmrg break; 44201e04c3fSmrg } 44301e04c3fSmrg case GLSL_TYPE_UINT64: { 44401e04c3fSmrg uint64_t tmp; 44501e04c3fSmrg memcpy(&tmp, &src[sidx].u, sizeof(tmp)); 44601e04c3fSmrg dst[didx].f = tmp; 44701e04c3fSmrg break; 44801e04c3fSmrg } 44901e04c3fSmrg case GLSL_TYPE_INT64: { 45001e04c3fSmrg uint64_t tmp; 45101e04c3fSmrg memcpy(&tmp, &src[sidx].i, sizeof(tmp)); 45201e04c3fSmrg dst[didx].f = tmp; 45301e04c3fSmrg break; 45401e04c3fSmrg } 45501e04c3fSmrg default: 45601e04c3fSmrg assert(!"Should not get here."); 45701e04c3fSmrg break; 45801e04c3fSmrg } 45901e04c3fSmrg break; 46001e04c3fSmrg 46101e04c3fSmrg case GLSL_TYPE_DOUBLE: 46201e04c3fSmrg switch (uni->type->base_type) { 4637ec681f3Smrg case GLSL_TYPE_FLOAT16: { 4647ec681f3Smrg double f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 4657ec681f3Smrg memcpy(&dst[didx].f, &f, sizeof(f)); 4667ec681f3Smrg break; 4677ec681f3Smrg } 46801e04c3fSmrg case GLSL_TYPE_UINT: { 46901e04c3fSmrg double tmp = src[sidx].u; 47001e04c3fSmrg memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 47101e04c3fSmrg break; 47201e04c3fSmrg } 47301e04c3fSmrg case GLSL_TYPE_INT: 47401e04c3fSmrg case GLSL_TYPE_SAMPLER: 47501e04c3fSmrg case GLSL_TYPE_IMAGE: { 47601e04c3fSmrg double tmp = src[sidx].i; 47701e04c3fSmrg memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 47801e04c3fSmrg break; 47901e04c3fSmrg } 48001e04c3fSmrg case GLSL_TYPE_BOOL: { 48101e04c3fSmrg double tmp = src[sidx].i ? 1.0 : 0.0; 48201e04c3fSmrg memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 48301e04c3fSmrg break; 48401e04c3fSmrg } 48501e04c3fSmrg case GLSL_TYPE_FLOAT: { 48601e04c3fSmrg double tmp = src[sidx].f; 48701e04c3fSmrg memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 48801e04c3fSmrg break; 48901e04c3fSmrg } 49001e04c3fSmrg case GLSL_TYPE_UINT64: { 49101e04c3fSmrg uint64_t tmpu; 49201e04c3fSmrg double tmp; 49301e04c3fSmrg memcpy(&tmpu, &src[sidx].u, sizeof(tmpu)); 49401e04c3fSmrg tmp = tmpu; 49501e04c3fSmrg memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 49601e04c3fSmrg break; 49701e04c3fSmrg } 49801e04c3fSmrg case GLSL_TYPE_INT64: { 49901e04c3fSmrg int64_t tmpi; 50001e04c3fSmrg double tmp; 50101e04c3fSmrg memcpy(&tmpi, &src[sidx].i, sizeof(tmpi)); 50201e04c3fSmrg tmp = tmpi; 50301e04c3fSmrg memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 50401e04c3fSmrg break; 50501e04c3fSmrg } 50601e04c3fSmrg default: 50701e04c3fSmrg assert(!"Should not get here."); 50801e04c3fSmrg break; 50901e04c3fSmrg } 51001e04c3fSmrg break; 51101e04c3fSmrg 51201e04c3fSmrg case GLSL_TYPE_INT: 51301e04c3fSmrg switch (uni->type->base_type) { 51401e04c3fSmrg case GLSL_TYPE_FLOAT: 51501e04c3fSmrg /* While the GL 3.2 core spec doesn't explicitly 51601e04c3fSmrg * state how conversion of float uniforms to integer 51701e04c3fSmrg * values works, in section 6.2 "State Tables" on 51801e04c3fSmrg * page 267 it says: 51901e04c3fSmrg * 52001e04c3fSmrg * "Unless otherwise specified, when floating 52101e04c3fSmrg * point state is returned as integer values or 52201e04c3fSmrg * integer state is returned as floating-point 52301e04c3fSmrg * values it is converted in the fashion 52401e04c3fSmrg * described in section 6.1.2" 52501e04c3fSmrg * 52601e04c3fSmrg * That section, on page 248, says: 52701e04c3fSmrg * 52801e04c3fSmrg * "If GetIntegerv or GetInteger64v are called, 52901e04c3fSmrg * a floating-point value is rounded to the 53001e04c3fSmrg * nearest integer..." 53101e04c3fSmrg */ 53201e04c3fSmrg dst[didx].i = (int64_t) roundf(src[sidx].f); 53301e04c3fSmrg break; 5347ec681f3Smrg case GLSL_TYPE_FLOAT16: 5357ec681f3Smrg dst[didx].i = 5367ec681f3Smrg (int64_t)roundf(_mesa_half_to_float(((uint16_t*)src)[sidx])); 5377ec681f3Smrg break; 53801e04c3fSmrg case GLSL_TYPE_BOOL: 53901e04c3fSmrg dst[didx].i = src[sidx].i ? 1 : 0; 54001e04c3fSmrg break; 54101e04c3fSmrg case GLSL_TYPE_UINT: 54201e04c3fSmrg dst[didx].i = MIN2(src[sidx].i, INT_MAX); 54301e04c3fSmrg break; 54401e04c3fSmrg case GLSL_TYPE_DOUBLE: { 54501e04c3fSmrg double tmp; 54601e04c3fSmrg memcpy(&tmp, &src[sidx].f, sizeof(tmp)); 54701e04c3fSmrg dst[didx].i = (int64_t) round(tmp); 54801e04c3fSmrg break; 54901e04c3fSmrg } 55001e04c3fSmrg case GLSL_TYPE_UINT64: { 55101e04c3fSmrg uint64_t tmp; 55201e04c3fSmrg memcpy(&tmp, &src[sidx].u, sizeof(tmp)); 55301e04c3fSmrg dst[didx].i = tmp; 55401e04c3fSmrg break; 55501e04c3fSmrg } 55601e04c3fSmrg case GLSL_TYPE_INT64: { 55701e04c3fSmrg int64_t tmp; 55801e04c3fSmrg memcpy(&tmp, &src[sidx].i, sizeof(tmp)); 55901e04c3fSmrg dst[didx].i = tmp; 56001e04c3fSmrg break; 56101e04c3fSmrg } 56201e04c3fSmrg default: 56301e04c3fSmrg assert(!"Should not get here."); 56401e04c3fSmrg break; 56501e04c3fSmrg } 56601e04c3fSmrg break; 56701e04c3fSmrg 56801e04c3fSmrg case GLSL_TYPE_UINT: 56901e04c3fSmrg switch (uni->type->base_type) { 57001e04c3fSmrg case GLSL_TYPE_FLOAT: 57101e04c3fSmrg /* The spec isn't terribly clear how to handle negative 57201e04c3fSmrg * values with an unsigned return type. 57301e04c3fSmrg * 57401e04c3fSmrg * GL 4.5 section 2.2.2 ("Data Conversions for State 57501e04c3fSmrg * Query Commands") says: 57601e04c3fSmrg * 57701e04c3fSmrg * "If a value is so large in magnitude that it cannot be 57801e04c3fSmrg * represented by the returned data type, then the nearest 57901e04c3fSmrg * value representable using the requested type is 58001e04c3fSmrg * returned." 58101e04c3fSmrg */ 58201e04c3fSmrg dst[didx].u = src[sidx].f < 0.0f ? 58301e04c3fSmrg 0u : (uint32_t) roundf(src[sidx].f); 58401e04c3fSmrg break; 5857ec681f3Smrg case GLSL_TYPE_FLOAT16: { 5867ec681f3Smrg float f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 5877ec681f3Smrg dst[didx].u = f < 0.0f ? 0u : (uint32_t)roundf(f); 5887ec681f3Smrg break; 5897ec681f3Smrg } 59001e04c3fSmrg case GLSL_TYPE_BOOL: 59101e04c3fSmrg dst[didx].i = src[sidx].i ? 1 : 0; 59201e04c3fSmrg break; 59301e04c3fSmrg case GLSL_TYPE_INT: 59401e04c3fSmrg dst[didx].i = MAX2(src[sidx].i, 0); 59501e04c3fSmrg break; 59601e04c3fSmrg case GLSL_TYPE_DOUBLE: { 59701e04c3fSmrg double tmp; 59801e04c3fSmrg memcpy(&tmp, &src[sidx].f, sizeof(tmp)); 59901e04c3fSmrg dst[didx].u = tmp < 0.0 ? 0u : (uint32_t) round(tmp); 60001e04c3fSmrg break; 60101e04c3fSmrg } 60201e04c3fSmrg case GLSL_TYPE_UINT64: { 60301e04c3fSmrg uint64_t tmp; 60401e04c3fSmrg memcpy(&tmp, &src[sidx].u, sizeof(tmp)); 60501e04c3fSmrg dst[didx].i = MIN2(tmp, INT_MAX); 60601e04c3fSmrg break; 60701e04c3fSmrg } 60801e04c3fSmrg case GLSL_TYPE_INT64: { 60901e04c3fSmrg int64_t tmp; 61001e04c3fSmrg memcpy(&tmp, &src[sidx].i, sizeof(tmp)); 61101e04c3fSmrg dst[didx].i = MAX2(tmp, 0); 61201e04c3fSmrg break; 61301e04c3fSmrg } 61401e04c3fSmrg default: 61501e04c3fSmrg unreachable("invalid uniform type"); 61601e04c3fSmrg } 61701e04c3fSmrg break; 61801e04c3fSmrg 61901e04c3fSmrg case GLSL_TYPE_INT64: 62001e04c3fSmrg switch (uni->type->base_type) { 62101e04c3fSmrg case GLSL_TYPE_UINT: { 62201e04c3fSmrg uint64_t tmp = src[sidx].u; 62301e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 62401e04c3fSmrg break; 62501e04c3fSmrg } 62601e04c3fSmrg case GLSL_TYPE_INT: 62701e04c3fSmrg case GLSL_TYPE_SAMPLER: 62801e04c3fSmrg case GLSL_TYPE_IMAGE: { 62901e04c3fSmrg int64_t tmp = src[sidx].i; 63001e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 63101e04c3fSmrg break; 63201e04c3fSmrg } 63301e04c3fSmrg case GLSL_TYPE_BOOL: { 63401e04c3fSmrg int64_t tmp = src[sidx].i ? 1.0f : 0.0f; 63501e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 63601e04c3fSmrg break; 63701e04c3fSmrg } 63801e04c3fSmrg case GLSL_TYPE_UINT64: { 63901e04c3fSmrg uint64_t u64; 64001e04c3fSmrg memcpy(&u64, &src[sidx].u, sizeof(u64)); 64101e04c3fSmrg int64_t tmp = MIN2(u64, INT_MAX); 64201e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 64301e04c3fSmrg break; 64401e04c3fSmrg } 64501e04c3fSmrg case GLSL_TYPE_FLOAT: { 64601e04c3fSmrg int64_t tmp = (int64_t) roundf(src[sidx].f); 64701e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 64801e04c3fSmrg break; 64901e04c3fSmrg } 6507ec681f3Smrg case GLSL_TYPE_FLOAT16: { 6517ec681f3Smrg float f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 6527ec681f3Smrg int64_t tmp = (int64_t) roundf(f); 6537ec681f3Smrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 6547ec681f3Smrg break; 6557ec681f3Smrg } 65601e04c3fSmrg case GLSL_TYPE_DOUBLE: { 65701e04c3fSmrg double d; 65801e04c3fSmrg memcpy(&d, &src[sidx].f, sizeof(d)); 65901e04c3fSmrg int64_t tmp = (int64_t) round(d); 66001e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 66101e04c3fSmrg break; 66201e04c3fSmrg } 66301e04c3fSmrg default: 66401e04c3fSmrg assert(!"Should not get here."); 66501e04c3fSmrg break; 66601e04c3fSmrg } 66701e04c3fSmrg break; 66801e04c3fSmrg 66901e04c3fSmrg case GLSL_TYPE_UINT64: 67001e04c3fSmrg switch (uni->type->base_type) { 67101e04c3fSmrg case GLSL_TYPE_UINT: { 67201e04c3fSmrg uint64_t tmp = src[sidx].u; 67301e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 67401e04c3fSmrg break; 67501e04c3fSmrg } 67601e04c3fSmrg case GLSL_TYPE_INT: 67701e04c3fSmrg case GLSL_TYPE_SAMPLER: 67801e04c3fSmrg case GLSL_TYPE_IMAGE: { 67901e04c3fSmrg int64_t tmp = MAX2(src[sidx].i, 0); 68001e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 68101e04c3fSmrg break; 68201e04c3fSmrg } 68301e04c3fSmrg case GLSL_TYPE_BOOL: { 68401e04c3fSmrg int64_t tmp = src[sidx].i ? 1.0f : 0.0f; 68501e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 68601e04c3fSmrg break; 68701e04c3fSmrg } 68801e04c3fSmrg case GLSL_TYPE_INT64: { 68901e04c3fSmrg uint64_t i64; 69001e04c3fSmrg memcpy(&i64, &src[sidx].i, sizeof(i64)); 69101e04c3fSmrg uint64_t tmp = MAX2(i64, 0); 69201e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 69301e04c3fSmrg break; 69401e04c3fSmrg } 69501e04c3fSmrg case GLSL_TYPE_FLOAT: { 69601e04c3fSmrg uint64_t tmp = src[sidx].f < 0.0f ? 69701e04c3fSmrg 0ull : (uint64_t) roundf(src[sidx].f); 69801e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 69901e04c3fSmrg break; 70001e04c3fSmrg } 7017ec681f3Smrg case GLSL_TYPE_FLOAT16: { 7027ec681f3Smrg float f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 7037ec681f3Smrg uint64_t tmp = f < 0.0f ? 0ull : (uint64_t) roundf(f); 7047ec681f3Smrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 7057ec681f3Smrg break; 7067ec681f3Smrg } 70701e04c3fSmrg case GLSL_TYPE_DOUBLE: { 70801e04c3fSmrg double d; 70901e04c3fSmrg memcpy(&d, &src[sidx].f, sizeof(d)); 71001e04c3fSmrg uint64_t tmp = (d < 0.0) ? 0ull : (uint64_t) round(d); 71101e04c3fSmrg memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 71201e04c3fSmrg break; 71301e04c3fSmrg } 71401e04c3fSmrg default: 71501e04c3fSmrg assert(!"Should not get here."); 71601e04c3fSmrg break; 71701e04c3fSmrg } 71801e04c3fSmrg break; 71901e04c3fSmrg 72001e04c3fSmrg default: 72101e04c3fSmrg assert(!"Should not get here."); 72201e04c3fSmrg break; 72301e04c3fSmrg } 72401e04c3fSmrg } 725af69d88dSmrg } 726af69d88dSmrg } 727af69d88dSmrg} 728af69d88dSmrg 729af69d88dSmrgstatic void 730af69d88dSmrglog_uniform(const void *values, enum glsl_base_type basicType, 731af69d88dSmrg unsigned rows, unsigned cols, unsigned count, 732af69d88dSmrg bool transpose, 733af69d88dSmrg const struct gl_shader_program *shProg, 734af69d88dSmrg GLint location, 735af69d88dSmrg const struct gl_uniform_storage *uni) 736af69d88dSmrg{ 737af69d88dSmrg 738af69d88dSmrg const union gl_constant_value *v = (const union gl_constant_value *) values; 739af69d88dSmrg const unsigned elems = rows * cols * count; 740af69d88dSmrg const char *const extra = (cols == 1) ? "uniform" : "uniform matrix"; 741af69d88dSmrg 742af69d88dSmrg printf("Mesa: set program %u %s \"%s\" (loc %d, type \"%s\", " 743af69d88dSmrg "transpose = %s) to: ", 744af69d88dSmrg shProg->Name, extra, uni->name, location, uni->type->name, 745af69d88dSmrg transpose ? "true" : "false"); 746af69d88dSmrg for (unsigned i = 0; i < elems; i++) { 747af69d88dSmrg if (i != 0 && ((i % rows) == 0)) 748af69d88dSmrg printf(", "); 749af69d88dSmrg 750af69d88dSmrg switch (basicType) { 751af69d88dSmrg case GLSL_TYPE_UINT: 752af69d88dSmrg printf("%u ", v[i].u); 753af69d88dSmrg break; 754af69d88dSmrg case GLSL_TYPE_INT: 755af69d88dSmrg printf("%d ", v[i].i); 756af69d88dSmrg break; 75701e04c3fSmrg case GLSL_TYPE_UINT64: { 75801e04c3fSmrg uint64_t tmp; 75901e04c3fSmrg memcpy(&tmp, &v[i * 2].u, sizeof(tmp)); 76001e04c3fSmrg printf("%" PRIu64 " ", tmp); 76101e04c3fSmrg break; 76201e04c3fSmrg } 76301e04c3fSmrg case GLSL_TYPE_INT64: { 76401e04c3fSmrg int64_t tmp; 76501e04c3fSmrg memcpy(&tmp, &v[i * 2].u, sizeof(tmp)); 76601e04c3fSmrg printf("%" PRId64 " ", tmp); 76701e04c3fSmrg break; 76801e04c3fSmrg } 769af69d88dSmrg case GLSL_TYPE_FLOAT: 770af69d88dSmrg printf("%g ", v[i].f); 771af69d88dSmrg break; 77201e04c3fSmrg case GLSL_TYPE_DOUBLE: { 77301e04c3fSmrg double tmp; 77401e04c3fSmrg memcpy(&tmp, &v[i * 2].f, sizeof(tmp)); 77501e04c3fSmrg printf("%g ", tmp); 77601e04c3fSmrg break; 77701e04c3fSmrg } 778af69d88dSmrg default: 779af69d88dSmrg assert(!"Should not get here."); 780af69d88dSmrg break; 781af69d88dSmrg } 782af69d88dSmrg } 783af69d88dSmrg printf("\n"); 784af69d88dSmrg fflush(stdout); 785af69d88dSmrg} 786af69d88dSmrg 787af69d88dSmrg#if 0 788af69d88dSmrgstatic void 789af69d88dSmrglog_program_parameters(const struct gl_shader_program *shProg) 790af69d88dSmrg{ 791af69d88dSmrg for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 792af69d88dSmrg if (shProg->_LinkedShaders[i] == NULL) 793af69d88dSmrg continue; 794af69d88dSmrg 795af69d88dSmrg const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program; 796af69d88dSmrg 797af69d88dSmrg printf("Program %d %s shader parameters:\n", 798af69d88dSmrg shProg->Name, _mesa_shader_stage_to_string(i)); 799af69d88dSmrg for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) { 80001e04c3fSmrg unsigned pvo = prog->Parameters->ParameterValueOffset[j]; 80101e04c3fSmrg printf("%s: %u %p %f %f %f %f\n", 802af69d88dSmrg prog->Parameters->Parameters[j].Name, 80301e04c3fSmrg pvo, 80401e04c3fSmrg prog->Parameters->ParameterValues + pvo, 80501e04c3fSmrg prog->Parameters->ParameterValues[pvo].f, 80601e04c3fSmrg prog->Parameters->ParameterValues[pvo + 1].f, 80701e04c3fSmrg prog->Parameters->ParameterValues[pvo + 2].f, 80801e04c3fSmrg prog->Parameters->ParameterValues[pvo + 3].f); 809af69d88dSmrg } 810af69d88dSmrg } 811af69d88dSmrg fflush(stdout); 812af69d88dSmrg} 813af69d88dSmrg#endif 814af69d88dSmrg 815af69d88dSmrg/** 816af69d88dSmrg * Propagate some values from uniform backing storage to driver storage 817af69d88dSmrg * 818af69d88dSmrg * Values propagated from uniform backing storage to driver storage 819af69d88dSmrg * have all format / type conversions previously requested by the 820af69d88dSmrg * driver applied. This function is most often called by the 821af69d88dSmrg * implementations of \c glUniform1f, etc. and \c glUniformMatrix2f, 822af69d88dSmrg * etc. 823af69d88dSmrg * 824af69d88dSmrg * \param uni Uniform whose data is to be propagated to driver storage 825af69d88dSmrg * \param array_index If \c uni is an array, this is the element of 826af69d88dSmrg * the array to be propagated. 827af69d88dSmrg * \param count Number of array elements to propagate. 828af69d88dSmrg */ 829af69d88dSmrgextern "C" void 830af69d88dSmrg_mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, 831af69d88dSmrg unsigned array_index, 832af69d88dSmrg unsigned count) 833af69d88dSmrg{ 834af69d88dSmrg unsigned i; 835af69d88dSmrg 83601e04c3fSmrg const unsigned components = uni->type->vector_elements; 83701e04c3fSmrg const unsigned vectors = uni->type->matrix_columns; 83801e04c3fSmrg const int dmul = uni->type->is_64bit() ? 2 : 1; 839af69d88dSmrg 840af69d88dSmrg /* Store the data in the driver's requested type in the driver's storage 841af69d88dSmrg * areas. 842af69d88dSmrg */ 84301e04c3fSmrg unsigned src_vector_byte_stride = components * 4 * dmul; 844af69d88dSmrg 845af69d88dSmrg for (i = 0; i < uni->num_driver_storage; i++) { 846af69d88dSmrg struct gl_uniform_driver_storage *const store = &uni->driver_storage[i]; 847af69d88dSmrg uint8_t *dst = (uint8_t *) store->data; 848af69d88dSmrg const unsigned extra_stride = 849af69d88dSmrg store->element_stride - (vectors * store->vector_stride); 850af69d88dSmrg const uint8_t *src = 85101e04c3fSmrg (uint8_t *) (&uni->storage[array_index * (dmul * components * vectors)].i); 852af69d88dSmrg 853af69d88dSmrg#if 0 854af69d88dSmrg printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u " 855af69d88dSmrg "extra_stride=%u\n", 856af69d88dSmrg __func__, dst, array_index, components, 857af69d88dSmrg vectors, count, store->vector_stride, extra_stride); 858af69d88dSmrg#endif 859af69d88dSmrg 860af69d88dSmrg dst += array_index * store->element_stride; 861af69d88dSmrg 862af69d88dSmrg switch (store->format) { 86301e04c3fSmrg case uniform_native: { 864af69d88dSmrg unsigned j; 865af69d88dSmrg unsigned v; 866af69d88dSmrg 86701e04c3fSmrg if (src_vector_byte_stride == store->vector_stride) { 86801e04c3fSmrg if (extra_stride) { 86901e04c3fSmrg for (j = 0; j < count; j++) { 87001e04c3fSmrg memcpy(dst, src, src_vector_byte_stride * vectors); 87101e04c3fSmrg src += src_vector_byte_stride * vectors; 87201e04c3fSmrg dst += store->vector_stride * vectors; 873af69d88dSmrg 87401e04c3fSmrg dst += extra_stride; 875af69d88dSmrg } 87601e04c3fSmrg } else { 87701e04c3fSmrg /* Unigine Heaven benchmark gets here */ 87801e04c3fSmrg memcpy(dst, src, src_vector_byte_stride * vectors * count); 87901e04c3fSmrg src += src_vector_byte_stride * vectors * count; 88001e04c3fSmrg dst += store->vector_stride * vectors * count; 881af69d88dSmrg } 88201e04c3fSmrg } else { 88301e04c3fSmrg for (j = 0; j < count; j++) { 88401e04c3fSmrg for (v = 0; v < vectors; v++) { 88501e04c3fSmrg memcpy(dst, src, src_vector_byte_stride); 88601e04c3fSmrg src += src_vector_byte_stride; 88701e04c3fSmrg dst += store->vector_stride; 88801e04c3fSmrg } 889af69d88dSmrg 89001e04c3fSmrg dst += extra_stride; 89101e04c3fSmrg } 892af69d88dSmrg } 893af69d88dSmrg break; 894af69d88dSmrg } 895af69d88dSmrg 89601e04c3fSmrg case uniform_int_float: { 897af69d88dSmrg const int *isrc = (const int *) src; 898af69d88dSmrg unsigned j; 899af69d88dSmrg unsigned v; 900af69d88dSmrg unsigned c; 901af69d88dSmrg 902af69d88dSmrg for (j = 0; j < count; j++) { 903af69d88dSmrg for (v = 0; v < vectors; v++) { 904af69d88dSmrg for (c = 0; c < components; c++) { 90501e04c3fSmrg ((float *) dst)[c] = (float) *isrc; 906af69d88dSmrg isrc++; 907af69d88dSmrg } 908af69d88dSmrg 909af69d88dSmrg dst += store->vector_stride; 910af69d88dSmrg } 911af69d88dSmrg 912af69d88dSmrg dst += extra_stride; 913af69d88dSmrg } 914af69d88dSmrg break; 915af69d88dSmrg } 916af69d88dSmrg 917af69d88dSmrg default: 918af69d88dSmrg assert(!"Should not get here."); 919af69d88dSmrg break; 920af69d88dSmrg } 921af69d88dSmrg } 922af69d88dSmrg} 923af69d88dSmrg 92401e04c3fSmrg 925af69d88dSmrg/** 92601e04c3fSmrg * Return printable string for a given GLSL_TYPE_x 927af69d88dSmrg */ 92801e04c3fSmrgstatic const char * 92901e04c3fSmrgglsl_type_name(enum glsl_base_type type) 930af69d88dSmrg{ 93101e04c3fSmrg switch (type) { 93201e04c3fSmrg case GLSL_TYPE_UINT: 93301e04c3fSmrg return "uint"; 93401e04c3fSmrg case GLSL_TYPE_INT: 93501e04c3fSmrg return "int"; 93601e04c3fSmrg case GLSL_TYPE_FLOAT: 93701e04c3fSmrg return "float"; 93801e04c3fSmrg case GLSL_TYPE_DOUBLE: 93901e04c3fSmrg return "double"; 94001e04c3fSmrg case GLSL_TYPE_UINT64: 94101e04c3fSmrg return "uint64"; 94201e04c3fSmrg case GLSL_TYPE_INT64: 94301e04c3fSmrg return "int64"; 94401e04c3fSmrg case GLSL_TYPE_BOOL: 94501e04c3fSmrg return "bool"; 94601e04c3fSmrg case GLSL_TYPE_SAMPLER: 94701e04c3fSmrg return "sampler"; 94801e04c3fSmrg case GLSL_TYPE_IMAGE: 94901e04c3fSmrg return "image"; 95001e04c3fSmrg case GLSL_TYPE_ATOMIC_UINT: 95101e04c3fSmrg return "atomic_uint"; 95201e04c3fSmrg case GLSL_TYPE_STRUCT: 95301e04c3fSmrg return "struct"; 95401e04c3fSmrg case GLSL_TYPE_INTERFACE: 95501e04c3fSmrg return "interface"; 95601e04c3fSmrg case GLSL_TYPE_ARRAY: 95701e04c3fSmrg return "array"; 95801e04c3fSmrg case GLSL_TYPE_VOID: 95901e04c3fSmrg return "void"; 96001e04c3fSmrg case GLSL_TYPE_ERROR: 96101e04c3fSmrg return "error"; 96201e04c3fSmrg default: 96301e04c3fSmrg return "other"; 96401e04c3fSmrg } 96501e04c3fSmrg} 966af69d88dSmrg 96701e04c3fSmrg 96801e04c3fSmrgstatic struct gl_uniform_storage * 96901e04c3fSmrgvalidate_uniform(GLint location, GLsizei count, const GLvoid *values, 97001e04c3fSmrg unsigned *offset, struct gl_context *ctx, 97101e04c3fSmrg struct gl_shader_program *shProg, 97201e04c3fSmrg enum glsl_base_type basicType, unsigned src_components) 97301e04c3fSmrg{ 974af69d88dSmrg struct gl_uniform_storage *const uni = 97501e04c3fSmrg validate_uniform_parameters(location, count, offset, 97601e04c3fSmrg ctx, shProg, "glUniform"); 977af69d88dSmrg if (uni == NULL) 97801e04c3fSmrg return NULL; 979af69d88dSmrg 98001e04c3fSmrg if (uni->type->is_matrix()) { 98101e04c3fSmrg /* Can't set matrix uniforms (like mat4) with glUniform */ 98201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 98301e04c3fSmrg "glUniform%u(uniform \"%s\"@%d is matrix)", 98401e04c3fSmrg src_components, uni->name, location); 98501e04c3fSmrg return NULL; 986af69d88dSmrg } 987af69d88dSmrg 98801e04c3fSmrg /* Verify that the types are compatible. */ 98901e04c3fSmrg const unsigned components = uni->type->vector_elements; 99001e04c3fSmrg 99101e04c3fSmrg if (components != src_components) { 99201e04c3fSmrg /* glUniformN() must match float/vecN type */ 99301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 99401e04c3fSmrg "glUniform%u(\"%s\"@%u has %u components, not %u)", 99501e04c3fSmrg src_components, uni->name, location, 99601e04c3fSmrg components, src_components); 99701e04c3fSmrg return NULL; 998af69d88dSmrg } 999af69d88dSmrg 1000af69d88dSmrg bool match; 1001af69d88dSmrg switch (uni->type->base_type) { 1002af69d88dSmrg case GLSL_TYPE_BOOL: 100301e04c3fSmrg match = (basicType != GLSL_TYPE_DOUBLE); 1004af69d88dSmrg break; 1005af69d88dSmrg case GLSL_TYPE_SAMPLER: 1006af69d88dSmrg match = (basicType == GLSL_TYPE_INT); 1007af69d88dSmrg break; 100801e04c3fSmrg case GLSL_TYPE_IMAGE: 100901e04c3fSmrg match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx)); 101001e04c3fSmrg break; 10117ec681f3Smrg case GLSL_TYPE_FLOAT16: 10127ec681f3Smrg match = basicType == GLSL_TYPE_FLOAT; 10137ec681f3Smrg break; 1014af69d88dSmrg default: 1015af69d88dSmrg match = (basicType == uni->type->base_type); 1016af69d88dSmrg break; 1017af69d88dSmrg } 1018af69d88dSmrg 101901e04c3fSmrg if (!match) { 102001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 102101e04c3fSmrg "glUniform%u(\"%s\"@%d is %s, not %s)", 102201e04c3fSmrg src_components, uni->name, location, 102301e04c3fSmrg glsl_type_name(uni->type->base_type), 102401e04c3fSmrg glsl_type_name(basicType)); 102501e04c3fSmrg return NULL; 1026af69d88dSmrg } 1027af69d88dSmrg 102801e04c3fSmrg if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { 1029af69d88dSmrg log_uniform(values, basicType, components, 1, count, 103001e04c3fSmrg false, shProg, location, uni); 1031af69d88dSmrg } 1032af69d88dSmrg 1033af69d88dSmrg /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: 1034af69d88dSmrg * 1035af69d88dSmrg * "Setting a sampler's value to i selects texture image unit number 1036af69d88dSmrg * i. The values of i range from zero to the implementation- dependent 1037af69d88dSmrg * maximum supported number of texture image units." 1038af69d88dSmrg * 1039af69d88dSmrg * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of 1040af69d88dSmrg * the PDF) says: 1041af69d88dSmrg * 1042af69d88dSmrg * "Error Description Offending command 1043af69d88dSmrg * ignored? 1044af69d88dSmrg * ... 1045af69d88dSmrg * INVALID_VALUE Numeric argument out of range Yes" 1046af69d88dSmrg * 1047af69d88dSmrg * Based on that, when an invalid sampler is specified, we generate a 1048af69d88dSmrg * GL_INVALID_VALUE error and ignore the command. 1049af69d88dSmrg */ 1050af69d88dSmrg if (uni->type->is_sampler()) { 105101e04c3fSmrg for (int i = 0; i < count; i++) { 105201e04c3fSmrg const unsigned texUnit = ((unsigned *) values)[i]; 1053af69d88dSmrg 1054af69d88dSmrg /* check that the sampler (tex unit index) is legal */ 1055af69d88dSmrg if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { 1056af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 1057af69d88dSmrg "glUniform1i(invalid sampler/tex unit index for " 105801e04c3fSmrg "uniform %d)", location); 105901e04c3fSmrg return NULL; 1060af69d88dSmrg } 1061af69d88dSmrg } 106201e04c3fSmrg /* We need to reset the validate flag on changes to samplers in case 106301e04c3fSmrg * two different sampler types are set to the same texture unit. 106401e04c3fSmrg */ 10657ec681f3Smrg ctx->_Shader->Validated = ctx->_Shader->UserValidated = GL_FALSE; 1066af69d88dSmrg } 1067af69d88dSmrg 1068af69d88dSmrg if (uni->type->is_image()) { 106901e04c3fSmrg for (int i = 0; i < count; i++) { 1070af69d88dSmrg const int unit = ((GLint *) values)[i]; 1071af69d88dSmrg 1072af69d88dSmrg /* check that the image unit is legal */ 1073af69d88dSmrg if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) { 1074af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 1075af69d88dSmrg "glUniform1i(invalid image unit index for uniform %d)", 1076af69d88dSmrg location); 107701e04c3fSmrg return NULL; 1078af69d88dSmrg } 1079af69d88dSmrg } 1080af69d88dSmrg } 1081af69d88dSmrg 108201e04c3fSmrg return uni; 108301e04c3fSmrg} 108401e04c3fSmrg 108501e04c3fSmrgvoid 108601e04c3fSmrg_mesa_flush_vertices_for_uniforms(struct gl_context *ctx, 108701e04c3fSmrg const struct gl_uniform_storage *uni) 108801e04c3fSmrg{ 108901e04c3fSmrg /* Opaque uniforms have no storage unless they are bindless */ 109001e04c3fSmrg if (!uni->is_bindless && uni->type->contains_opaque()) { 10917ec681f3Smrg /* Samplers flush on demand and ignore redundant updates. */ 10927ec681f3Smrg if (!uni->type->is_sampler()) 10937ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 109401e04c3fSmrg return; 109501e04c3fSmrg } 109601e04c3fSmrg 109701e04c3fSmrg uint64_t new_driver_state = 0; 109801e04c3fSmrg unsigned mask = uni->active_shader_mask; 109901e04c3fSmrg 110001e04c3fSmrg while (mask) { 110101e04c3fSmrg unsigned index = u_bit_scan(&mask); 110201e04c3fSmrg 110301e04c3fSmrg assert(index < MESA_SHADER_STAGES); 110401e04c3fSmrg new_driver_state |= ctx->DriverFlags.NewShaderConstants[index]; 110501e04c3fSmrg } 110601e04c3fSmrg 11077ec681f3Smrg FLUSH_VERTICES(ctx, new_driver_state ? 0 : _NEW_PROGRAM_CONSTANTS, 0); 110801e04c3fSmrg ctx->NewDriverState |= new_driver_state; 110901e04c3fSmrg} 111001e04c3fSmrg 11117ec681f3Smrgstatic bool 111201e04c3fSmrgcopy_uniforms_to_storage(gl_constant_value *storage, 111301e04c3fSmrg struct gl_uniform_storage *uni, 111401e04c3fSmrg struct gl_context *ctx, GLsizei count, 111501e04c3fSmrg const GLvoid *values, const int size_mul, 111601e04c3fSmrg const unsigned offset, const unsigned components, 11177ec681f3Smrg enum glsl_base_type basicType, bool flush) 111801e04c3fSmrg{ 11197ec681f3Smrg const gl_constant_value *src = (const gl_constant_value*)values; 11207ec681f3Smrg bool copy_as_uint64 = uni->is_bindless && 11217ec681f3Smrg (uni->type->is_sampler() || uni->type->is_image()); 11227ec681f3Smrg bool copy_to_float16 = uni->type->base_type == GLSL_TYPE_FLOAT16; 11237ec681f3Smrg 11247ec681f3Smrg if (!uni->type->is_boolean() && !copy_as_uint64 && !copy_to_float16) { 11257ec681f3Smrg unsigned size = sizeof(storage[0]) * components * count * size_mul; 11267ec681f3Smrg 11277ec681f3Smrg if (!memcmp(storage, values, size)) 11287ec681f3Smrg return false; 112901e04c3fSmrg 11307ec681f3Smrg if (flush) 11317ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 11327ec681f3Smrg 11337ec681f3Smrg memcpy(storage, values, size); 11347ec681f3Smrg return true; 11357ec681f3Smrg } else if (copy_to_float16) { 11367ec681f3Smrg assert(ctx->Const.PackedDriverUniformStorage); 11377ec681f3Smrg const unsigned dst_components = align(components, 2); 11387ec681f3Smrg uint16_t *dst = (uint16_t*)storage; 11397ec681f3Smrg 11407ec681f3Smrg int i = 0; 11417ec681f3Smrg unsigned c = 0; 11427ec681f3Smrg 11437ec681f3Smrg if (flush) { 11447ec681f3Smrg /* Find the first element that's different. */ 11457ec681f3Smrg for (; i < count; i++) { 11467ec681f3Smrg for (; c < components; c++) { 11477ec681f3Smrg if (dst[c] != _mesa_float_to_half(src[c].f)) { 11487ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 11497ec681f3Smrg flush = false; 11507ec681f3Smrg goto break_loops; 11517ec681f3Smrg } 11527ec681f3Smrg } 11537ec681f3Smrg c = 0; 11547ec681f3Smrg dst += dst_components; 11557ec681f3Smrg src += components; 11567ec681f3Smrg } 11577ec681f3Smrg break_loops: 11587ec681f3Smrg if (flush) 11597ec681f3Smrg return false; /* No change. */ 116001e04c3fSmrg } 11617ec681f3Smrg 11627ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 11637ec681f3Smrg * different and that we have flushed. 11647ec681f3Smrg */ 11657ec681f3Smrg for (; i < count; i++) { 11667ec681f3Smrg for (; c < components; c++) 11677ec681f3Smrg dst[c] = _mesa_float_to_half(src[c].f); 11687ec681f3Smrg 11697ec681f3Smrg c = 0; 11707ec681f3Smrg dst += dst_components; 11717ec681f3Smrg src += components; 11727ec681f3Smrg } 11737ec681f3Smrg 11747ec681f3Smrg return true; 11757ec681f3Smrg } else if (copy_as_uint64) { 11767ec681f3Smrg const unsigned elems = components * count; 11777ec681f3Smrg uint64_t *dst = (uint64_t*)storage; 11787ec681f3Smrg unsigned i = 0; 11797ec681f3Smrg 11807ec681f3Smrg if (flush) { 11817ec681f3Smrg /* Find the first element that's different. */ 11827ec681f3Smrg for (; i < elems; i++) { 11837ec681f3Smrg if (dst[i] != src[i].u) { 11847ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 11857ec681f3Smrg flush = false; 11867ec681f3Smrg break; 11877ec681f3Smrg } 11887ec681f3Smrg } 11897ec681f3Smrg if (flush) 11907ec681f3Smrg return false; /* No change. */ 11917ec681f3Smrg } 11927ec681f3Smrg 11937ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 11947ec681f3Smrg * different and that we have flushed. 11957ec681f3Smrg */ 11967ec681f3Smrg for (; i < elems; i++) 11977ec681f3Smrg dst[i] = src[i].u; 11987ec681f3Smrg 11997ec681f3Smrg return true; 120001e04c3fSmrg } else { 120101e04c3fSmrg const unsigned elems = components * count; 12027ec681f3Smrg gl_constant_value *dst = storage; 12037ec681f3Smrg 12047ec681f3Smrg if (basicType == GLSL_TYPE_FLOAT) { 12057ec681f3Smrg unsigned i = 0; 12067ec681f3Smrg 12077ec681f3Smrg if (flush) { 12087ec681f3Smrg /* Find the first element that's different. */ 12097ec681f3Smrg for (; i < elems; i++) { 12107ec681f3Smrg if (dst[i].u != 12117ec681f3Smrg (src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0)) { 12127ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 12137ec681f3Smrg flush = false; 12147ec681f3Smrg break; 12157ec681f3Smrg } 12167ec681f3Smrg } 12177ec681f3Smrg if (flush) 12187ec681f3Smrg return false; /* No change. */ 12197ec681f3Smrg } 12207ec681f3Smrg 12217ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 12227ec681f3Smrg * different and that we have flushed. 12237ec681f3Smrg */ 12247ec681f3Smrg for (; i < elems; i++) 12257ec681f3Smrg dst[i].u = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0; 122601e04c3fSmrg 12277ec681f3Smrg return true; 12287ec681f3Smrg } else { 12297ec681f3Smrg unsigned i = 0; 12307ec681f3Smrg 12317ec681f3Smrg if (flush) { 12327ec681f3Smrg /* Find the first element that's different. */ 12337ec681f3Smrg for (; i < elems; i++) { 12347ec681f3Smrg if (dst[i].u != 12357ec681f3Smrg (src[i].u ? ctx->Const.UniformBooleanTrue : 0)) { 12367ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 12377ec681f3Smrg flush = false; 12387ec681f3Smrg break; 12397ec681f3Smrg } 12407ec681f3Smrg } 12417ec681f3Smrg if (flush) 12427ec681f3Smrg return false; /* No change. */ 124301e04c3fSmrg } 12447ec681f3Smrg 12457ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 12467ec681f3Smrg * different and that we have flushed. 12477ec681f3Smrg */ 12487ec681f3Smrg for (; i < elems; i++) 12497ec681f3Smrg dst[i].u = src[i].u ? ctx->Const.UniformBooleanTrue : 0; 12507ec681f3Smrg 12517ec681f3Smrg return true; 125201e04c3fSmrg } 125301e04c3fSmrg } 125401e04c3fSmrg} 125501e04c3fSmrg 125601e04c3fSmrg 125701e04c3fSmrg/** 125801e04c3fSmrg * Called via glUniform*() functions. 125901e04c3fSmrg */ 126001e04c3fSmrgextern "C" void 126101e04c3fSmrg_mesa_uniform(GLint location, GLsizei count, const GLvoid *values, 126201e04c3fSmrg struct gl_context *ctx, struct gl_shader_program *shProg, 126301e04c3fSmrg enum glsl_base_type basicType, unsigned src_components) 126401e04c3fSmrg{ 126501e04c3fSmrg unsigned offset; 126601e04c3fSmrg int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1; 126701e04c3fSmrg 126801e04c3fSmrg struct gl_uniform_storage *uni; 126901e04c3fSmrg if (_mesa_is_no_error_enabled(ctx)) { 127001e04c3fSmrg /* From Seciton 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec: 127101e04c3fSmrg * 127201e04c3fSmrg * "If the value of location is -1, the Uniform* commands will 127301e04c3fSmrg * silently ignore the data passed in, and the current uniform values 127401e04c3fSmrg * will not be changed. 127501e04c3fSmrg */ 127601e04c3fSmrg if (location == -1) 127701e04c3fSmrg return; 127801e04c3fSmrg 12797ec681f3Smrg if (location >= (int)shProg->NumUniformRemapTable) 12807ec681f3Smrg return; 12817ec681f3Smrg 128201e04c3fSmrg uni = shProg->UniformRemapTable[location]; 12837ec681f3Smrg if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) 12847ec681f3Smrg return; 128501e04c3fSmrg 128601e04c3fSmrg /* The array index specified by the uniform location is just the 128701e04c3fSmrg * uniform location minus the base location of of the uniform. 128801e04c3fSmrg */ 128901e04c3fSmrg assert(uni->array_elements > 0 || location == (int)uni->remap_location); 129001e04c3fSmrg offset = location - uni->remap_location; 129101e04c3fSmrg } else { 129201e04c3fSmrg uni = validate_uniform(location, count, values, &offset, ctx, shProg, 129301e04c3fSmrg basicType, src_components); 129401e04c3fSmrg if (!uni) 129501e04c3fSmrg return; 129601e04c3fSmrg } 129701e04c3fSmrg 129801e04c3fSmrg const unsigned components = uni->type->vector_elements; 129901e04c3fSmrg 1300af69d88dSmrg /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 1301af69d88dSmrg * 1302af69d88dSmrg * "When loading N elements starting at an arbitrary position k in a 1303af69d88dSmrg * uniform declared as an array, elements k through k + N - 1 in the 1304af69d88dSmrg * array will be replaced with the new values. Values for any array 1305af69d88dSmrg * element that exceeds the highest array element index used, as 1306af69d88dSmrg * reported by GetActiveUniform, will be ignored by the GL." 1307af69d88dSmrg * 1308af69d88dSmrg * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 1309af69d88dSmrg * will have already generated an error. 1310af69d88dSmrg */ 1311af69d88dSmrg if (uni->array_elements != 0) { 1312af69d88dSmrg count = MIN2(count, (int) (uni->array_elements - offset)); 1313af69d88dSmrg } 1314af69d88dSmrg 1315af69d88dSmrg /* Store the data in the "actual type" backing storage for the uniform. 1316af69d88dSmrg */ 13177ec681f3Smrg bool ctx_flushed = false; 131801e04c3fSmrg gl_constant_value *storage; 131901e04c3fSmrg if (ctx->Const.PackedDriverUniformStorage && 132001e04c3fSmrg (uni->is_bindless || !uni->type->contains_opaque())) { 132101e04c3fSmrg for (unsigned s = 0; s < uni->num_driver_storage; s++) { 13227ec681f3Smrg unsigned dword_components = components; 13237ec681f3Smrg 13247ec681f3Smrg /* 16-bit uniforms are packed. */ 13257ec681f3Smrg if (glsl_base_type_is_16bit(uni->type->base_type)) 13267ec681f3Smrg dword_components = DIV_ROUND_UP(dword_components, 2); 13277ec681f3Smrg 132801e04c3fSmrg storage = (gl_constant_value *) 13297ec681f3Smrg uni->driver_storage[s].data + (size_mul * offset * dword_components); 133001e04c3fSmrg 13317ec681f3Smrg if (copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul, 13327ec681f3Smrg offset, components, basicType, !ctx_flushed)) 13337ec681f3Smrg ctx_flushed = true; 133401e04c3fSmrg } 1335af69d88dSmrg } else { 133601e04c3fSmrg storage = &uni->storage[size_mul * components * offset]; 13377ec681f3Smrg if (copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul, 13387ec681f3Smrg offset, components, basicType, !ctx_flushed)) { 13397ec681f3Smrg _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); 13407ec681f3Smrg ctx_flushed = true; 13417ec681f3Smrg } 1342af69d88dSmrg } 13437ec681f3Smrg /* Return early if possible. Bindless samplers need to be processed 13447ec681f3Smrg * because of the !sampler->bound codepath below. 13457ec681f3Smrg */ 13467ec681f3Smrg if (!ctx_flushed && !(uni->type->is_sampler() && uni->is_bindless)) 13477ec681f3Smrg return; /* no change in uniform values */ 1348af69d88dSmrg 1349af69d88dSmrg /* If the uniform is a sampler, do the extra magic necessary to propagate 1350af69d88dSmrg * the changes through. 1351af69d88dSmrg */ 1352af69d88dSmrg if (uni->type->is_sampler()) { 13537ec681f3Smrg /* Note that samplers are the only uniforms that don't call 13547ec681f3Smrg * FLUSH_VERTICES above. 13557ec681f3Smrg */ 1356af69d88dSmrg bool flushed = false; 13577ec681f3Smrg bool any_changed = false; 1358af69d88dSmrg 135901e04c3fSmrg shProg->SamplersValidated = GL_TRUE; 1360af69d88dSmrg 136101e04c3fSmrg for (int i = 0; i < MESA_SHADER_STAGES; i++) { 136201e04c3fSmrg struct gl_linked_shader *const sh = shProg->_LinkedShaders[i]; 1363af69d88dSmrg 136401e04c3fSmrg /* If the shader stage doesn't use the sampler uniform, skip this. */ 136501e04c3fSmrg if (!uni->opaque[i].active) 136601e04c3fSmrg continue; 1367af69d88dSmrg 136801e04c3fSmrg bool changed = false; 136901e04c3fSmrg for (int j = 0; j < count; j++) { 137001e04c3fSmrg unsigned unit = uni->opaque[i].index + offset + j; 137101e04c3fSmrg unsigned value = ((unsigned *)values)[j]; 137201e04c3fSmrg 137301e04c3fSmrg if (uni->is_bindless) { 137401e04c3fSmrg struct gl_bindless_sampler *sampler = 137501e04c3fSmrg &sh->Program->sh.BindlessSamplers[unit]; 137601e04c3fSmrg 137701e04c3fSmrg /* Mark this bindless sampler as bound to a texture unit. 137801e04c3fSmrg */ 137901e04c3fSmrg if (sampler->unit != value || !sampler->bound) { 13807ec681f3Smrg if (!flushed) { 13817ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM, 0); 13827ec681f3Smrg flushed = true; 13837ec681f3Smrg } 138401e04c3fSmrg sampler->unit = value; 138501e04c3fSmrg changed = true; 138601e04c3fSmrg } 138701e04c3fSmrg sampler->bound = true; 138801e04c3fSmrg sh->Program->sh.HasBoundBindlessSampler = true; 138901e04c3fSmrg } else { 139001e04c3fSmrg if (sh->Program->SamplerUnits[unit] != value) { 13917ec681f3Smrg if (!flushed) { 13927ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM, 0); 13937ec681f3Smrg flushed = true; 13947ec681f3Smrg } 139501e04c3fSmrg sh->Program->SamplerUnits[unit] = value; 139601e04c3fSmrg changed = true; 139701e04c3fSmrg } 139801e04c3fSmrg } 139901e04c3fSmrg } 1400af69d88dSmrg 140101e04c3fSmrg if (changed) { 140201e04c3fSmrg struct gl_program *const prog = sh->Program; 140301e04c3fSmrg _mesa_update_shader_textures_used(shProg, prog); 1404af69d88dSmrg if (ctx->Driver.SamplerUniformChange) 140501e04c3fSmrg ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog); 14067ec681f3Smrg any_changed = true; 140701e04c3fSmrg } 1408af69d88dSmrg } 14097ec681f3Smrg 14107ec681f3Smrg if (any_changed) 14117ec681f3Smrg _mesa_update_valid_to_render_state(ctx); 1412af69d88dSmrg } 1413af69d88dSmrg 1414af69d88dSmrg /* If the uniform is an image, update the mapping from image 1415af69d88dSmrg * uniforms to image units present in the shader data structure. 1416af69d88dSmrg */ 1417af69d88dSmrg if (uni->type->is_image()) { 141801e04c3fSmrg for (int i = 0; i < MESA_SHADER_STAGES; i++) { 141901e04c3fSmrg struct gl_linked_shader *sh = shProg->_LinkedShaders[i]; 1420af69d88dSmrg 142101e04c3fSmrg /* If the shader stage doesn't use the image uniform, skip this. */ 142201e04c3fSmrg if (!uni->opaque[i].active) 142301e04c3fSmrg continue; 1424af69d88dSmrg 142501e04c3fSmrg for (int j = 0; j < count; j++) { 142601e04c3fSmrg unsigned unit = uni->opaque[i].index + offset + j; 142701e04c3fSmrg unsigned value = ((unsigned *)values)[j]; 142801e04c3fSmrg 142901e04c3fSmrg if (uni->is_bindless) { 143001e04c3fSmrg struct gl_bindless_image *image = 143101e04c3fSmrg &sh->Program->sh.BindlessImages[unit]; 143201e04c3fSmrg 143301e04c3fSmrg /* Mark this bindless image as bound to an image unit. 143401e04c3fSmrg */ 143501e04c3fSmrg image->unit = value; 143601e04c3fSmrg image->bound = true; 143701e04c3fSmrg sh->Program->sh.HasBoundBindlessImage = true; 143801e04c3fSmrg } else { 143901e04c3fSmrg sh->Program->sh.ImageUnits[unit] = value; 144001e04c3fSmrg } 1441af69d88dSmrg } 1442af69d88dSmrg } 1443af69d88dSmrg 1444af69d88dSmrg ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; 1445af69d88dSmrg } 1446af69d88dSmrg} 1447af69d88dSmrg 144801e04c3fSmrg 14497ec681f3Smrgstatic bool 14507ec681f3Smrgcopy_uniform_matrix_to_storage(struct gl_context *ctx, 14517ec681f3Smrg gl_constant_value *storage, 14527ec681f3Smrg struct gl_uniform_storage *const uni, 14537ec681f3Smrg unsigned count, const void *values, 145401e04c3fSmrg const unsigned size_mul, const unsigned offset, 145501e04c3fSmrg const unsigned components, 145601e04c3fSmrg const unsigned vectors, bool transpose, 145701e04c3fSmrg unsigned cols, unsigned rows, 14587ec681f3Smrg enum glsl_base_type basicType, bool flush) 145901e04c3fSmrg{ 146001e04c3fSmrg const unsigned elements = components * vectors; 14617ec681f3Smrg const unsigned size = sizeof(storage[0]) * elements * count * size_mul; 14627ec681f3Smrg 14637ec681f3Smrg if (uni->type->base_type == GLSL_TYPE_FLOAT16) { 14647ec681f3Smrg assert(ctx->Const.PackedDriverUniformStorage); 14657ec681f3Smrg const unsigned dst_components = align(components, 2); 14667ec681f3Smrg const unsigned dst_elements = dst_components * vectors; 14677ec681f3Smrg 14687ec681f3Smrg if (!transpose) { 14697ec681f3Smrg const float *src = (const float *)values; 14707ec681f3Smrg uint16_t *dst = (uint16_t*)storage; 14717ec681f3Smrg 14727ec681f3Smrg unsigned i = 0, r = 0, c = 0; 14737ec681f3Smrg 14747ec681f3Smrg if (flush) { 14757ec681f3Smrg /* Find the first element that's different. */ 14767ec681f3Smrg for (; i < count; i++) { 14777ec681f3Smrg for (; c < cols; c++) { 14787ec681f3Smrg for (; r < rows; r++) { 14797ec681f3Smrg if (dst[(c * dst_components) + r] != 14807ec681f3Smrg _mesa_float_to_half(src[(c * components) + r])) { 14817ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 14827ec681f3Smrg flush = false; 14837ec681f3Smrg goto break_loops_16bit; 14847ec681f3Smrg } 14857ec681f3Smrg } 14867ec681f3Smrg r = 0; 14877ec681f3Smrg } 14887ec681f3Smrg c = 0; 14897ec681f3Smrg dst += dst_elements; 14907ec681f3Smrg src += elements; 14917ec681f3Smrg } 14927ec681f3Smrg 14937ec681f3Smrg break_loops_16bit: 14947ec681f3Smrg if (flush) 14957ec681f3Smrg return false; /* No change. */ 14967ec681f3Smrg } 14977ec681f3Smrg 14987ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 14997ec681f3Smrg * different and that we have flushed. 15007ec681f3Smrg */ 15017ec681f3Smrg for (; i < count; i++) { 15027ec681f3Smrg for (; c < cols; c++) { 15037ec681f3Smrg for (; r < rows; r++) { 15047ec681f3Smrg dst[(c * dst_components) + r] = 15057ec681f3Smrg _mesa_float_to_half(src[(c * components) + r]); 15067ec681f3Smrg } 15077ec681f3Smrg r = 0; 15087ec681f3Smrg } 15097ec681f3Smrg c = 0; 15107ec681f3Smrg dst += dst_elements; 15117ec681f3Smrg src += elements; 15127ec681f3Smrg } 15137ec681f3Smrg return true; 15147ec681f3Smrg } else { 15157ec681f3Smrg /* Transpose the matrix. */ 15167ec681f3Smrg const float *src = (const float *)values; 15177ec681f3Smrg uint16_t *dst = (uint16_t*)storage; 15187ec681f3Smrg 15197ec681f3Smrg unsigned i = 0, r = 0, c = 0; 15207ec681f3Smrg 15217ec681f3Smrg if (flush) { 15227ec681f3Smrg /* Find the first element that's different. */ 15237ec681f3Smrg for (; i < count; i++) { 15247ec681f3Smrg for (; r < rows; r++) { 15257ec681f3Smrg for (; c < cols; c++) { 15267ec681f3Smrg if (dst[(c * dst_components) + r] != 15277ec681f3Smrg _mesa_float_to_half(src[c + (r * vectors)])) { 15287ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 15297ec681f3Smrg flush = false; 15307ec681f3Smrg goto break_loops_16bit_transpose; 15317ec681f3Smrg } 15327ec681f3Smrg } 15337ec681f3Smrg c = 0; 15347ec681f3Smrg } 15357ec681f3Smrg r = 0; 15367ec681f3Smrg dst += elements; 15377ec681f3Smrg src += elements; 15387ec681f3Smrg } 15397ec681f3Smrg 15407ec681f3Smrg break_loops_16bit_transpose: 15417ec681f3Smrg if (flush) 15427ec681f3Smrg return false; /* No change. */ 15437ec681f3Smrg } 15447ec681f3Smrg 15457ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 15467ec681f3Smrg * different and that we have flushed. 15477ec681f3Smrg */ 15487ec681f3Smrg for (; i < count; i++) { 15497ec681f3Smrg for (; r < rows; r++) { 15507ec681f3Smrg for (; c < cols; c++) { 15517ec681f3Smrg dst[(c * dst_components) + r] = 15527ec681f3Smrg _mesa_float_to_half(src[c + (r * vectors)]); 15537ec681f3Smrg } 15547ec681f3Smrg c = 0; 15557ec681f3Smrg } 15567ec681f3Smrg r = 0; 15577ec681f3Smrg dst += elements; 15587ec681f3Smrg src += elements; 15597ec681f3Smrg } 15607ec681f3Smrg return true; 15617ec681f3Smrg } 15627ec681f3Smrg } else if (!transpose) { 15637ec681f3Smrg if (!memcmp(storage, values, size)) 15647ec681f3Smrg return false; 156501e04c3fSmrg 15667ec681f3Smrg if (flush) 15677ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 15687ec681f3Smrg 15697ec681f3Smrg memcpy(storage, values, size); 15707ec681f3Smrg return true; 157101e04c3fSmrg } else if (basicType == GLSL_TYPE_FLOAT) { 15727ec681f3Smrg /* Transpose the matrix. */ 157301e04c3fSmrg const float *src = (const float *)values; 15747ec681f3Smrg float *dst = (float*)storage; 15757ec681f3Smrg 15767ec681f3Smrg unsigned i = 0, r = 0, c = 0; 15777ec681f3Smrg 15787ec681f3Smrg if (flush) { 15797ec681f3Smrg /* Find the first element that's different. */ 15807ec681f3Smrg for (; i < count; i++) { 15817ec681f3Smrg for (; r < rows; r++) { 15827ec681f3Smrg for (; c < cols; c++) { 15837ec681f3Smrg if (dst[(c * components) + r] != src[c + (r * vectors)]) { 15847ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 15857ec681f3Smrg flush = false; 15867ec681f3Smrg goto break_loops; 15877ec681f3Smrg } 15887ec681f3Smrg } 15897ec681f3Smrg c = 0; 159001e04c3fSmrg } 15917ec681f3Smrg r = 0; 15927ec681f3Smrg dst += elements; 15937ec681f3Smrg src += elements; 159401e04c3fSmrg } 159501e04c3fSmrg 15967ec681f3Smrg break_loops: 15977ec681f3Smrg if (flush) 15987ec681f3Smrg return false; /* No change. */ 15997ec681f3Smrg } 16007ec681f3Smrg 16017ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 16027ec681f3Smrg * different and that we have flushed. 16037ec681f3Smrg */ 16047ec681f3Smrg for (; i < count; i++) { 16057ec681f3Smrg for (; r < rows; r++) { 16067ec681f3Smrg for (; c < cols; c++) 16077ec681f3Smrg dst[(c * components) + r] = src[c + (r * vectors)]; 16087ec681f3Smrg c = 0; 16097ec681f3Smrg } 16107ec681f3Smrg r = 0; 161101e04c3fSmrg dst += elements; 161201e04c3fSmrg src += elements; 161301e04c3fSmrg } 16147ec681f3Smrg return true; 161501e04c3fSmrg } else { 161601e04c3fSmrg assert(basicType == GLSL_TYPE_DOUBLE); 161701e04c3fSmrg const double *src = (const double *)values; 16187ec681f3Smrg double *dst = (double*)storage; 16197ec681f3Smrg 16207ec681f3Smrg unsigned i = 0, r = 0, c = 0; 16217ec681f3Smrg 16227ec681f3Smrg if (flush) { 16237ec681f3Smrg /* Find the first element that's different. */ 16247ec681f3Smrg for (; i < count; i++) { 16257ec681f3Smrg for (; r < rows; r++) { 16267ec681f3Smrg for (; c < cols; c++) { 16277ec681f3Smrg if (dst[(c * components) + r] != src[c + (r * vectors)]) { 16287ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 16297ec681f3Smrg flush = false; 16307ec681f3Smrg goto break_loops2; 16317ec681f3Smrg } 16327ec681f3Smrg } 16337ec681f3Smrg c = 0; 163401e04c3fSmrg } 16357ec681f3Smrg r = 0; 16367ec681f3Smrg dst += elements; 16377ec681f3Smrg src += elements; 163801e04c3fSmrg } 163901e04c3fSmrg 16407ec681f3Smrg break_loops2: 16417ec681f3Smrg if (flush) 16427ec681f3Smrg return false; /* No change. */ 16437ec681f3Smrg } 16447ec681f3Smrg 16457ec681f3Smrg /* Set the remaining elements. We know that at least 1 element is 16467ec681f3Smrg * different and that we have flushed. 16477ec681f3Smrg */ 16487ec681f3Smrg for (; i < count; i++) { 16497ec681f3Smrg for (; r < rows; r++) { 16507ec681f3Smrg for (; c < cols; c++) 16517ec681f3Smrg dst[(c * components) + r] = src[c + (r * vectors)]; 16527ec681f3Smrg c = 0; 16537ec681f3Smrg } 16547ec681f3Smrg r = 0; 165501e04c3fSmrg dst += elements; 165601e04c3fSmrg src += elements; 165701e04c3fSmrg } 16587ec681f3Smrg return true; 165901e04c3fSmrg } 166001e04c3fSmrg} 166101e04c3fSmrg 166201e04c3fSmrg 1663af69d88dSmrg/** 1664af69d88dSmrg * Called by glUniformMatrix*() functions. 1665af69d88dSmrg * Note: cols=2, rows=4 ==> array[2] of vec4 1666af69d88dSmrg */ 1667af69d88dSmrgextern "C" void 166801e04c3fSmrg_mesa_uniform_matrix(GLint location, GLsizei count, 166901e04c3fSmrg GLboolean transpose, const void *values, 167001e04c3fSmrg struct gl_context *ctx, struct gl_shader_program *shProg, 167101e04c3fSmrg GLuint cols, GLuint rows, enum glsl_base_type basicType) 1672af69d88dSmrg{ 1673af69d88dSmrg unsigned offset; 1674af69d88dSmrg struct gl_uniform_storage *const uni = 167501e04c3fSmrg validate_uniform_parameters(location, count, &offset, 167601e04c3fSmrg ctx, shProg, "glUniformMatrix"); 1677af69d88dSmrg if (uni == NULL) 1678af69d88dSmrg return; 1679af69d88dSmrg 16807ec681f3Smrg /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE. 16817ec681f3Smrg * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml 16827ec681f3Smrg */ 16837ec681f3Smrg if (transpose) { 16847ec681f3Smrg if (ctx->API == API_OPENGLES2 && ctx->Version < 30) { 16857ec681f3Smrg _mesa_error(ctx, GL_INVALID_VALUE, 16867ec681f3Smrg "glUniformMatrix(matrix transpose is not GL_FALSE)"); 16877ec681f3Smrg return; 16887ec681f3Smrg } 16897ec681f3Smrg } 16907ec681f3Smrg 1691af69d88dSmrg if (!uni->type->is_matrix()) { 1692af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1693af69d88dSmrg "glUniformMatrix(non-matrix uniform)"); 1694af69d88dSmrg return; 1695af69d88dSmrg } 1696af69d88dSmrg 169701e04c3fSmrg assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE); 169801e04c3fSmrg const unsigned size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1; 169901e04c3fSmrg 1700af69d88dSmrg assert(!uni->type->is_sampler()); 170101e04c3fSmrg const unsigned vectors = uni->type->matrix_columns; 170201e04c3fSmrg const unsigned components = uni->type->vector_elements; 1703af69d88dSmrg 1704af69d88dSmrg /* Verify that the types are compatible. This is greatly simplified for 1705af69d88dSmrg * matrices because they can only have a float base type. 1706af69d88dSmrg */ 1707af69d88dSmrg if (vectors != cols || components != rows) { 1708af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1709af69d88dSmrg "glUniformMatrix(matrix size mismatch)"); 1710af69d88dSmrg return; 1711af69d88dSmrg } 1712af69d88dSmrg 171301e04c3fSmrg /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec 171401e04c3fSmrg * says: 171501e04c3fSmrg * 171601e04c3fSmrg * "If any of the following conditions occur, an INVALID_OPERATION 171701e04c3fSmrg * error is generated by the Uniform* commands, and no uniform values 171801e04c3fSmrg * are changed: 171901e04c3fSmrg * 172001e04c3fSmrg * ... 172101e04c3fSmrg * 172201e04c3fSmrg * - if the uniform declared in the shader is not of type boolean and 172301e04c3fSmrg * the type indicated in the name of the Uniform* command used does 172401e04c3fSmrg * not match the type of the uniform" 172501e04c3fSmrg * 172601e04c3fSmrg * There are no Boolean matrix types, so we do not need to allow 172701e04c3fSmrg * GLSL_TYPE_BOOL here (as _mesa_uniform does). 172801e04c3fSmrg */ 17297ec681f3Smrg if (uni->type->base_type != basicType && 17307ec681f3Smrg !(uni->type->base_type == GLSL_TYPE_FLOAT16 && 17317ec681f3Smrg basicType == GLSL_TYPE_FLOAT)) { 173201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 173301e04c3fSmrg "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)", 173401e04c3fSmrg cols, rows, uni->name, location, 173501e04c3fSmrg glsl_type_name(uni->type->base_type), 173601e04c3fSmrg glsl_type_name(basicType)); 173701e04c3fSmrg return; 173801e04c3fSmrg } 173901e04c3fSmrg 174001e04c3fSmrg if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { 174101e04c3fSmrg log_uniform(values, uni->type->base_type, components, vectors, count, 1742af69d88dSmrg bool(transpose), shProg, location, uni); 1743af69d88dSmrg } 1744af69d88dSmrg 1745af69d88dSmrg /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 1746af69d88dSmrg * 1747af69d88dSmrg * "When loading N elements starting at an arbitrary position k in a 1748af69d88dSmrg * uniform declared as an array, elements k through k + N - 1 in the 1749af69d88dSmrg * array will be replaced with the new values. Values for any array 1750af69d88dSmrg * element that exceeds the highest array element index used, as 1751af69d88dSmrg * reported by GetActiveUniform, will be ignored by the GL." 1752af69d88dSmrg * 1753af69d88dSmrg * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 1754af69d88dSmrg * will have already generated an error. 1755af69d88dSmrg */ 1756af69d88dSmrg if (uni->array_elements != 0) { 1757af69d88dSmrg count = MIN2(count, (int) (uni->array_elements - offset)); 1758af69d88dSmrg } 1759af69d88dSmrg 1760af69d88dSmrg /* Store the data in the "actual type" backing storage for the uniform. 1761af69d88dSmrg */ 176201e04c3fSmrg gl_constant_value *storage; 176301e04c3fSmrg const unsigned elements = components * vectors; 176401e04c3fSmrg if (ctx->Const.PackedDriverUniformStorage) { 17657ec681f3Smrg bool flushed = false; 17667ec681f3Smrg 176701e04c3fSmrg for (unsigned s = 0; s < uni->num_driver_storage; s++) { 17687ec681f3Smrg unsigned dword_components = components; 17697ec681f3Smrg 17707ec681f3Smrg /* 16-bit uniforms are packed. */ 17717ec681f3Smrg if (glsl_base_type_is_16bit(uni->type->base_type)) 17727ec681f3Smrg dword_components = DIV_ROUND_UP(dword_components, 2); 177301e04c3fSmrg 17747ec681f3Smrg storage = (gl_constant_value *) 17757ec681f3Smrg uni->driver_storage[s].data + 17767ec681f3Smrg (size_mul * offset * dword_components * vectors); 17777ec681f3Smrg 17787ec681f3Smrg if (copy_uniform_matrix_to_storage(ctx, storage, uni, count, values, 17797ec681f3Smrg size_mul, offset, components, 17807ec681f3Smrg vectors, transpose, cols, rows, 17817ec681f3Smrg basicType, !flushed)) 17827ec681f3Smrg flushed = true; 178301e04c3fSmrg } 1784af69d88dSmrg } else { 178501e04c3fSmrg storage = &uni->storage[size_mul * elements * offset]; 17867ec681f3Smrg if (copy_uniform_matrix_to_storage(ctx, storage, uni, count, values, 17877ec681f3Smrg size_mul, offset, components, vectors, 17887ec681f3Smrg transpose, cols, rows, basicType, 17897ec681f3Smrg true)) 17907ec681f3Smrg _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); 1791af69d88dSmrg } 179201e04c3fSmrg} 179301e04c3fSmrg 179401e04c3fSmrgstatic void 179501e04c3fSmrgupdate_bound_bindless_sampler_flag(struct gl_program *prog) 179601e04c3fSmrg{ 179701e04c3fSmrg unsigned i; 179801e04c3fSmrg 179901e04c3fSmrg if (likely(!prog->sh.HasBoundBindlessSampler)) 180001e04c3fSmrg return; 1801af69d88dSmrg 180201e04c3fSmrg for (i = 0; i < prog->sh.NumBindlessSamplers; i++) { 180301e04c3fSmrg struct gl_bindless_sampler *sampler = &prog->sh.BindlessSamplers[i]; 1804af69d88dSmrg 180501e04c3fSmrg if (sampler->bound) 180601e04c3fSmrg return; 180701e04c3fSmrg } 180801e04c3fSmrg prog->sh.HasBoundBindlessSampler = false; 1809af69d88dSmrg} 1810af69d88dSmrg 181101e04c3fSmrgstatic void 181201e04c3fSmrgupdate_bound_bindless_image_flag(struct gl_program *prog) 181301e04c3fSmrg{ 181401e04c3fSmrg unsigned i; 181501e04c3fSmrg 181601e04c3fSmrg if (likely(!prog->sh.HasBoundBindlessImage)) 181701e04c3fSmrg return; 181801e04c3fSmrg 181901e04c3fSmrg for (i = 0; i < prog->sh.NumBindlessImages; i++) { 182001e04c3fSmrg struct gl_bindless_image *image = &prog->sh.BindlessImages[i]; 182101e04c3fSmrg 182201e04c3fSmrg if (image->bound) 182301e04c3fSmrg return; 182401e04c3fSmrg } 182501e04c3fSmrg prog->sh.HasBoundBindlessImage = false; 182601e04c3fSmrg} 1827af69d88dSmrg 1828af69d88dSmrg/** 182901e04c3fSmrg * Called via glUniformHandleui64*ARB() functions. 1830af69d88dSmrg */ 183101e04c3fSmrgextern "C" void 183201e04c3fSmrg_mesa_uniform_handle(GLint location, GLsizei count, const GLvoid *values, 183301e04c3fSmrg struct gl_context *ctx, struct gl_shader_program *shProg) 1834af69d88dSmrg{ 183501e04c3fSmrg unsigned offset; 183601e04c3fSmrg struct gl_uniform_storage *uni; 1837af69d88dSmrg 183801e04c3fSmrg if (_mesa_is_no_error_enabled(ctx)) { 183901e04c3fSmrg /* From Section 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec: 184001e04c3fSmrg * 184101e04c3fSmrg * "If the value of location is -1, the Uniform* commands will 184201e04c3fSmrg * silently ignore the data passed in, and the current uniform values 184301e04c3fSmrg * will not be changed. 184401e04c3fSmrg */ 184501e04c3fSmrg if (location == -1) 184601e04c3fSmrg return; 1847af69d88dSmrg 184801e04c3fSmrg uni = shProg->UniformRemapTable[location]; 18497ec681f3Smrg if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) 18507ec681f3Smrg return; 185101e04c3fSmrg 185201e04c3fSmrg /* The array index specified by the uniform location is just the 185301e04c3fSmrg * uniform location minus the base location of of the uniform. 185401e04c3fSmrg */ 185501e04c3fSmrg assert(uni->array_elements > 0 || location == (int)uni->remap_location); 185601e04c3fSmrg offset = location - uni->remap_location; 1857af69d88dSmrg } else { 185801e04c3fSmrg uni = validate_uniform_parameters(location, count, &offset, 185901e04c3fSmrg ctx, shProg, "glUniformHandleui64*ARB"); 186001e04c3fSmrg if (!uni) 186101e04c3fSmrg return; 186201e04c3fSmrg 186301e04c3fSmrg if (!uni->is_bindless) { 186401e04c3fSmrg /* From section "Errors" of the ARB_bindless_texture spec: 186501e04c3fSmrg * 186601e04c3fSmrg * "The error INVALID_OPERATION is generated by 186701e04c3fSmrg * UniformHandleui64{v}ARB if the sampler or image uniform being 186801e04c3fSmrg * updated has the "bound_sampler" or "bound_image" layout qualifier." 186901e04c3fSmrg * 187001e04c3fSmrg * From section 4.4.6 of the ARB_bindless_texture spec: 187101e04c3fSmrg * 187201e04c3fSmrg * "In the absence of these qualifiers, sampler and image uniforms are 187301e04c3fSmrg * considered "bound". Additionally, if GL_ARB_bindless_texture is 187401e04c3fSmrg * not enabled, these uniforms are considered "bound"." 187501e04c3fSmrg */ 187601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 187701e04c3fSmrg "glUniformHandleui64*ARB(non-bindless sampler/image uniform)"); 187801e04c3fSmrg return; 187901e04c3fSmrg } 1880af69d88dSmrg } 1881af69d88dSmrg 188201e04c3fSmrg const unsigned components = uni->type->vector_elements; 188301e04c3fSmrg const int size_mul = 2; 1884af69d88dSmrg 188501e04c3fSmrg if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { 188601e04c3fSmrg log_uniform(values, GLSL_TYPE_UINT64, components, 1, count, 188701e04c3fSmrg false, shProg, location, uni); 188801e04c3fSmrg } 1889af69d88dSmrg 189001e04c3fSmrg /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 189101e04c3fSmrg * 189201e04c3fSmrg * "When loading N elements starting at an arbitrary position k in a 189301e04c3fSmrg * uniform declared as an array, elements k through k + N - 1 in the 189401e04c3fSmrg * array will be replaced with the new values. Values for any array 189501e04c3fSmrg * element that exceeds the highest array element index used, as 189601e04c3fSmrg * reported by GetActiveUniform, will be ignored by the GL." 189701e04c3fSmrg * 189801e04c3fSmrg * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 189901e04c3fSmrg * will have already generated an error. 1900af69d88dSmrg */ 190101e04c3fSmrg if (uni->array_elements != 0) { 190201e04c3fSmrg count = MIN2(count, (int) (uni->array_elements - offset)); 190301e04c3fSmrg } 1904af69d88dSmrg 1905af69d88dSmrg 190601e04c3fSmrg /* Store the data in the "actual type" backing storage for the uniform. 1907af69d88dSmrg */ 190801e04c3fSmrg if (ctx->Const.PackedDriverUniformStorage) { 19097ec681f3Smrg bool flushed = false; 19107ec681f3Smrg 191101e04c3fSmrg for (unsigned s = 0; s < uni->num_driver_storage; s++) { 19127ec681f3Smrg void *storage = (gl_constant_value *) 191301e04c3fSmrg uni->driver_storage[s].data + (size_mul * offset * components); 19147ec681f3Smrg unsigned size = sizeof(uni->storage[0]) * components * count * size_mul; 19157ec681f3Smrg 19167ec681f3Smrg if (!memcmp(storage, values, size)) 19177ec681f3Smrg continue; 19187ec681f3Smrg 19197ec681f3Smrg if (!flushed) { 19207ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 19217ec681f3Smrg flushed = true; 19227ec681f3Smrg } 19237ec681f3Smrg memcpy(storage, values, size); 192401e04c3fSmrg } 19257ec681f3Smrg if (!flushed) 19267ec681f3Smrg return; 192701e04c3fSmrg } else { 19287ec681f3Smrg void *storage = &uni->storage[size_mul * components * offset]; 19297ec681f3Smrg unsigned size = sizeof(uni->storage[0]) * components * count * size_mul; 19307ec681f3Smrg 19317ec681f3Smrg if (!memcmp(storage, values, size)) 19327ec681f3Smrg return; 193301e04c3fSmrg 19347ec681f3Smrg _mesa_flush_vertices_for_uniforms(ctx, uni); 19357ec681f3Smrg memcpy(storage, values, size); 193601e04c3fSmrg _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); 1937af69d88dSmrg } 1938af69d88dSmrg 193901e04c3fSmrg if (uni->type->is_sampler()) { 194001e04c3fSmrg /* Mark this bindless sampler as not bound to a texture unit because 194101e04c3fSmrg * it refers to a texture handle. 194201e04c3fSmrg */ 194301e04c3fSmrg for (int i = 0; i < MESA_SHADER_STAGES; i++) { 194401e04c3fSmrg struct gl_linked_shader *const sh = shProg->_LinkedShaders[i]; 1945af69d88dSmrg 194601e04c3fSmrg /* If the shader stage doesn't use the sampler uniform, skip this. */ 194701e04c3fSmrg if (!uni->opaque[i].active) 194801e04c3fSmrg continue; 1949af69d88dSmrg 195001e04c3fSmrg for (int j = 0; j < count; j++) { 195101e04c3fSmrg unsigned unit = uni->opaque[i].index + offset + j; 195201e04c3fSmrg struct gl_bindless_sampler *sampler = 195301e04c3fSmrg &sh->Program->sh.BindlessSamplers[unit]; 1954af69d88dSmrg 195501e04c3fSmrg sampler->bound = false; 195601e04c3fSmrg } 1957af69d88dSmrg 195801e04c3fSmrg update_bound_bindless_sampler_flag(sh->Program); 195901e04c3fSmrg } 196001e04c3fSmrg } 1961af69d88dSmrg 196201e04c3fSmrg if (uni->type->is_image()) { 196301e04c3fSmrg /* Mark this bindless image as not bound to an image unit because it 196401e04c3fSmrg * refers to a texture handle. 196501e04c3fSmrg */ 196601e04c3fSmrg for (int i = 0; i < MESA_SHADER_STAGES; i++) { 196701e04c3fSmrg struct gl_linked_shader *sh = shProg->_LinkedShaders[i]; 196801e04c3fSmrg 196901e04c3fSmrg /* If the shader stage doesn't use the sampler uniform, skip this. */ 197001e04c3fSmrg if (!uni->opaque[i].active) 197101e04c3fSmrg continue; 197201e04c3fSmrg 197301e04c3fSmrg for (int j = 0; j < count; j++) { 197401e04c3fSmrg unsigned unit = uni->opaque[i].index + offset + j; 197501e04c3fSmrg struct gl_bindless_image *image = 197601e04c3fSmrg &sh->Program->sh.BindlessImages[unit]; 197701e04c3fSmrg 197801e04c3fSmrg image->bound = false; 197901e04c3fSmrg } 198001e04c3fSmrg 198101e04c3fSmrg update_bound_bindless_image_flag(sh->Program); 1982af69d88dSmrg } 1983af69d88dSmrg } 198401e04c3fSmrg} 1985af69d88dSmrg 198601e04c3fSmrgextern "C" bool 198701e04c3fSmrg_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg, 198801e04c3fSmrg char *errMsg, size_t errMsgLength) 198901e04c3fSmrg{ 199001e04c3fSmrg /* Shader does not have samplers. */ 199101e04c3fSmrg if (shProg->data->NumUniformStorage == 0) 199201e04c3fSmrg return true; 199301e04c3fSmrg 199401e04c3fSmrg if (!shProg->SamplersValidated) { 19957ec681f3Smrg snprintf(errMsg, errMsgLength, 199601e04c3fSmrg "active samplers with a different type " 199701e04c3fSmrg "refer to the same texture image unit"); 199801e04c3fSmrg return false; 199901e04c3fSmrg } 2000af69d88dSmrg return true; 2001af69d88dSmrg} 2002af69d88dSmrg 2003af69d88dSmrgextern "C" bool 2004af69d88dSmrg_mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline) 2005af69d88dSmrg{ 2006af69d88dSmrg /* Section 2.11.11 (Shader Execution), subheading "Validation," of the 2007af69d88dSmrg * OpenGL 4.1 spec says: 2008af69d88dSmrg * 2009af69d88dSmrg * "[INVALID_OPERATION] is generated by any command that transfers 2010af69d88dSmrg * vertices to the GL if: 2011af69d88dSmrg * 2012af69d88dSmrg * ... 2013af69d88dSmrg * 2014af69d88dSmrg * - Any two active samplers in the current program object are of 2015af69d88dSmrg * different types, but refer to the same texture image unit. 2016af69d88dSmrg * 2017af69d88dSmrg * - The number of active samplers in the program exceeds the 2018af69d88dSmrg * maximum number of texture image units allowed." 2019af69d88dSmrg */ 202001e04c3fSmrg 202101e04c3fSmrg GLbitfield mask; 202201e04c3fSmrg GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; 2023af69d88dSmrg unsigned active_samplers = 0; 202401e04c3fSmrg const struct gl_program **prog = 202501e04c3fSmrg (const struct gl_program **) pipeline->CurrentProgram; 202601e04c3fSmrg 2027af69d88dSmrg 202801e04c3fSmrg memset(TexturesUsed, 0, sizeof(TexturesUsed)); 2029af69d88dSmrg 2030af69d88dSmrg for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) { 203101e04c3fSmrg if (!prog[idx]) 2032af69d88dSmrg continue; 2033af69d88dSmrg 203401e04c3fSmrg mask = prog[idx]->SamplersUsed; 203501e04c3fSmrg while (mask) { 203601e04c3fSmrg const int s = u_bit_scan(&mask); 203701e04c3fSmrg GLuint unit = prog[idx]->SamplerUnits[s]; 203801e04c3fSmrg GLuint tgt = prog[idx]->sh.SamplerTargets[s]; 2039af69d88dSmrg 204001e04c3fSmrg /* FIXME: Samplers are initialized to 0 and Mesa doesn't do a 204101e04c3fSmrg * great job of eliminating unused uniforms currently so for now 204201e04c3fSmrg * don't throw an error if two sampler types both point to 0. 204301e04c3fSmrg */ 204401e04c3fSmrg if (unit == 0) 2045af69d88dSmrg continue; 2046af69d88dSmrg 204701e04c3fSmrg if (TexturesUsed[unit] & ~(1 << tgt)) { 204801e04c3fSmrg pipeline->InfoLog = 204901e04c3fSmrg ralloc_asprintf(pipeline, 205001e04c3fSmrg "Program %d: " 205101e04c3fSmrg "Texture unit %d is accessed with 2 different types", 205201e04c3fSmrg prog[idx]->Id, unit); 205301e04c3fSmrg return false; 2054af69d88dSmrg } 205501e04c3fSmrg 205601e04c3fSmrg TexturesUsed[unit] |= (1 << tgt); 2057af69d88dSmrg } 205801e04c3fSmrg 205901e04c3fSmrg active_samplers += prog[idx]->info.num_textures; 2060af69d88dSmrg } 2061af69d88dSmrg 2062af69d88dSmrg if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) { 2063af69d88dSmrg pipeline->InfoLog = 2064af69d88dSmrg ralloc_asprintf(pipeline, 2065af69d88dSmrg "the number of active samplers %d exceed the " 2066af69d88dSmrg "maximum %d", 2067af69d88dSmrg active_samplers, MAX_COMBINED_TEXTURE_IMAGE_UNITS); 2068af69d88dSmrg return false; 2069af69d88dSmrg } 2070af69d88dSmrg 2071af69d88dSmrg return true; 2072af69d88dSmrg} 2073