1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Mesa 3-D graphics library 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. 5bf215546Sopenharmony_ci * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. 6bf215546Sopenharmony_ci * Copyright © 2010, 2011 Intel Corporation 7bf215546Sopenharmony_ci * 8bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 9bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 10bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 11bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 13bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included 16bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include <stdlib.h> 28bf215546Sopenharmony_ci#include <inttypes.h> /* for PRIx64 macro */ 29bf215546Sopenharmony_ci#include <math.h> 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "main/context.h" 32bf215546Sopenharmony_ci#include "main/draw_validate.h" 33bf215546Sopenharmony_ci#include "main/shaderapi.h" 34bf215546Sopenharmony_ci#include "main/shaderobj.h" 35bf215546Sopenharmony_ci#include "main/uniforms.h" 36bf215546Sopenharmony_ci#include "compiler/glsl/ir.h" 37bf215546Sopenharmony_ci#include "compiler/glsl/ir_uniform.h" 38bf215546Sopenharmony_ci#include "compiler/glsl/glsl_parser_extras.h" 39bf215546Sopenharmony_ci#include "compiler/glsl/program.h" 40bf215546Sopenharmony_ci#include "util/bitscan.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci#include "state_tracker/st_context.h" 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci/* This is one of the few glGet that can be called from the app thread safely. 45bf215546Sopenharmony_ci * Only these conditions must be met: 46bf215546Sopenharmony_ci * - There are no unfinished glLinkProgram and glDeleteProgram calls 47bf215546Sopenharmony_ci * for the program object. This assures that the program object is immutable. 48bf215546Sopenharmony_ci * - glthread=true for GL errors to be passed to the driver thread safely 49bf215546Sopenharmony_ci * 50bf215546Sopenharmony_ci * Program objects can be looked up from any thread because they are part 51bf215546Sopenharmony_ci * of the multi-context shared state. 52bf215546Sopenharmony_ci */ 53bf215546Sopenharmony_ciextern "C" void 54bf215546Sopenharmony_ci_mesa_GetActiveUniform_impl(GLuint program, GLuint index, 55bf215546Sopenharmony_ci GLsizei maxLength, GLsizei *length, GLint *size, 56bf215546Sopenharmony_ci GLenum *type, GLcharARB *nameOut, bool glthread) 57bf215546Sopenharmony_ci{ 58bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 59bf215546Sopenharmony_ci struct gl_shader_program *shProg; 60bf215546Sopenharmony_ci struct gl_program_resource *res; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci if (maxLength < 0) { 63bf215546Sopenharmony_ci _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, 64bf215546Sopenharmony_ci "glGetActiveUniform(maxLength < 0)"); 65bf215546Sopenharmony_ci return; 66bf215546Sopenharmony_ci } 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci shProg = _mesa_lookup_shader_program_err_glthread(ctx, program, glthread, 69bf215546Sopenharmony_ci "glGetActiveUniform"); 70bf215546Sopenharmony_ci if (!shProg) 71bf215546Sopenharmony_ci return; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg, 74bf215546Sopenharmony_ci GL_UNIFORM, index); 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci if (!res) { 77bf215546Sopenharmony_ci _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, 78bf215546Sopenharmony_ci "glGetActiveUniform(index)"); 79bf215546Sopenharmony_ci return; 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci if (nameOut) 83bf215546Sopenharmony_ci _mesa_get_program_resource_name(shProg, GL_UNIFORM, index, maxLength, 84bf215546Sopenharmony_ci length, nameOut, glthread, 85bf215546Sopenharmony_ci "glGetActiveUniform"); 86bf215546Sopenharmony_ci if (type) 87bf215546Sopenharmony_ci _mesa_program_resource_prop((struct gl_shader_program *) shProg, 88bf215546Sopenharmony_ci res, index, GL_TYPE, (GLint*) type, 89bf215546Sopenharmony_ci glthread, "glGetActiveUniform"); 90bf215546Sopenharmony_ci if (size) 91bf215546Sopenharmony_ci _mesa_program_resource_prop((struct gl_shader_program *) shProg, 92bf215546Sopenharmony_ci res, index, GL_ARRAY_SIZE, (GLint*) size, 93bf215546Sopenharmony_ci glthread, "glGetActiveUniform"); 94bf215546Sopenharmony_ci} 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ciextern "C" void GLAPIENTRY 97bf215546Sopenharmony_ci_mesa_GetActiveUniform(GLuint program, GLuint index, 98bf215546Sopenharmony_ci GLsizei maxLength, GLsizei *length, GLint *size, 99bf215546Sopenharmony_ci GLenum *type, GLcharARB *nameOut) 100bf215546Sopenharmony_ci{ 101bf215546Sopenharmony_ci _mesa_GetActiveUniform_impl(program, index, maxLength, length, size, 102bf215546Sopenharmony_ci type, nameOut, false); 103bf215546Sopenharmony_ci} 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_cistatic GLenum 106bf215546Sopenharmony_ciresource_prop_from_uniform_prop(GLenum uni_prop) 107bf215546Sopenharmony_ci{ 108bf215546Sopenharmony_ci switch (uni_prop) { 109bf215546Sopenharmony_ci case GL_UNIFORM_TYPE: 110bf215546Sopenharmony_ci return GL_TYPE; 111bf215546Sopenharmony_ci case GL_UNIFORM_SIZE: 112bf215546Sopenharmony_ci return GL_ARRAY_SIZE; 113bf215546Sopenharmony_ci case GL_UNIFORM_NAME_LENGTH: 114bf215546Sopenharmony_ci return GL_NAME_LENGTH; 115bf215546Sopenharmony_ci case GL_UNIFORM_BLOCK_INDEX: 116bf215546Sopenharmony_ci return GL_BLOCK_INDEX; 117bf215546Sopenharmony_ci case GL_UNIFORM_OFFSET: 118bf215546Sopenharmony_ci return GL_OFFSET; 119bf215546Sopenharmony_ci case GL_UNIFORM_ARRAY_STRIDE: 120bf215546Sopenharmony_ci return GL_ARRAY_STRIDE; 121bf215546Sopenharmony_ci case GL_UNIFORM_MATRIX_STRIDE: 122bf215546Sopenharmony_ci return GL_MATRIX_STRIDE; 123bf215546Sopenharmony_ci case GL_UNIFORM_IS_ROW_MAJOR: 124bf215546Sopenharmony_ci return GL_IS_ROW_MAJOR; 125bf215546Sopenharmony_ci case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: 126bf215546Sopenharmony_ci return GL_ATOMIC_COUNTER_BUFFER_INDEX; 127bf215546Sopenharmony_ci default: 128bf215546Sopenharmony_ci return 0; 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ciextern "C" void GLAPIENTRY 133bf215546Sopenharmony_ci_mesa_GetActiveUniformsiv(GLuint program, 134bf215546Sopenharmony_ci GLsizei uniformCount, 135bf215546Sopenharmony_ci const GLuint *uniformIndices, 136bf215546Sopenharmony_ci GLenum pname, 137bf215546Sopenharmony_ci GLint *params) 138bf215546Sopenharmony_ci{ 139bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 140bf215546Sopenharmony_ci struct gl_shader_program *shProg; 141bf215546Sopenharmony_ci struct gl_program_resource *res; 142bf215546Sopenharmony_ci GLenum res_prop; 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci if (uniformCount < 0) { 145bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 146bf215546Sopenharmony_ci "glGetActiveUniformsiv(uniformCount < 0)"); 147bf215546Sopenharmony_ci return; 148bf215546Sopenharmony_ci } 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); 151bf215546Sopenharmony_ci if (!shProg) 152bf215546Sopenharmony_ci return; 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci res_prop = resource_prop_from_uniform_prop(pname); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci /* We need to first verify that each entry exists as active uniform. If 157bf215546Sopenharmony_ci * not, generate error and do not cause any other side effects. 158bf215546Sopenharmony_ci * 159bf215546Sopenharmony_ci * In the case of and error condition, Page 16 (section 2.3.1 Errors) 160bf215546Sopenharmony_ci * of the OpenGL 4.5 spec says: 161bf215546Sopenharmony_ci * 162bf215546Sopenharmony_ci * "If the generating command modifies values through a pointer argu- 163bf215546Sopenharmony_ci * ment, no change is made to these values." 164bf215546Sopenharmony_ci */ 165bf215546Sopenharmony_ci for (int i = 0; i < uniformCount; i++) { 166bf215546Sopenharmony_ci if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM, 167bf215546Sopenharmony_ci uniformIndices[i])) { 168bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)"); 169bf215546Sopenharmony_ci return; 170bf215546Sopenharmony_ci } 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci for (int i = 0; i < uniformCount; i++) { 174bf215546Sopenharmony_ci res = _mesa_program_resource_find_index(shProg, GL_UNIFORM, 175bf215546Sopenharmony_ci uniformIndices[i]); 176bf215546Sopenharmony_ci if (!_mesa_program_resource_prop(shProg, res, uniformIndices[i], 177bf215546Sopenharmony_ci res_prop, ¶ms[i], 178bf215546Sopenharmony_ci false, "glGetActiveUniformsiv")) 179bf215546Sopenharmony_ci break; 180bf215546Sopenharmony_ci } 181bf215546Sopenharmony_ci} 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_cistatic struct gl_uniform_storage * 184bf215546Sopenharmony_civalidate_uniform_parameters(GLint location, GLsizei count, 185bf215546Sopenharmony_ci unsigned *array_index, 186bf215546Sopenharmony_ci struct gl_context *ctx, 187bf215546Sopenharmony_ci struct gl_shader_program *shProg, 188bf215546Sopenharmony_ci const char *caller) 189bf215546Sopenharmony_ci{ 190bf215546Sopenharmony_ci if (shProg == NULL) { 191bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); 192bf215546Sopenharmony_ci return NULL; 193bf215546Sopenharmony_ci } 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec: 196bf215546Sopenharmony_ci * 197bf215546Sopenharmony_ci * "If a negative number is provided where an argument of type sizei or 198bf215546Sopenharmony_ci * sizeiptr is specified, the error INVALID_VALUE is generated." 199bf215546Sopenharmony_ci */ 200bf215546Sopenharmony_ci if (count < 0) { 201bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller); 202bf215546Sopenharmony_ci return NULL; 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci /* Check that the given location is in bounds of uniform remap table. 206bf215546Sopenharmony_ci * Unlinked programs will have NumUniformRemapTable == 0, so we can take 207bf215546Sopenharmony_ci * the shProg->data->LinkStatus check out of the main path. 208bf215546Sopenharmony_ci */ 209bf215546Sopenharmony_ci if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) { 210bf215546Sopenharmony_ci if (!shProg->data->LinkStatus) 211bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", 212bf215546Sopenharmony_ci caller); 213bf215546Sopenharmony_ci else 214bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", 215bf215546Sopenharmony_ci caller, location); 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci return NULL; 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci if (location == -1) { 221bf215546Sopenharmony_ci if (!shProg->data->LinkStatus) 222bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", 223bf215546Sopenharmony_ci caller); 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci return NULL; 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 229bf215546Sopenharmony_ci * 230bf215546Sopenharmony_ci * "If any of the following conditions occur, an INVALID_OPERATION 231bf215546Sopenharmony_ci * error is generated by the Uniform* commands, and no uniform values 232bf215546Sopenharmony_ci * are changed: 233bf215546Sopenharmony_ci * 234bf215546Sopenharmony_ci * ... 235bf215546Sopenharmony_ci * 236bf215546Sopenharmony_ci * - if no variable with a location of location exists in the 237bf215546Sopenharmony_ci * program object currently in use and location is not -1, 238bf215546Sopenharmony_ci * - if count is greater than one, and the uniform declared in the 239bf215546Sopenharmony_ci * shader is not an array variable, 240bf215546Sopenharmony_ci */ 241bf215546Sopenharmony_ci if (location < -1 || !shProg->UniformRemapTable[location]) { 242bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", 243bf215546Sopenharmony_ci caller, location); 244bf215546Sopenharmony_ci return NULL; 245bf215546Sopenharmony_ci } 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci /* If the driver storage pointer in remap table is -1, we ignore silently. 248bf215546Sopenharmony_ci * 249bf215546Sopenharmony_ci * GL_ARB_explicit_uniform_location spec says: 250bf215546Sopenharmony_ci * "What happens if Uniform* is called with an explicitly defined 251bf215546Sopenharmony_ci * uniform location, but that uniform is deemed inactive by the 252bf215546Sopenharmony_ci * linker? 253bf215546Sopenharmony_ci * 254bf215546Sopenharmony_ci * RESOLVED: The call is ignored for inactive uniform variables and 255bf215546Sopenharmony_ci * no error is generated." 256bf215546Sopenharmony_ci * 257bf215546Sopenharmony_ci */ 258bf215546Sopenharmony_ci if (shProg->UniformRemapTable[location] == 259bf215546Sopenharmony_ci INACTIVE_UNIFORM_EXPLICIT_LOCATION) 260bf215546Sopenharmony_ci return NULL; 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location]; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci /* Even though no location is assigned to a built-in uniform and this 265bf215546Sopenharmony_ci * function should already have returned NULL, this test makes it explicit 266bf215546Sopenharmony_ci * that we are not allowing to update the value of a built-in. 267bf215546Sopenharmony_ci */ 268bf215546Sopenharmony_ci if (uni->builtin) 269bf215546Sopenharmony_ci return NULL; 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci if (uni->array_elements == 0) { 272bf215546Sopenharmony_ci if (count > 1) { 273bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 274bf215546Sopenharmony_ci "%s(count = %u for non-array \"%s\"@%d)", 275bf215546Sopenharmony_ci caller, count, uni->name.string, location); 276bf215546Sopenharmony_ci return NULL; 277bf215546Sopenharmony_ci } 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci assert((location - uni->remap_location) == 0); 280bf215546Sopenharmony_ci *array_index = 0; 281bf215546Sopenharmony_ci } else { 282bf215546Sopenharmony_ci /* The array index specified by the uniform location is just the uniform 283bf215546Sopenharmony_ci * location minus the base location of of the uniform. 284bf215546Sopenharmony_ci */ 285bf215546Sopenharmony_ci *array_index = location - uni->remap_location; 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci /* If the uniform is an array, check that array_index is in bounds. 288bf215546Sopenharmony_ci * array_index is unsigned so no need to check for less than zero. 289bf215546Sopenharmony_ci */ 290bf215546Sopenharmony_ci if (*array_index >= uni->array_elements) { 291bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", 292bf215546Sopenharmony_ci caller, location); 293bf215546Sopenharmony_ci return NULL; 294bf215546Sopenharmony_ci } 295bf215546Sopenharmony_ci } 296bf215546Sopenharmony_ci return uni; 297bf215546Sopenharmony_ci} 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci/** 300bf215546Sopenharmony_ci * Called via glGetUniform[fiui]v() to get the current value of a uniform. 301bf215546Sopenharmony_ci */ 302bf215546Sopenharmony_ciextern "C" void 303bf215546Sopenharmony_ci_mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, 304bf215546Sopenharmony_ci GLsizei bufSize, enum glsl_base_type returnType, 305bf215546Sopenharmony_ci GLvoid *paramsOut) 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci struct gl_shader_program *shProg = 308bf215546Sopenharmony_ci _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv"); 309bf215546Sopenharmony_ci unsigned offset; 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci struct gl_uniform_storage *const uni = 312bf215546Sopenharmony_ci validate_uniform_parameters(location, 1, &offset, 313bf215546Sopenharmony_ci ctx, shProg, "glGetUniform"); 314bf215546Sopenharmony_ci if (uni == NULL) { 315bf215546Sopenharmony_ci /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1 316bf215546Sopenharmony_ci * spec says: 317bf215546Sopenharmony_ci * 318bf215546Sopenharmony_ci * "The error INVALID_OPERATION is generated if program has not been 319bf215546Sopenharmony_ci * linked successfully, or if location is not a valid location for 320bf215546Sopenharmony_ci * program." 321bf215546Sopenharmony_ci * 322bf215546Sopenharmony_ci * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec 323bf215546Sopenharmony_ci * says: 324bf215546Sopenharmony_ci * 325bf215546Sopenharmony_ci * "If the value of location is -1, the Uniform* commands will 326bf215546Sopenharmony_ci * silently ignore the data passed in, and the current uniform 327bf215546Sopenharmony_ci * values will not be changed." 328bf215546Sopenharmony_ci * 329bf215546Sopenharmony_ci * Allowing -1 for the location parameter of glUniform allows 330bf215546Sopenharmony_ci * applications to avoid error paths in the case that, for example, some 331bf215546Sopenharmony_ci * uniform variable is removed by the compiler / linker after 332bf215546Sopenharmony_ci * optimization. In this case, the new value of the uniform is dropped 333bf215546Sopenharmony_ci * on the floor. For the case of glGetUniform, there is nothing 334bf215546Sopenharmony_ci * sensible to do for a location of -1. 335bf215546Sopenharmony_ci * 336bf215546Sopenharmony_ci * If the location was -1, validate_unfirom_parameters will return NULL 337bf215546Sopenharmony_ci * without raising an error. Raise the error here. 338bf215546Sopenharmony_ci */ 339bf215546Sopenharmony_ci if (location == -1) { 340bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniform(location=%d)", 341bf215546Sopenharmony_ci location); 342bf215546Sopenharmony_ci } 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci return; 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci { 348bf215546Sopenharmony_ci unsigned elements = uni->type->components(); 349bf215546Sopenharmony_ci unsigned components = uni->type->vector_elements; 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci const int rmul = glsl_base_type_is_64bit(returnType) ? 2 : 1; 352bf215546Sopenharmony_ci int dmul = (uni->type->is_64bit()) ? 2 : 1; 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci if ((uni->type->is_sampler() || uni->type->is_image()) && 355bf215546Sopenharmony_ci !uni->is_bindless) { 356bf215546Sopenharmony_ci /* Non-bindless samplers/images are represented using unsigned integer 357bf215546Sopenharmony_ci * 32-bit, while bindless handles are 64-bit. 358bf215546Sopenharmony_ci */ 359bf215546Sopenharmony_ci dmul = 1; 360bf215546Sopenharmony_ci } 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci /* Calculate the source base address *BEFORE* modifying elements to 363bf215546Sopenharmony_ci * account for the size of the user's buffer. 364bf215546Sopenharmony_ci */ 365bf215546Sopenharmony_ci const union gl_constant_value *src; 366bf215546Sopenharmony_ci if (ctx->Const.PackedDriverUniformStorage && 367bf215546Sopenharmony_ci (uni->is_bindless || !uni->type->contains_opaque())) { 368bf215546Sopenharmony_ci unsigned dword_elements = elements; 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci /* 16-bit uniforms are packed. */ 371bf215546Sopenharmony_ci if (glsl_base_type_is_16bit(uni->type->base_type)) { 372bf215546Sopenharmony_ci dword_elements = DIV_ROUND_UP(components, 2) * 373bf215546Sopenharmony_ci uni->type->matrix_columns; 374bf215546Sopenharmony_ci } 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci src = (gl_constant_value *) uni->driver_storage[0].data + 377bf215546Sopenharmony_ci (offset * dword_elements * dmul); 378bf215546Sopenharmony_ci } else { 379bf215546Sopenharmony_ci src = &uni->storage[offset * elements * dmul]; 380bf215546Sopenharmony_ci } 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT || 383bf215546Sopenharmony_ci returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_DOUBLE || 384bf215546Sopenharmony_ci returnType == GLSL_TYPE_UINT64 || returnType == GLSL_TYPE_INT64); 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci /* doubles have a different size than the other 3 types */ 387bf215546Sopenharmony_ci unsigned bytes = sizeof(src[0]) * elements * rmul; 388bf215546Sopenharmony_ci if (bufSize < 0 || bytes > (unsigned) bufSize) { 389bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 390bf215546Sopenharmony_ci "glGetnUniform*vARB(out of bounds: bufSize is %d," 391bf215546Sopenharmony_ci " but %u bytes are required)", bufSize, bytes); 392bf215546Sopenharmony_ci return; 393bf215546Sopenharmony_ci } 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci /* If the return type and the uniform's native type are "compatible," 396bf215546Sopenharmony_ci * just memcpy the data. If the types are not compatible, perform a 397bf215546Sopenharmony_ci * slower convert-and-copy process. 398bf215546Sopenharmony_ci */ 399bf215546Sopenharmony_ci if (returnType == uni->type->base_type || 400bf215546Sopenharmony_ci ((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT) && 401bf215546Sopenharmony_ci (uni->type->is_sampler() || uni->type->is_image())) || 402bf215546Sopenharmony_ci (returnType == GLSL_TYPE_UINT64 && uni->is_bindless)) { 403bf215546Sopenharmony_ci memcpy(paramsOut, src, bytes); 404bf215546Sopenharmony_ci } else { 405bf215546Sopenharmony_ci union gl_constant_value *const dst = 406bf215546Sopenharmony_ci (union gl_constant_value *) paramsOut; 407bf215546Sopenharmony_ci /* This code could be optimized by putting the loop inside the switch 408bf215546Sopenharmony_ci * statements. However, this is not expected to be 409bf215546Sopenharmony_ci * performance-critical code. 410bf215546Sopenharmony_ci */ 411bf215546Sopenharmony_ci for (unsigned i = 0; i < elements; i++) { 412bf215546Sopenharmony_ci int sidx = i * dmul; 413bf215546Sopenharmony_ci int didx = i * rmul; 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci if (glsl_base_type_is_16bit(uni->type->base_type)) { 416bf215546Sopenharmony_ci unsigned column = i / components; 417bf215546Sopenharmony_ci unsigned row = i % components; 418bf215546Sopenharmony_ci sidx = column * align(components, 2) + row; 419bf215546Sopenharmony_ci } 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci switch (returnType) { 422bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: 423bf215546Sopenharmony_ci switch (uni->type->base_type) { 424bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: 425bf215546Sopenharmony_ci dst[didx].f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 426bf215546Sopenharmony_ci break; 427bf215546Sopenharmony_ci case GLSL_TYPE_UINT: 428bf215546Sopenharmony_ci dst[didx].f = (float) src[sidx].u; 429bf215546Sopenharmony_ci break; 430bf215546Sopenharmony_ci case GLSL_TYPE_INT: 431bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 432bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: 433bf215546Sopenharmony_ci dst[didx].f = (float) src[sidx].i; 434bf215546Sopenharmony_ci break; 435bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: 436bf215546Sopenharmony_ci dst[didx].f = src[sidx].i ? 1.0f : 0.0f; 437bf215546Sopenharmony_ci break; 438bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: { 439bf215546Sopenharmony_ci double tmp; 440bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].f, sizeof(tmp)); 441bf215546Sopenharmony_ci dst[didx].f = tmp; 442bf215546Sopenharmony_ci break; 443bf215546Sopenharmony_ci } 444bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: { 445bf215546Sopenharmony_ci uint64_t tmp; 446bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].u, sizeof(tmp)); 447bf215546Sopenharmony_ci dst[didx].f = tmp; 448bf215546Sopenharmony_ci break; 449bf215546Sopenharmony_ci } 450bf215546Sopenharmony_ci case GLSL_TYPE_INT64: { 451bf215546Sopenharmony_ci uint64_t tmp; 452bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].i, sizeof(tmp)); 453bf215546Sopenharmony_ci dst[didx].f = tmp; 454bf215546Sopenharmony_ci break; 455bf215546Sopenharmony_ci } 456bf215546Sopenharmony_ci default: 457bf215546Sopenharmony_ci assert(!"Should not get here."); 458bf215546Sopenharmony_ci break; 459bf215546Sopenharmony_ci } 460bf215546Sopenharmony_ci break; 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: 463bf215546Sopenharmony_ci switch (uni->type->base_type) { 464bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: { 465bf215546Sopenharmony_ci double f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 466bf215546Sopenharmony_ci memcpy(&dst[didx].f, &f, sizeof(f)); 467bf215546Sopenharmony_ci break; 468bf215546Sopenharmony_ci } 469bf215546Sopenharmony_ci case GLSL_TYPE_UINT: { 470bf215546Sopenharmony_ci double tmp = src[sidx].u; 471bf215546Sopenharmony_ci memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 472bf215546Sopenharmony_ci break; 473bf215546Sopenharmony_ci } 474bf215546Sopenharmony_ci case GLSL_TYPE_INT: 475bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 476bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: { 477bf215546Sopenharmony_ci double tmp = src[sidx].i; 478bf215546Sopenharmony_ci memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 479bf215546Sopenharmony_ci break; 480bf215546Sopenharmony_ci } 481bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: { 482bf215546Sopenharmony_ci double tmp = src[sidx].i ? 1.0 : 0.0; 483bf215546Sopenharmony_ci memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 484bf215546Sopenharmony_ci break; 485bf215546Sopenharmony_ci } 486bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: { 487bf215546Sopenharmony_ci double tmp = src[sidx].f; 488bf215546Sopenharmony_ci memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 489bf215546Sopenharmony_ci break; 490bf215546Sopenharmony_ci } 491bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: { 492bf215546Sopenharmony_ci uint64_t tmpu; 493bf215546Sopenharmony_ci double tmp; 494bf215546Sopenharmony_ci memcpy(&tmpu, &src[sidx].u, sizeof(tmpu)); 495bf215546Sopenharmony_ci tmp = tmpu; 496bf215546Sopenharmony_ci memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 497bf215546Sopenharmony_ci break; 498bf215546Sopenharmony_ci } 499bf215546Sopenharmony_ci case GLSL_TYPE_INT64: { 500bf215546Sopenharmony_ci int64_t tmpi; 501bf215546Sopenharmony_ci double tmp; 502bf215546Sopenharmony_ci memcpy(&tmpi, &src[sidx].i, sizeof(tmpi)); 503bf215546Sopenharmony_ci tmp = tmpi; 504bf215546Sopenharmony_ci memcpy(&dst[didx].f, &tmp, sizeof(tmp)); 505bf215546Sopenharmony_ci break; 506bf215546Sopenharmony_ci } 507bf215546Sopenharmony_ci default: 508bf215546Sopenharmony_ci assert(!"Should not get here."); 509bf215546Sopenharmony_ci break; 510bf215546Sopenharmony_ci } 511bf215546Sopenharmony_ci break; 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci case GLSL_TYPE_INT: 514bf215546Sopenharmony_ci switch (uni->type->base_type) { 515bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: 516bf215546Sopenharmony_ci /* While the GL 3.2 core spec doesn't explicitly 517bf215546Sopenharmony_ci * state how conversion of float uniforms to integer 518bf215546Sopenharmony_ci * values works, in section 6.2 "State Tables" on 519bf215546Sopenharmony_ci * page 267 it says: 520bf215546Sopenharmony_ci * 521bf215546Sopenharmony_ci * "Unless otherwise specified, when floating 522bf215546Sopenharmony_ci * point state is returned as integer values or 523bf215546Sopenharmony_ci * integer state is returned as floating-point 524bf215546Sopenharmony_ci * values it is converted in the fashion 525bf215546Sopenharmony_ci * described in section 6.1.2" 526bf215546Sopenharmony_ci * 527bf215546Sopenharmony_ci * That section, on page 248, says: 528bf215546Sopenharmony_ci * 529bf215546Sopenharmony_ci * "If GetIntegerv or GetInteger64v are called, 530bf215546Sopenharmony_ci * a floating-point value is rounded to the 531bf215546Sopenharmony_ci * nearest integer..." 532bf215546Sopenharmony_ci */ 533bf215546Sopenharmony_ci dst[didx].i = (int64_t) roundf(src[sidx].f); 534bf215546Sopenharmony_ci break; 535bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: 536bf215546Sopenharmony_ci dst[didx].i = 537bf215546Sopenharmony_ci (int64_t)roundf(_mesa_half_to_float(((uint16_t*)src)[sidx])); 538bf215546Sopenharmony_ci break; 539bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: 540bf215546Sopenharmony_ci dst[didx].i = src[sidx].i ? 1 : 0; 541bf215546Sopenharmony_ci break; 542bf215546Sopenharmony_ci case GLSL_TYPE_UINT: 543bf215546Sopenharmony_ci dst[didx].i = MIN2(src[sidx].i, INT_MAX); 544bf215546Sopenharmony_ci break; 545bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: { 546bf215546Sopenharmony_ci double tmp; 547bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].f, sizeof(tmp)); 548bf215546Sopenharmony_ci dst[didx].i = (int64_t) round(tmp); 549bf215546Sopenharmony_ci break; 550bf215546Sopenharmony_ci } 551bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: { 552bf215546Sopenharmony_ci uint64_t tmp; 553bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].u, sizeof(tmp)); 554bf215546Sopenharmony_ci dst[didx].i = tmp; 555bf215546Sopenharmony_ci break; 556bf215546Sopenharmony_ci } 557bf215546Sopenharmony_ci case GLSL_TYPE_INT64: { 558bf215546Sopenharmony_ci int64_t tmp; 559bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].i, sizeof(tmp)); 560bf215546Sopenharmony_ci dst[didx].i = tmp; 561bf215546Sopenharmony_ci break; 562bf215546Sopenharmony_ci } 563bf215546Sopenharmony_ci default: 564bf215546Sopenharmony_ci assert(!"Should not get here."); 565bf215546Sopenharmony_ci break; 566bf215546Sopenharmony_ci } 567bf215546Sopenharmony_ci break; 568bf215546Sopenharmony_ci 569bf215546Sopenharmony_ci case GLSL_TYPE_UINT: 570bf215546Sopenharmony_ci switch (uni->type->base_type) { 571bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: 572bf215546Sopenharmony_ci /* The spec isn't terribly clear how to handle negative 573bf215546Sopenharmony_ci * values with an unsigned return type. 574bf215546Sopenharmony_ci * 575bf215546Sopenharmony_ci * GL 4.5 section 2.2.2 ("Data Conversions for State 576bf215546Sopenharmony_ci * Query Commands") says: 577bf215546Sopenharmony_ci * 578bf215546Sopenharmony_ci * "If a value is so large in magnitude that it cannot be 579bf215546Sopenharmony_ci * represented by the returned data type, then the nearest 580bf215546Sopenharmony_ci * value representable using the requested type is 581bf215546Sopenharmony_ci * returned." 582bf215546Sopenharmony_ci */ 583bf215546Sopenharmony_ci dst[didx].u = src[sidx].f < 0.0f ? 584bf215546Sopenharmony_ci 0u : (uint32_t) roundf(src[sidx].f); 585bf215546Sopenharmony_ci break; 586bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: { 587bf215546Sopenharmony_ci float f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 588bf215546Sopenharmony_ci dst[didx].u = f < 0.0f ? 0u : (uint32_t)roundf(f); 589bf215546Sopenharmony_ci break; 590bf215546Sopenharmony_ci } 591bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: 592bf215546Sopenharmony_ci dst[didx].i = src[sidx].i ? 1 : 0; 593bf215546Sopenharmony_ci break; 594bf215546Sopenharmony_ci case GLSL_TYPE_INT: 595bf215546Sopenharmony_ci dst[didx].i = MAX2(src[sidx].i, 0); 596bf215546Sopenharmony_ci break; 597bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: { 598bf215546Sopenharmony_ci double tmp; 599bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].f, sizeof(tmp)); 600bf215546Sopenharmony_ci dst[didx].u = tmp < 0.0 ? 0u : (uint32_t) round(tmp); 601bf215546Sopenharmony_ci break; 602bf215546Sopenharmony_ci } 603bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: { 604bf215546Sopenharmony_ci uint64_t tmp; 605bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].u, sizeof(tmp)); 606bf215546Sopenharmony_ci dst[didx].i = MIN2(tmp, INT_MAX); 607bf215546Sopenharmony_ci break; 608bf215546Sopenharmony_ci } 609bf215546Sopenharmony_ci case GLSL_TYPE_INT64: { 610bf215546Sopenharmony_ci int64_t tmp; 611bf215546Sopenharmony_ci memcpy(&tmp, &src[sidx].i, sizeof(tmp)); 612bf215546Sopenharmony_ci dst[didx].i = MAX2(tmp, 0); 613bf215546Sopenharmony_ci break; 614bf215546Sopenharmony_ci } 615bf215546Sopenharmony_ci default: 616bf215546Sopenharmony_ci unreachable("invalid uniform type"); 617bf215546Sopenharmony_ci } 618bf215546Sopenharmony_ci break; 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci case GLSL_TYPE_INT64: 621bf215546Sopenharmony_ci switch (uni->type->base_type) { 622bf215546Sopenharmony_ci case GLSL_TYPE_UINT: { 623bf215546Sopenharmony_ci uint64_t tmp = src[sidx].u; 624bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 625bf215546Sopenharmony_ci break; 626bf215546Sopenharmony_ci } 627bf215546Sopenharmony_ci case GLSL_TYPE_INT: 628bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 629bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: { 630bf215546Sopenharmony_ci int64_t tmp = src[sidx].i; 631bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 632bf215546Sopenharmony_ci break; 633bf215546Sopenharmony_ci } 634bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: { 635bf215546Sopenharmony_ci int64_t tmp = src[sidx].i ? 1.0f : 0.0f; 636bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 637bf215546Sopenharmony_ci break; 638bf215546Sopenharmony_ci } 639bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: { 640bf215546Sopenharmony_ci uint64_t u64; 641bf215546Sopenharmony_ci memcpy(&u64, &src[sidx].u, sizeof(u64)); 642bf215546Sopenharmony_ci int64_t tmp = MIN2(u64, INT_MAX); 643bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 644bf215546Sopenharmony_ci break; 645bf215546Sopenharmony_ci } 646bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: { 647bf215546Sopenharmony_ci int64_t tmp = (int64_t) roundf(src[sidx].f); 648bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 649bf215546Sopenharmony_ci break; 650bf215546Sopenharmony_ci } 651bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: { 652bf215546Sopenharmony_ci float f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 653bf215546Sopenharmony_ci int64_t tmp = (int64_t) roundf(f); 654bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 655bf215546Sopenharmony_ci break; 656bf215546Sopenharmony_ci } 657bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: { 658bf215546Sopenharmony_ci double d; 659bf215546Sopenharmony_ci memcpy(&d, &src[sidx].f, sizeof(d)); 660bf215546Sopenharmony_ci int64_t tmp = (int64_t) round(d); 661bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 662bf215546Sopenharmony_ci break; 663bf215546Sopenharmony_ci } 664bf215546Sopenharmony_ci default: 665bf215546Sopenharmony_ci assert(!"Should not get here."); 666bf215546Sopenharmony_ci break; 667bf215546Sopenharmony_ci } 668bf215546Sopenharmony_ci break; 669bf215546Sopenharmony_ci 670bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: 671bf215546Sopenharmony_ci switch (uni->type->base_type) { 672bf215546Sopenharmony_ci case GLSL_TYPE_UINT: { 673bf215546Sopenharmony_ci uint64_t tmp = src[sidx].u; 674bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 675bf215546Sopenharmony_ci break; 676bf215546Sopenharmony_ci } 677bf215546Sopenharmony_ci case GLSL_TYPE_INT: 678bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 679bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: { 680bf215546Sopenharmony_ci int64_t tmp = MAX2(src[sidx].i, 0); 681bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 682bf215546Sopenharmony_ci break; 683bf215546Sopenharmony_ci } 684bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: { 685bf215546Sopenharmony_ci int64_t tmp = src[sidx].i ? 1.0f : 0.0f; 686bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 687bf215546Sopenharmony_ci break; 688bf215546Sopenharmony_ci } 689bf215546Sopenharmony_ci case GLSL_TYPE_INT64: { 690bf215546Sopenharmony_ci uint64_t i64; 691bf215546Sopenharmony_ci memcpy(&i64, &src[sidx].i, sizeof(i64)); 692bf215546Sopenharmony_ci uint64_t tmp = MAX2(i64, 0); 693bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 694bf215546Sopenharmony_ci break; 695bf215546Sopenharmony_ci } 696bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: { 697bf215546Sopenharmony_ci uint64_t tmp = src[sidx].f < 0.0f ? 698bf215546Sopenharmony_ci 0ull : (uint64_t) roundf(src[sidx].f); 699bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 700bf215546Sopenharmony_ci break; 701bf215546Sopenharmony_ci } 702bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: { 703bf215546Sopenharmony_ci float f = _mesa_half_to_float(((uint16_t*)src)[sidx]); 704bf215546Sopenharmony_ci uint64_t tmp = f < 0.0f ? 0ull : (uint64_t) roundf(f); 705bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 706bf215546Sopenharmony_ci break; 707bf215546Sopenharmony_ci } 708bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: { 709bf215546Sopenharmony_ci double d; 710bf215546Sopenharmony_ci memcpy(&d, &src[sidx].f, sizeof(d)); 711bf215546Sopenharmony_ci uint64_t tmp = (d < 0.0) ? 0ull : (uint64_t) round(d); 712bf215546Sopenharmony_ci memcpy(&dst[didx].u, &tmp, sizeof(tmp)); 713bf215546Sopenharmony_ci break; 714bf215546Sopenharmony_ci } 715bf215546Sopenharmony_ci default: 716bf215546Sopenharmony_ci assert(!"Should not get here."); 717bf215546Sopenharmony_ci break; 718bf215546Sopenharmony_ci } 719bf215546Sopenharmony_ci break; 720bf215546Sopenharmony_ci 721bf215546Sopenharmony_ci default: 722bf215546Sopenharmony_ci assert(!"Should not get here."); 723bf215546Sopenharmony_ci break; 724bf215546Sopenharmony_ci } 725bf215546Sopenharmony_ci } 726bf215546Sopenharmony_ci } 727bf215546Sopenharmony_ci } 728bf215546Sopenharmony_ci} 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_cistatic void 731bf215546Sopenharmony_cilog_uniform(const void *values, enum glsl_base_type basicType, 732bf215546Sopenharmony_ci unsigned rows, unsigned cols, unsigned count, 733bf215546Sopenharmony_ci bool transpose, 734bf215546Sopenharmony_ci const struct gl_shader_program *shProg, 735bf215546Sopenharmony_ci GLint location, 736bf215546Sopenharmony_ci const struct gl_uniform_storage *uni) 737bf215546Sopenharmony_ci{ 738bf215546Sopenharmony_ci 739bf215546Sopenharmony_ci const union gl_constant_value *v = (const union gl_constant_value *) values; 740bf215546Sopenharmony_ci const unsigned elems = rows * cols * count; 741bf215546Sopenharmony_ci const char *const extra = (cols == 1) ? "uniform" : "uniform matrix"; 742bf215546Sopenharmony_ci 743bf215546Sopenharmony_ci printf("Mesa: set program %u %s \"%s\" (loc %d, type \"%s\", " 744bf215546Sopenharmony_ci "transpose = %s) to: ", 745bf215546Sopenharmony_ci shProg->Name, extra, uni->name.string, location, uni->type->name, 746bf215546Sopenharmony_ci transpose ? "true" : "false"); 747bf215546Sopenharmony_ci for (unsigned i = 0; i < elems; i++) { 748bf215546Sopenharmony_ci if (i != 0 && ((i % rows) == 0)) 749bf215546Sopenharmony_ci printf(", "); 750bf215546Sopenharmony_ci 751bf215546Sopenharmony_ci switch (basicType) { 752bf215546Sopenharmony_ci case GLSL_TYPE_UINT: 753bf215546Sopenharmony_ci printf("%u ", v[i].u); 754bf215546Sopenharmony_ci break; 755bf215546Sopenharmony_ci case GLSL_TYPE_INT: 756bf215546Sopenharmony_ci printf("%d ", v[i].i); 757bf215546Sopenharmony_ci break; 758bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: { 759bf215546Sopenharmony_ci uint64_t tmp; 760bf215546Sopenharmony_ci memcpy(&tmp, &v[i * 2].u, sizeof(tmp)); 761bf215546Sopenharmony_ci printf("%" PRIu64 " ", tmp); 762bf215546Sopenharmony_ci break; 763bf215546Sopenharmony_ci } 764bf215546Sopenharmony_ci case GLSL_TYPE_INT64: { 765bf215546Sopenharmony_ci int64_t tmp; 766bf215546Sopenharmony_ci memcpy(&tmp, &v[i * 2].u, sizeof(tmp)); 767bf215546Sopenharmony_ci printf("%" PRId64 " ", tmp); 768bf215546Sopenharmony_ci break; 769bf215546Sopenharmony_ci } 770bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: 771bf215546Sopenharmony_ci printf("%g ", v[i].f); 772bf215546Sopenharmony_ci break; 773bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: { 774bf215546Sopenharmony_ci double tmp; 775bf215546Sopenharmony_ci memcpy(&tmp, &v[i * 2].f, sizeof(tmp)); 776bf215546Sopenharmony_ci printf("%g ", tmp); 777bf215546Sopenharmony_ci break; 778bf215546Sopenharmony_ci } 779bf215546Sopenharmony_ci default: 780bf215546Sopenharmony_ci assert(!"Should not get here."); 781bf215546Sopenharmony_ci break; 782bf215546Sopenharmony_ci } 783bf215546Sopenharmony_ci } 784bf215546Sopenharmony_ci printf("\n"); 785bf215546Sopenharmony_ci fflush(stdout); 786bf215546Sopenharmony_ci} 787bf215546Sopenharmony_ci 788bf215546Sopenharmony_ci#if 0 789bf215546Sopenharmony_cistatic void 790bf215546Sopenharmony_cilog_program_parameters(const struct gl_shader_program *shProg) 791bf215546Sopenharmony_ci{ 792bf215546Sopenharmony_ci for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 793bf215546Sopenharmony_ci if (shProg->_LinkedShaders[i] == NULL) 794bf215546Sopenharmony_ci continue; 795bf215546Sopenharmony_ci 796bf215546Sopenharmony_ci const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program; 797bf215546Sopenharmony_ci 798bf215546Sopenharmony_ci printf("Program %d %s shader parameters:\n", 799bf215546Sopenharmony_ci shProg->Name, _mesa_shader_stage_to_string(i)); 800bf215546Sopenharmony_ci for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) { 801bf215546Sopenharmony_ci unsigned pvo = prog->Parameters->ParameterValueOffset[j]; 802bf215546Sopenharmony_ci printf("%s: %u %p %f %f %f %f\n", 803bf215546Sopenharmony_ci prog->Parameters->Parameters[j].Name, 804bf215546Sopenharmony_ci pvo, 805bf215546Sopenharmony_ci prog->Parameters->ParameterValues + pvo, 806bf215546Sopenharmony_ci prog->Parameters->ParameterValues[pvo].f, 807bf215546Sopenharmony_ci prog->Parameters->ParameterValues[pvo + 1].f, 808bf215546Sopenharmony_ci prog->Parameters->ParameterValues[pvo + 2].f, 809bf215546Sopenharmony_ci prog->Parameters->ParameterValues[pvo + 3].f); 810bf215546Sopenharmony_ci } 811bf215546Sopenharmony_ci } 812bf215546Sopenharmony_ci fflush(stdout); 813bf215546Sopenharmony_ci} 814bf215546Sopenharmony_ci#endif 815bf215546Sopenharmony_ci 816bf215546Sopenharmony_ci/** 817bf215546Sopenharmony_ci * Propagate some values from uniform backing storage to driver storage 818bf215546Sopenharmony_ci * 819bf215546Sopenharmony_ci * Values propagated from uniform backing storage to driver storage 820bf215546Sopenharmony_ci * have all format / type conversions previously requested by the 821bf215546Sopenharmony_ci * driver applied. This function is most often called by the 822bf215546Sopenharmony_ci * implementations of \c glUniform1f, etc. and \c glUniformMatrix2f, 823bf215546Sopenharmony_ci * etc. 824bf215546Sopenharmony_ci * 825bf215546Sopenharmony_ci * \param uni Uniform whose data is to be propagated to driver storage 826bf215546Sopenharmony_ci * \param array_index If \c uni is an array, this is the element of 827bf215546Sopenharmony_ci * the array to be propagated. 828bf215546Sopenharmony_ci * \param count Number of array elements to propagate. 829bf215546Sopenharmony_ci */ 830bf215546Sopenharmony_ciextern "C" void 831bf215546Sopenharmony_ci_mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, 832bf215546Sopenharmony_ci unsigned array_index, 833bf215546Sopenharmony_ci unsigned count) 834bf215546Sopenharmony_ci{ 835bf215546Sopenharmony_ci unsigned i; 836bf215546Sopenharmony_ci 837bf215546Sopenharmony_ci const unsigned components = uni->type->vector_elements; 838bf215546Sopenharmony_ci const unsigned vectors = uni->type->matrix_columns; 839bf215546Sopenharmony_ci const int dmul = uni->type->is_64bit() ? 2 : 1; 840bf215546Sopenharmony_ci 841bf215546Sopenharmony_ci /* Store the data in the driver's requested type in the driver's storage 842bf215546Sopenharmony_ci * areas. 843bf215546Sopenharmony_ci */ 844bf215546Sopenharmony_ci unsigned src_vector_byte_stride = components * 4 * dmul; 845bf215546Sopenharmony_ci 846bf215546Sopenharmony_ci for (i = 0; i < uni->num_driver_storage; i++) { 847bf215546Sopenharmony_ci struct gl_uniform_driver_storage *const store = &uni->driver_storage[i]; 848bf215546Sopenharmony_ci uint8_t *dst = (uint8_t *) store->data; 849bf215546Sopenharmony_ci const unsigned extra_stride = 850bf215546Sopenharmony_ci store->element_stride - (vectors * store->vector_stride); 851bf215546Sopenharmony_ci const uint8_t *src = 852bf215546Sopenharmony_ci (uint8_t *) (&uni->storage[array_index * (dmul * components * vectors)].i); 853bf215546Sopenharmony_ci 854bf215546Sopenharmony_ci#if 0 855bf215546Sopenharmony_ci printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u " 856bf215546Sopenharmony_ci "extra_stride=%u\n", 857bf215546Sopenharmony_ci __func__, dst, array_index, components, 858bf215546Sopenharmony_ci vectors, count, store->vector_stride, extra_stride); 859bf215546Sopenharmony_ci#endif 860bf215546Sopenharmony_ci 861bf215546Sopenharmony_ci dst += array_index * store->element_stride; 862bf215546Sopenharmony_ci 863bf215546Sopenharmony_ci switch (store->format) { 864bf215546Sopenharmony_ci case uniform_native: { 865bf215546Sopenharmony_ci unsigned j; 866bf215546Sopenharmony_ci unsigned v; 867bf215546Sopenharmony_ci 868bf215546Sopenharmony_ci if (src_vector_byte_stride == store->vector_stride) { 869bf215546Sopenharmony_ci if (extra_stride) { 870bf215546Sopenharmony_ci for (j = 0; j < count; j++) { 871bf215546Sopenharmony_ci memcpy(dst, src, src_vector_byte_stride * vectors); 872bf215546Sopenharmony_ci src += src_vector_byte_stride * vectors; 873bf215546Sopenharmony_ci dst += store->vector_stride * vectors; 874bf215546Sopenharmony_ci 875bf215546Sopenharmony_ci dst += extra_stride; 876bf215546Sopenharmony_ci } 877bf215546Sopenharmony_ci } else { 878bf215546Sopenharmony_ci /* Unigine Heaven benchmark gets here */ 879bf215546Sopenharmony_ci memcpy(dst, src, src_vector_byte_stride * vectors * count); 880bf215546Sopenharmony_ci src += src_vector_byte_stride * vectors * count; 881bf215546Sopenharmony_ci dst += store->vector_stride * vectors * count; 882bf215546Sopenharmony_ci } 883bf215546Sopenharmony_ci } else { 884bf215546Sopenharmony_ci for (j = 0; j < count; j++) { 885bf215546Sopenharmony_ci for (v = 0; v < vectors; v++) { 886bf215546Sopenharmony_ci memcpy(dst, src, src_vector_byte_stride); 887bf215546Sopenharmony_ci src += src_vector_byte_stride; 888bf215546Sopenharmony_ci dst += store->vector_stride; 889bf215546Sopenharmony_ci } 890bf215546Sopenharmony_ci 891bf215546Sopenharmony_ci dst += extra_stride; 892bf215546Sopenharmony_ci } 893bf215546Sopenharmony_ci } 894bf215546Sopenharmony_ci break; 895bf215546Sopenharmony_ci } 896bf215546Sopenharmony_ci 897bf215546Sopenharmony_ci case uniform_int_float: { 898bf215546Sopenharmony_ci const int *isrc = (const int *) src; 899bf215546Sopenharmony_ci unsigned j; 900bf215546Sopenharmony_ci unsigned v; 901bf215546Sopenharmony_ci unsigned c; 902bf215546Sopenharmony_ci 903bf215546Sopenharmony_ci for (j = 0; j < count; j++) { 904bf215546Sopenharmony_ci for (v = 0; v < vectors; v++) { 905bf215546Sopenharmony_ci for (c = 0; c < components; c++) { 906bf215546Sopenharmony_ci ((float *) dst)[c] = (float) *isrc; 907bf215546Sopenharmony_ci isrc++; 908bf215546Sopenharmony_ci } 909bf215546Sopenharmony_ci 910bf215546Sopenharmony_ci dst += store->vector_stride; 911bf215546Sopenharmony_ci } 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci dst += extra_stride; 914bf215546Sopenharmony_ci } 915bf215546Sopenharmony_ci break; 916bf215546Sopenharmony_ci } 917bf215546Sopenharmony_ci 918bf215546Sopenharmony_ci default: 919bf215546Sopenharmony_ci assert(!"Should not get here."); 920bf215546Sopenharmony_ci break; 921bf215546Sopenharmony_ci } 922bf215546Sopenharmony_ci } 923bf215546Sopenharmony_ci} 924bf215546Sopenharmony_ci 925bf215546Sopenharmony_ci 926bf215546Sopenharmony_cistatic void 927bf215546Sopenharmony_ciassociate_uniform_storage(struct gl_context *ctx, 928bf215546Sopenharmony_ci struct gl_shader_program *shader_program, 929bf215546Sopenharmony_ci struct gl_program *prog) 930bf215546Sopenharmony_ci{ 931bf215546Sopenharmony_ci struct gl_program_parameter_list *params = prog->Parameters; 932bf215546Sopenharmony_ci gl_shader_stage shader_type = prog->info.stage; 933bf215546Sopenharmony_ci 934bf215546Sopenharmony_ci _mesa_disallow_parameter_storage_realloc(params); 935bf215546Sopenharmony_ci 936bf215546Sopenharmony_ci /* After adding each uniform to the parameter list, connect the storage for 937bf215546Sopenharmony_ci * the parameter with the tracking structure used by the API for the 938bf215546Sopenharmony_ci * uniform. 939bf215546Sopenharmony_ci */ 940bf215546Sopenharmony_ci unsigned last_location = unsigned(~0); 941bf215546Sopenharmony_ci for (unsigned i = 0; i < params->NumParameters; i++) { 942bf215546Sopenharmony_ci if (params->Parameters[i].Type != PROGRAM_UNIFORM) 943bf215546Sopenharmony_ci continue; 944bf215546Sopenharmony_ci 945bf215546Sopenharmony_ci unsigned location = params->Parameters[i].UniformStorageIndex; 946bf215546Sopenharmony_ci 947bf215546Sopenharmony_ci struct gl_uniform_storage *storage = 948bf215546Sopenharmony_ci &shader_program->data->UniformStorage[location]; 949bf215546Sopenharmony_ci 950bf215546Sopenharmony_ci /* Do not associate any uniform storage to built-in uniforms */ 951bf215546Sopenharmony_ci if (storage->builtin) 952bf215546Sopenharmony_ci continue; 953bf215546Sopenharmony_ci 954bf215546Sopenharmony_ci if (location != last_location) { 955bf215546Sopenharmony_ci enum gl_uniform_driver_format format = uniform_native; 956bf215546Sopenharmony_ci unsigned columns = 0; 957bf215546Sopenharmony_ci 958bf215546Sopenharmony_ci int dmul; 959bf215546Sopenharmony_ci if (ctx->Const.PackedDriverUniformStorage && !prog->info.use_legacy_math_rules) { 960bf215546Sopenharmony_ci dmul = storage->type->vector_elements * sizeof(float); 961bf215546Sopenharmony_ci } else { 962bf215546Sopenharmony_ci dmul = 4 * sizeof(float); 963bf215546Sopenharmony_ci } 964bf215546Sopenharmony_ci 965bf215546Sopenharmony_ci switch (storage->type->base_type) { 966bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: 967bf215546Sopenharmony_ci if (storage->type->vector_elements > 2) 968bf215546Sopenharmony_ci dmul *= 2; 969bf215546Sopenharmony_ci FALLTHROUGH; 970bf215546Sopenharmony_ci case GLSL_TYPE_UINT: 971bf215546Sopenharmony_ci case GLSL_TYPE_UINT16: 972bf215546Sopenharmony_ci case GLSL_TYPE_UINT8: 973bf215546Sopenharmony_ci assert(ctx->Const.NativeIntegers); 974bf215546Sopenharmony_ci format = uniform_native; 975bf215546Sopenharmony_ci columns = 1; 976bf215546Sopenharmony_ci break; 977bf215546Sopenharmony_ci case GLSL_TYPE_INT64: 978bf215546Sopenharmony_ci if (storage->type->vector_elements > 2) 979bf215546Sopenharmony_ci dmul *= 2; 980bf215546Sopenharmony_ci FALLTHROUGH; 981bf215546Sopenharmony_ci case GLSL_TYPE_INT: 982bf215546Sopenharmony_ci case GLSL_TYPE_INT16: 983bf215546Sopenharmony_ci case GLSL_TYPE_INT8: 984bf215546Sopenharmony_ci format = 985bf215546Sopenharmony_ci (ctx->Const.NativeIntegers) ? uniform_native : uniform_int_float; 986bf215546Sopenharmony_ci columns = 1; 987bf215546Sopenharmony_ci break; 988bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: 989bf215546Sopenharmony_ci if (storage->type->vector_elements > 2) 990bf215546Sopenharmony_ci dmul *= 2; 991bf215546Sopenharmony_ci FALLTHROUGH; 992bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: 993bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: 994bf215546Sopenharmony_ci format = uniform_native; 995bf215546Sopenharmony_ci columns = storage->type->matrix_columns; 996bf215546Sopenharmony_ci break; 997bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: 998bf215546Sopenharmony_ci format = uniform_native; 999bf215546Sopenharmony_ci columns = 1; 1000bf215546Sopenharmony_ci break; 1001bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 1002bf215546Sopenharmony_ci case GLSL_TYPE_TEXTURE: 1003bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: 1004bf215546Sopenharmony_ci case GLSL_TYPE_SUBROUTINE: 1005bf215546Sopenharmony_ci format = uniform_native; 1006bf215546Sopenharmony_ci columns = 1; 1007bf215546Sopenharmony_ci break; 1008bf215546Sopenharmony_ci case GLSL_TYPE_ATOMIC_UINT: 1009bf215546Sopenharmony_ci case GLSL_TYPE_ARRAY: 1010bf215546Sopenharmony_ci case GLSL_TYPE_VOID: 1011bf215546Sopenharmony_ci case GLSL_TYPE_STRUCT: 1012bf215546Sopenharmony_ci case GLSL_TYPE_ERROR: 1013bf215546Sopenharmony_ci case GLSL_TYPE_INTERFACE: 1014bf215546Sopenharmony_ci case GLSL_TYPE_FUNCTION: 1015bf215546Sopenharmony_ci assert(!"Should not get here."); 1016bf215546Sopenharmony_ci break; 1017bf215546Sopenharmony_ci } 1018bf215546Sopenharmony_ci 1019bf215546Sopenharmony_ci unsigned pvo = params->Parameters[i].ValueOffset; 1020bf215546Sopenharmony_ci _mesa_uniform_attach_driver_storage(storage, dmul * columns, dmul, 1021bf215546Sopenharmony_ci format, 1022bf215546Sopenharmony_ci ¶ms->ParameterValues[pvo]); 1023bf215546Sopenharmony_ci 1024bf215546Sopenharmony_ci /* When a bindless sampler/image is bound to a texture/image unit, we 1025bf215546Sopenharmony_ci * have to overwrite the constant value by the resident handle 1026bf215546Sopenharmony_ci * directly in the constant buffer before the next draw. One solution 1027bf215546Sopenharmony_ci * is to keep track a pointer to the base of the data. 1028bf215546Sopenharmony_ci */ 1029bf215546Sopenharmony_ci if (storage->is_bindless && (prog->sh.NumBindlessSamplers || 1030bf215546Sopenharmony_ci prog->sh.NumBindlessImages)) { 1031bf215546Sopenharmony_ci unsigned array_elements = MAX2(1, storage->array_elements); 1032bf215546Sopenharmony_ci 1033bf215546Sopenharmony_ci for (unsigned j = 0; j < array_elements; ++j) { 1034bf215546Sopenharmony_ci unsigned unit = storage->opaque[shader_type].index + j; 1035bf215546Sopenharmony_ci 1036bf215546Sopenharmony_ci if (storage->type->without_array()->is_sampler()) { 1037bf215546Sopenharmony_ci assert(unit >= 0 && unit < prog->sh.NumBindlessSamplers); 1038bf215546Sopenharmony_ci prog->sh.BindlessSamplers[unit].data = 1039bf215546Sopenharmony_ci ¶ms->ParameterValues[pvo] + 4 * j; 1040bf215546Sopenharmony_ci } else if (storage->type->without_array()->is_image()) { 1041bf215546Sopenharmony_ci assert(unit >= 0 && unit < prog->sh.NumBindlessImages); 1042bf215546Sopenharmony_ci prog->sh.BindlessImages[unit].data = 1043bf215546Sopenharmony_ci ¶ms->ParameterValues[pvo] + 4 * j; 1044bf215546Sopenharmony_ci } 1045bf215546Sopenharmony_ci } 1046bf215546Sopenharmony_ci } 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ci /* After attaching the driver's storage to the uniform, propagate any 1049bf215546Sopenharmony_ci * data from the linker's backing store. This will cause values from 1050bf215546Sopenharmony_ci * initializers in the source code to be copied over. 1051bf215546Sopenharmony_ci */ 1052bf215546Sopenharmony_ci unsigned array_elements = MAX2(1, storage->array_elements); 1053bf215546Sopenharmony_ci if (ctx->Const.PackedDriverUniformStorage && !prog->info.use_legacy_math_rules && 1054bf215546Sopenharmony_ci (storage->is_bindless || !storage->type->contains_opaque())) { 1055bf215546Sopenharmony_ci const int dmul = storage->type->is_64bit() ? 2 : 1; 1056bf215546Sopenharmony_ci const unsigned components = 1057bf215546Sopenharmony_ci storage->type->vector_elements * 1058bf215546Sopenharmony_ci storage->type->matrix_columns; 1059bf215546Sopenharmony_ci 1060bf215546Sopenharmony_ci for (unsigned s = 0; s < storage->num_driver_storage; s++) { 1061bf215546Sopenharmony_ci gl_constant_value *uni_storage = (gl_constant_value *) 1062bf215546Sopenharmony_ci storage->driver_storage[s].data; 1063bf215546Sopenharmony_ci memcpy(uni_storage, storage->storage, 1064bf215546Sopenharmony_ci sizeof(storage->storage[0]) * components * 1065bf215546Sopenharmony_ci array_elements * dmul); 1066bf215546Sopenharmony_ci } 1067bf215546Sopenharmony_ci } else { 1068bf215546Sopenharmony_ci _mesa_propagate_uniforms_to_driver_storage(storage, 0, 1069bf215546Sopenharmony_ci array_elements); 1070bf215546Sopenharmony_ci } 1071bf215546Sopenharmony_ci 1072bf215546Sopenharmony_ci last_location = location; 1073bf215546Sopenharmony_ci } 1074bf215546Sopenharmony_ci } 1075bf215546Sopenharmony_ci} 1076bf215546Sopenharmony_ci 1077bf215546Sopenharmony_ci 1078bf215546Sopenharmony_civoid 1079bf215546Sopenharmony_ci_mesa_ensure_and_associate_uniform_storage(struct gl_context *ctx, 1080bf215546Sopenharmony_ci struct gl_shader_program *shader_program, 1081bf215546Sopenharmony_ci struct gl_program *prog, unsigned required_space) 1082bf215546Sopenharmony_ci{ 1083bf215546Sopenharmony_ci /* Avoid reallocation of the program parameter list, because the uniform 1084bf215546Sopenharmony_ci * storage is only associated with the original parameter list. 1085bf215546Sopenharmony_ci */ 1086bf215546Sopenharmony_ci _mesa_reserve_parameter_storage(prog->Parameters, required_space, 1087bf215546Sopenharmony_ci required_space); 1088bf215546Sopenharmony_ci 1089bf215546Sopenharmony_ci /* This has to be done last. Any operation the can cause 1090bf215546Sopenharmony_ci * prog->ParameterValues to get reallocated (e.g., anything that adds a 1091bf215546Sopenharmony_ci * program constant) has to happen before creating this linkage. 1092bf215546Sopenharmony_ci */ 1093bf215546Sopenharmony_ci associate_uniform_storage(ctx, shader_program, prog); 1094bf215546Sopenharmony_ci} 1095bf215546Sopenharmony_ci 1096bf215546Sopenharmony_ci 1097bf215546Sopenharmony_ci/** 1098bf215546Sopenharmony_ci * Return printable string for a given GLSL_TYPE_x 1099bf215546Sopenharmony_ci */ 1100bf215546Sopenharmony_cistatic const char * 1101bf215546Sopenharmony_ciglsl_type_name(enum glsl_base_type type) 1102bf215546Sopenharmony_ci{ 1103bf215546Sopenharmony_ci switch (type) { 1104bf215546Sopenharmony_ci case GLSL_TYPE_UINT: 1105bf215546Sopenharmony_ci return "uint"; 1106bf215546Sopenharmony_ci case GLSL_TYPE_INT: 1107bf215546Sopenharmony_ci return "int"; 1108bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT: 1109bf215546Sopenharmony_ci return "float"; 1110bf215546Sopenharmony_ci case GLSL_TYPE_DOUBLE: 1111bf215546Sopenharmony_ci return "double"; 1112bf215546Sopenharmony_ci case GLSL_TYPE_UINT64: 1113bf215546Sopenharmony_ci return "uint64"; 1114bf215546Sopenharmony_ci case GLSL_TYPE_INT64: 1115bf215546Sopenharmony_ci return "int64"; 1116bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: 1117bf215546Sopenharmony_ci return "bool"; 1118bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 1119bf215546Sopenharmony_ci return "sampler"; 1120bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: 1121bf215546Sopenharmony_ci return "image"; 1122bf215546Sopenharmony_ci case GLSL_TYPE_ATOMIC_UINT: 1123bf215546Sopenharmony_ci return "atomic_uint"; 1124bf215546Sopenharmony_ci case GLSL_TYPE_STRUCT: 1125bf215546Sopenharmony_ci return "struct"; 1126bf215546Sopenharmony_ci case GLSL_TYPE_INTERFACE: 1127bf215546Sopenharmony_ci return "interface"; 1128bf215546Sopenharmony_ci case GLSL_TYPE_ARRAY: 1129bf215546Sopenharmony_ci return "array"; 1130bf215546Sopenharmony_ci case GLSL_TYPE_VOID: 1131bf215546Sopenharmony_ci return "void"; 1132bf215546Sopenharmony_ci case GLSL_TYPE_ERROR: 1133bf215546Sopenharmony_ci return "error"; 1134bf215546Sopenharmony_ci default: 1135bf215546Sopenharmony_ci return "other"; 1136bf215546Sopenharmony_ci } 1137bf215546Sopenharmony_ci} 1138bf215546Sopenharmony_ci 1139bf215546Sopenharmony_ci 1140bf215546Sopenharmony_cistatic struct gl_uniform_storage * 1141bf215546Sopenharmony_civalidate_uniform(GLint location, GLsizei count, const GLvoid *values, 1142bf215546Sopenharmony_ci unsigned *offset, struct gl_context *ctx, 1143bf215546Sopenharmony_ci struct gl_shader_program *shProg, 1144bf215546Sopenharmony_ci enum glsl_base_type basicType, unsigned src_components) 1145bf215546Sopenharmony_ci{ 1146bf215546Sopenharmony_ci struct gl_uniform_storage *const uni = 1147bf215546Sopenharmony_ci validate_uniform_parameters(location, count, offset, 1148bf215546Sopenharmony_ci ctx, shProg, "glUniform"); 1149bf215546Sopenharmony_ci if (uni == NULL) 1150bf215546Sopenharmony_ci return NULL; 1151bf215546Sopenharmony_ci 1152bf215546Sopenharmony_ci if (uni->type->is_matrix()) { 1153bf215546Sopenharmony_ci /* Can't set matrix uniforms (like mat4) with glUniform */ 1154bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1155bf215546Sopenharmony_ci "glUniform%u(uniform \"%s\"@%d is matrix)", 1156bf215546Sopenharmony_ci src_components, uni->name.string, location); 1157bf215546Sopenharmony_ci return NULL; 1158bf215546Sopenharmony_ci } 1159bf215546Sopenharmony_ci 1160bf215546Sopenharmony_ci /* Verify that the types are compatible. */ 1161bf215546Sopenharmony_ci const unsigned components = uni->type->vector_elements; 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_ci if (components != src_components) { 1164bf215546Sopenharmony_ci /* glUniformN() must match float/vecN type */ 1165bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1166bf215546Sopenharmony_ci "glUniform%u(\"%s\"@%u has %u components, not %u)", 1167bf215546Sopenharmony_ci src_components, uni->name.string, location, 1168bf215546Sopenharmony_ci components, src_components); 1169bf215546Sopenharmony_ci return NULL; 1170bf215546Sopenharmony_ci } 1171bf215546Sopenharmony_ci 1172bf215546Sopenharmony_ci bool match; 1173bf215546Sopenharmony_ci switch (uni->type->base_type) { 1174bf215546Sopenharmony_ci case GLSL_TYPE_BOOL: 1175bf215546Sopenharmony_ci match = (basicType != GLSL_TYPE_DOUBLE); 1176bf215546Sopenharmony_ci break; 1177bf215546Sopenharmony_ci case GLSL_TYPE_SAMPLER: 1178bf215546Sopenharmony_ci match = (basicType == GLSL_TYPE_INT); 1179bf215546Sopenharmony_ci break; 1180bf215546Sopenharmony_ci case GLSL_TYPE_IMAGE: 1181bf215546Sopenharmony_ci match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx)); 1182bf215546Sopenharmony_ci break; 1183bf215546Sopenharmony_ci case GLSL_TYPE_FLOAT16: 1184bf215546Sopenharmony_ci match = basicType == GLSL_TYPE_FLOAT; 1185bf215546Sopenharmony_ci break; 1186bf215546Sopenharmony_ci default: 1187bf215546Sopenharmony_ci match = (basicType == uni->type->base_type); 1188bf215546Sopenharmony_ci break; 1189bf215546Sopenharmony_ci } 1190bf215546Sopenharmony_ci 1191bf215546Sopenharmony_ci if (!match) { 1192bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1193bf215546Sopenharmony_ci "glUniform%u(\"%s\"@%d is %s, not %s)", 1194bf215546Sopenharmony_ci src_components, uni->name.string, location, 1195bf215546Sopenharmony_ci glsl_type_name(uni->type->base_type), 1196bf215546Sopenharmony_ci glsl_type_name(basicType)); 1197bf215546Sopenharmony_ci return NULL; 1198bf215546Sopenharmony_ci } 1199bf215546Sopenharmony_ci 1200bf215546Sopenharmony_ci if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { 1201bf215546Sopenharmony_ci log_uniform(values, basicType, components, 1, count, 1202bf215546Sopenharmony_ci false, shProg, location, uni); 1203bf215546Sopenharmony_ci } 1204bf215546Sopenharmony_ci 1205bf215546Sopenharmony_ci /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: 1206bf215546Sopenharmony_ci * 1207bf215546Sopenharmony_ci * "Setting a sampler's value to i selects texture image unit number 1208bf215546Sopenharmony_ci * i. The values of i range from zero to the implementation- dependent 1209bf215546Sopenharmony_ci * maximum supported number of texture image units." 1210bf215546Sopenharmony_ci * 1211bf215546Sopenharmony_ci * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of 1212bf215546Sopenharmony_ci * the PDF) says: 1213bf215546Sopenharmony_ci * 1214bf215546Sopenharmony_ci * "Error Description Offending command 1215bf215546Sopenharmony_ci * ignored? 1216bf215546Sopenharmony_ci * ... 1217bf215546Sopenharmony_ci * INVALID_VALUE Numeric argument out of range Yes" 1218bf215546Sopenharmony_ci * 1219bf215546Sopenharmony_ci * Based on that, when an invalid sampler is specified, we generate a 1220bf215546Sopenharmony_ci * GL_INVALID_VALUE error and ignore the command. 1221bf215546Sopenharmony_ci */ 1222bf215546Sopenharmony_ci if (uni->type->is_sampler()) { 1223bf215546Sopenharmony_ci for (int i = 0; i < count; i++) { 1224bf215546Sopenharmony_ci const unsigned texUnit = ((unsigned *) values)[i]; 1225bf215546Sopenharmony_ci 1226bf215546Sopenharmony_ci /* check that the sampler (tex unit index) is legal */ 1227bf215546Sopenharmony_ci if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { 1228bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1229bf215546Sopenharmony_ci "glUniform1i(invalid sampler/tex unit index for " 1230bf215546Sopenharmony_ci "uniform %d)", location); 1231bf215546Sopenharmony_ci return NULL; 1232bf215546Sopenharmony_ci } 1233bf215546Sopenharmony_ci } 1234bf215546Sopenharmony_ci /* We need to reset the validate flag on changes to samplers in case 1235bf215546Sopenharmony_ci * two different sampler types are set to the same texture unit. 1236bf215546Sopenharmony_ci */ 1237bf215546Sopenharmony_ci ctx->_Shader->Validated = ctx->_Shader->UserValidated = GL_FALSE; 1238bf215546Sopenharmony_ci } 1239bf215546Sopenharmony_ci 1240bf215546Sopenharmony_ci if (uni->type->is_image()) { 1241bf215546Sopenharmony_ci for (int i = 0; i < count; i++) { 1242bf215546Sopenharmony_ci const int unit = ((GLint *) values)[i]; 1243bf215546Sopenharmony_ci 1244bf215546Sopenharmony_ci /* check that the image unit is legal */ 1245bf215546Sopenharmony_ci if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) { 1246bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1247bf215546Sopenharmony_ci "glUniform1i(invalid image unit index for uniform %d)", 1248bf215546Sopenharmony_ci location); 1249bf215546Sopenharmony_ci return NULL; 1250bf215546Sopenharmony_ci } 1251bf215546Sopenharmony_ci } 1252bf215546Sopenharmony_ci } 1253bf215546Sopenharmony_ci 1254bf215546Sopenharmony_ci return uni; 1255bf215546Sopenharmony_ci} 1256bf215546Sopenharmony_ci 1257bf215546Sopenharmony_civoid 1258bf215546Sopenharmony_ci_mesa_flush_vertices_for_uniforms(struct gl_context *ctx, 1259bf215546Sopenharmony_ci const struct gl_uniform_storage *uni) 1260bf215546Sopenharmony_ci{ 1261bf215546Sopenharmony_ci /* Opaque uniforms have no storage unless they are bindless */ 1262bf215546Sopenharmony_ci if (!uni->is_bindless && uni->type->contains_opaque()) { 1263bf215546Sopenharmony_ci /* Samplers flush on demand and ignore redundant updates. */ 1264bf215546Sopenharmony_ci if (!uni->type->is_sampler()) 1265bf215546Sopenharmony_ci FLUSH_VERTICES(ctx, 0, 0); 1266bf215546Sopenharmony_ci return; 1267bf215546Sopenharmony_ci } 1268bf215546Sopenharmony_ci 1269bf215546Sopenharmony_ci uint64_t new_driver_state = 0; 1270bf215546Sopenharmony_ci unsigned mask = uni->active_shader_mask; 1271bf215546Sopenharmony_ci 1272bf215546Sopenharmony_ci while (mask) { 1273bf215546Sopenharmony_ci unsigned index = u_bit_scan(&mask); 1274bf215546Sopenharmony_ci 1275bf215546Sopenharmony_ci assert(index < MESA_SHADER_STAGES); 1276bf215546Sopenharmony_ci new_driver_state |= ctx->DriverFlags.NewShaderConstants[index]; 1277bf215546Sopenharmony_ci } 1278bf215546Sopenharmony_ci 1279bf215546Sopenharmony_ci FLUSH_VERTICES(ctx, new_driver_state ? 0 : _NEW_PROGRAM_CONSTANTS, 0); 1280bf215546Sopenharmony_ci ctx->NewDriverState |= new_driver_state; 1281bf215546Sopenharmony_ci} 1282bf215546Sopenharmony_ci 1283bf215546Sopenharmony_cistatic bool 1284bf215546Sopenharmony_cicopy_uniforms_to_storage(gl_constant_value *storage, 1285bf215546Sopenharmony_ci struct gl_uniform_storage *uni, 1286bf215546Sopenharmony_ci struct gl_context *ctx, GLsizei count, 1287bf215546Sopenharmony_ci const GLvoid *values, const int size_mul, 1288bf215546Sopenharmony_ci const unsigned offset, const unsigned components, 1289bf215546Sopenharmony_ci enum glsl_base_type basicType, bool flush) 1290bf215546Sopenharmony_ci{ 1291bf215546Sopenharmony_ci const gl_constant_value *src = (const gl_constant_value*)values; 1292bf215546Sopenharmony_ci bool copy_as_uint64 = uni->is_bindless && 1293bf215546Sopenharmony_ci (uni->type->is_sampler() || uni->type->is_image()); 1294bf215546Sopenharmony_ci bool copy_to_float16 = uni->type->base_type == GLSL_TYPE_FLOAT16; 1295bf215546Sopenharmony_ci 1296bf215546Sopenharmony_ci if (!uni->type->is_boolean() && !copy_as_uint64 && !copy_to_float16) { 1297bf215546Sopenharmony_ci unsigned size = sizeof(storage[0]) * components * count * size_mul; 1298bf215546Sopenharmony_ci 1299bf215546Sopenharmony_ci if (!memcmp(storage, values, size)) 1300bf215546Sopenharmony_ci return false; 1301bf215546Sopenharmony_ci 1302bf215546Sopenharmony_ci if (flush) 1303bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1304bf215546Sopenharmony_ci 1305bf215546Sopenharmony_ci memcpy(storage, values, size); 1306bf215546Sopenharmony_ci return true; 1307bf215546Sopenharmony_ci } else if (copy_to_float16) { 1308bf215546Sopenharmony_ci assert(ctx->Const.PackedDriverUniformStorage); 1309bf215546Sopenharmony_ci const unsigned dst_components = align(components, 2); 1310bf215546Sopenharmony_ci uint16_t *dst = (uint16_t*)storage; 1311bf215546Sopenharmony_ci 1312bf215546Sopenharmony_ci int i = 0; 1313bf215546Sopenharmony_ci unsigned c = 0; 1314bf215546Sopenharmony_ci 1315bf215546Sopenharmony_ci if (flush) { 1316bf215546Sopenharmony_ci /* Find the first element that's different. */ 1317bf215546Sopenharmony_ci for (; i < count; i++) { 1318bf215546Sopenharmony_ci for (; c < components; c++) { 1319bf215546Sopenharmony_ci if (dst[c] != _mesa_float_to_half(src[c].f)) { 1320bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1321bf215546Sopenharmony_ci flush = false; 1322bf215546Sopenharmony_ci goto break_loops; 1323bf215546Sopenharmony_ci } 1324bf215546Sopenharmony_ci } 1325bf215546Sopenharmony_ci c = 0; 1326bf215546Sopenharmony_ci dst += dst_components; 1327bf215546Sopenharmony_ci src += components; 1328bf215546Sopenharmony_ci } 1329bf215546Sopenharmony_ci break_loops: 1330bf215546Sopenharmony_ci if (flush) 1331bf215546Sopenharmony_ci return false; /* No change. */ 1332bf215546Sopenharmony_ci } 1333bf215546Sopenharmony_ci 1334bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1335bf215546Sopenharmony_ci * different and that we have flushed. 1336bf215546Sopenharmony_ci */ 1337bf215546Sopenharmony_ci for (; i < count; i++) { 1338bf215546Sopenharmony_ci for (; c < components; c++) 1339bf215546Sopenharmony_ci dst[c] = _mesa_float_to_half(src[c].f); 1340bf215546Sopenharmony_ci 1341bf215546Sopenharmony_ci c = 0; 1342bf215546Sopenharmony_ci dst += dst_components; 1343bf215546Sopenharmony_ci src += components; 1344bf215546Sopenharmony_ci } 1345bf215546Sopenharmony_ci 1346bf215546Sopenharmony_ci return true; 1347bf215546Sopenharmony_ci } else if (copy_as_uint64) { 1348bf215546Sopenharmony_ci const unsigned elems = components * count; 1349bf215546Sopenharmony_ci uint64_t *dst = (uint64_t*)storage; 1350bf215546Sopenharmony_ci unsigned i = 0; 1351bf215546Sopenharmony_ci 1352bf215546Sopenharmony_ci if (flush) { 1353bf215546Sopenharmony_ci /* Find the first element that's different. */ 1354bf215546Sopenharmony_ci for (; i < elems; i++) { 1355bf215546Sopenharmony_ci if (dst[i] != src[i].u) { 1356bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1357bf215546Sopenharmony_ci flush = false; 1358bf215546Sopenharmony_ci break; 1359bf215546Sopenharmony_ci } 1360bf215546Sopenharmony_ci } 1361bf215546Sopenharmony_ci if (flush) 1362bf215546Sopenharmony_ci return false; /* No change. */ 1363bf215546Sopenharmony_ci } 1364bf215546Sopenharmony_ci 1365bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1366bf215546Sopenharmony_ci * different and that we have flushed. 1367bf215546Sopenharmony_ci */ 1368bf215546Sopenharmony_ci for (; i < elems; i++) 1369bf215546Sopenharmony_ci dst[i] = src[i].u; 1370bf215546Sopenharmony_ci 1371bf215546Sopenharmony_ci return true; 1372bf215546Sopenharmony_ci } else { 1373bf215546Sopenharmony_ci const unsigned elems = components * count; 1374bf215546Sopenharmony_ci gl_constant_value *dst = storage; 1375bf215546Sopenharmony_ci 1376bf215546Sopenharmony_ci if (basicType == GLSL_TYPE_FLOAT) { 1377bf215546Sopenharmony_ci unsigned i = 0; 1378bf215546Sopenharmony_ci 1379bf215546Sopenharmony_ci if (flush) { 1380bf215546Sopenharmony_ci /* Find the first element that's different. */ 1381bf215546Sopenharmony_ci for (; i < elems; i++) { 1382bf215546Sopenharmony_ci if (dst[i].u != 1383bf215546Sopenharmony_ci (src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0)) { 1384bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1385bf215546Sopenharmony_ci flush = false; 1386bf215546Sopenharmony_ci break; 1387bf215546Sopenharmony_ci } 1388bf215546Sopenharmony_ci } 1389bf215546Sopenharmony_ci if (flush) 1390bf215546Sopenharmony_ci return false; /* No change. */ 1391bf215546Sopenharmony_ci } 1392bf215546Sopenharmony_ci 1393bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1394bf215546Sopenharmony_ci * different and that we have flushed. 1395bf215546Sopenharmony_ci */ 1396bf215546Sopenharmony_ci for (; i < elems; i++) 1397bf215546Sopenharmony_ci dst[i].u = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0; 1398bf215546Sopenharmony_ci 1399bf215546Sopenharmony_ci return true; 1400bf215546Sopenharmony_ci } else { 1401bf215546Sopenharmony_ci unsigned i = 0; 1402bf215546Sopenharmony_ci 1403bf215546Sopenharmony_ci if (flush) { 1404bf215546Sopenharmony_ci /* Find the first element that's different. */ 1405bf215546Sopenharmony_ci for (; i < elems; i++) { 1406bf215546Sopenharmony_ci if (dst[i].u != 1407bf215546Sopenharmony_ci (src[i].u ? ctx->Const.UniformBooleanTrue : 0)) { 1408bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1409bf215546Sopenharmony_ci flush = false; 1410bf215546Sopenharmony_ci break; 1411bf215546Sopenharmony_ci } 1412bf215546Sopenharmony_ci } 1413bf215546Sopenharmony_ci if (flush) 1414bf215546Sopenharmony_ci return false; /* No change. */ 1415bf215546Sopenharmony_ci } 1416bf215546Sopenharmony_ci 1417bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1418bf215546Sopenharmony_ci * different and that we have flushed. 1419bf215546Sopenharmony_ci */ 1420bf215546Sopenharmony_ci for (; i < elems; i++) 1421bf215546Sopenharmony_ci dst[i].u = src[i].u ? ctx->Const.UniformBooleanTrue : 0; 1422bf215546Sopenharmony_ci 1423bf215546Sopenharmony_ci return true; 1424bf215546Sopenharmony_ci } 1425bf215546Sopenharmony_ci } 1426bf215546Sopenharmony_ci} 1427bf215546Sopenharmony_ci 1428bf215546Sopenharmony_ci 1429bf215546Sopenharmony_ci/** 1430bf215546Sopenharmony_ci * Called via glUniform*() functions. 1431bf215546Sopenharmony_ci */ 1432bf215546Sopenharmony_ciextern "C" void 1433bf215546Sopenharmony_ci_mesa_uniform(GLint location, GLsizei count, const GLvoid *values, 1434bf215546Sopenharmony_ci struct gl_context *ctx, struct gl_shader_program *shProg, 1435bf215546Sopenharmony_ci enum glsl_base_type basicType, unsigned src_components) 1436bf215546Sopenharmony_ci{ 1437bf215546Sopenharmony_ci unsigned offset; 1438bf215546Sopenharmony_ci int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1; 1439bf215546Sopenharmony_ci 1440bf215546Sopenharmony_ci struct gl_uniform_storage *uni; 1441bf215546Sopenharmony_ci if (_mesa_is_no_error_enabled(ctx)) { 1442bf215546Sopenharmony_ci /* From Seciton 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec: 1443bf215546Sopenharmony_ci * 1444bf215546Sopenharmony_ci * "If the value of location is -1, the Uniform* commands will 1445bf215546Sopenharmony_ci * silently ignore the data passed in, and the current uniform values 1446bf215546Sopenharmony_ci * will not be changed. 1447bf215546Sopenharmony_ci */ 1448bf215546Sopenharmony_ci if (location == -1) 1449bf215546Sopenharmony_ci return; 1450bf215546Sopenharmony_ci 1451bf215546Sopenharmony_ci if (location >= (int)shProg->NumUniformRemapTable) 1452bf215546Sopenharmony_ci return; 1453bf215546Sopenharmony_ci 1454bf215546Sopenharmony_ci uni = shProg->UniformRemapTable[location]; 1455bf215546Sopenharmony_ci if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) 1456bf215546Sopenharmony_ci return; 1457bf215546Sopenharmony_ci 1458bf215546Sopenharmony_ci /* The array index specified by the uniform location is just the 1459bf215546Sopenharmony_ci * uniform location minus the base location of of the uniform. 1460bf215546Sopenharmony_ci */ 1461bf215546Sopenharmony_ci assert(uni->array_elements > 0 || location == (int)uni->remap_location); 1462bf215546Sopenharmony_ci offset = location - uni->remap_location; 1463bf215546Sopenharmony_ci } else { 1464bf215546Sopenharmony_ci uni = validate_uniform(location, count, values, &offset, ctx, shProg, 1465bf215546Sopenharmony_ci basicType, src_components); 1466bf215546Sopenharmony_ci if (!uni) 1467bf215546Sopenharmony_ci return; 1468bf215546Sopenharmony_ci } 1469bf215546Sopenharmony_ci 1470bf215546Sopenharmony_ci const unsigned components = uni->type->vector_elements; 1471bf215546Sopenharmony_ci 1472bf215546Sopenharmony_ci /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 1473bf215546Sopenharmony_ci * 1474bf215546Sopenharmony_ci * "When loading N elements starting at an arbitrary position k in a 1475bf215546Sopenharmony_ci * uniform declared as an array, elements k through k + N - 1 in the 1476bf215546Sopenharmony_ci * array will be replaced with the new values. Values for any array 1477bf215546Sopenharmony_ci * element that exceeds the highest array element index used, as 1478bf215546Sopenharmony_ci * reported by GetActiveUniform, will be ignored by the GL." 1479bf215546Sopenharmony_ci * 1480bf215546Sopenharmony_ci * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 1481bf215546Sopenharmony_ci * will have already generated an error. 1482bf215546Sopenharmony_ci */ 1483bf215546Sopenharmony_ci if (uni->array_elements != 0) { 1484bf215546Sopenharmony_ci count = MIN2(count, (int) (uni->array_elements - offset)); 1485bf215546Sopenharmony_ci } 1486bf215546Sopenharmony_ci 1487bf215546Sopenharmony_ci /* Store the data in the "actual type" backing storage for the uniform. 1488bf215546Sopenharmony_ci */ 1489bf215546Sopenharmony_ci bool ctx_flushed = false; 1490bf215546Sopenharmony_ci gl_constant_value *storage; 1491bf215546Sopenharmony_ci if (ctx->Const.PackedDriverUniformStorage && 1492bf215546Sopenharmony_ci (uni->is_bindless || !uni->type->contains_opaque())) { 1493bf215546Sopenharmony_ci for (unsigned s = 0; s < uni->num_driver_storage; s++) { 1494bf215546Sopenharmony_ci unsigned dword_components = components; 1495bf215546Sopenharmony_ci 1496bf215546Sopenharmony_ci /* 16-bit uniforms are packed. */ 1497bf215546Sopenharmony_ci if (glsl_base_type_is_16bit(uni->type->base_type)) 1498bf215546Sopenharmony_ci dword_components = DIV_ROUND_UP(dword_components, 2); 1499bf215546Sopenharmony_ci 1500bf215546Sopenharmony_ci storage = (gl_constant_value *) 1501bf215546Sopenharmony_ci uni->driver_storage[s].data + (size_mul * offset * dword_components); 1502bf215546Sopenharmony_ci 1503bf215546Sopenharmony_ci if (copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul, 1504bf215546Sopenharmony_ci offset, components, basicType, !ctx_flushed)) 1505bf215546Sopenharmony_ci ctx_flushed = true; 1506bf215546Sopenharmony_ci } 1507bf215546Sopenharmony_ci } else { 1508bf215546Sopenharmony_ci storage = &uni->storage[size_mul * components * offset]; 1509bf215546Sopenharmony_ci if (copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul, 1510bf215546Sopenharmony_ci offset, components, basicType, !ctx_flushed)) { 1511bf215546Sopenharmony_ci _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); 1512bf215546Sopenharmony_ci ctx_flushed = true; 1513bf215546Sopenharmony_ci } 1514bf215546Sopenharmony_ci } 1515bf215546Sopenharmony_ci /* Return early if possible. Bindless samplers need to be processed 1516bf215546Sopenharmony_ci * because of the !sampler->bound codepath below. 1517bf215546Sopenharmony_ci */ 1518bf215546Sopenharmony_ci if (!ctx_flushed && !(uni->type->is_sampler() && uni->is_bindless)) 1519bf215546Sopenharmony_ci return; /* no change in uniform values */ 1520bf215546Sopenharmony_ci 1521bf215546Sopenharmony_ci /* If the uniform is a sampler, do the extra magic necessary to propagate 1522bf215546Sopenharmony_ci * the changes through. 1523bf215546Sopenharmony_ci */ 1524bf215546Sopenharmony_ci if (uni->type->is_sampler()) { 1525bf215546Sopenharmony_ci /* Note that samplers are the only uniforms that don't call 1526bf215546Sopenharmony_ci * FLUSH_VERTICES above. 1527bf215546Sopenharmony_ci */ 1528bf215546Sopenharmony_ci bool flushed = false; 1529bf215546Sopenharmony_ci bool any_changed = false; 1530bf215546Sopenharmony_ci bool samplers_validated = shProg->SamplersValidated; 1531bf215546Sopenharmony_ci 1532bf215546Sopenharmony_ci shProg->SamplersValidated = GL_TRUE; 1533bf215546Sopenharmony_ci 1534bf215546Sopenharmony_ci for (int i = 0; i < MESA_SHADER_STAGES; i++) { 1535bf215546Sopenharmony_ci struct gl_linked_shader *const sh = shProg->_LinkedShaders[i]; 1536bf215546Sopenharmony_ci 1537bf215546Sopenharmony_ci /* If the shader stage doesn't use the sampler uniform, skip this. */ 1538bf215546Sopenharmony_ci if (!uni->opaque[i].active) 1539bf215546Sopenharmony_ci continue; 1540bf215546Sopenharmony_ci 1541bf215546Sopenharmony_ci bool changed = false; 1542bf215546Sopenharmony_ci for (int j = 0; j < count; j++) { 1543bf215546Sopenharmony_ci unsigned unit = uni->opaque[i].index + offset + j; 1544bf215546Sopenharmony_ci unsigned value = ((unsigned *)values)[j]; 1545bf215546Sopenharmony_ci 1546bf215546Sopenharmony_ci if (uni->is_bindless) { 1547bf215546Sopenharmony_ci struct gl_bindless_sampler *sampler = 1548bf215546Sopenharmony_ci &sh->Program->sh.BindlessSamplers[unit]; 1549bf215546Sopenharmony_ci 1550bf215546Sopenharmony_ci /* Mark this bindless sampler as bound to a texture unit. 1551bf215546Sopenharmony_ci */ 1552bf215546Sopenharmony_ci if (sampler->unit != value || !sampler->bound) { 1553bf215546Sopenharmony_ci if (!flushed) { 1554bf215546Sopenharmony_ci FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM, 0); 1555bf215546Sopenharmony_ci flushed = true; 1556bf215546Sopenharmony_ci } 1557bf215546Sopenharmony_ci sampler->unit = value; 1558bf215546Sopenharmony_ci changed = true; 1559bf215546Sopenharmony_ci } 1560bf215546Sopenharmony_ci sampler->bound = true; 1561bf215546Sopenharmony_ci sh->Program->sh.HasBoundBindlessSampler = true; 1562bf215546Sopenharmony_ci } else { 1563bf215546Sopenharmony_ci if (sh->Program->SamplerUnits[unit] != value) { 1564bf215546Sopenharmony_ci if (!flushed) { 1565bf215546Sopenharmony_ci FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM, 0); 1566bf215546Sopenharmony_ci flushed = true; 1567bf215546Sopenharmony_ci } 1568bf215546Sopenharmony_ci sh->Program->SamplerUnits[unit] = value; 1569bf215546Sopenharmony_ci changed = true; 1570bf215546Sopenharmony_ci } 1571bf215546Sopenharmony_ci } 1572bf215546Sopenharmony_ci } 1573bf215546Sopenharmony_ci 1574bf215546Sopenharmony_ci if (changed) { 1575bf215546Sopenharmony_ci struct gl_program *const prog = sh->Program; 1576bf215546Sopenharmony_ci _mesa_update_shader_textures_used(shProg, prog); 1577bf215546Sopenharmony_ci any_changed = true; 1578bf215546Sopenharmony_ci } 1579bf215546Sopenharmony_ci } 1580bf215546Sopenharmony_ci 1581bf215546Sopenharmony_ci if (any_changed) 1582bf215546Sopenharmony_ci _mesa_update_valid_to_render_state(ctx); 1583bf215546Sopenharmony_ci else 1584bf215546Sopenharmony_ci shProg->SamplersValidated = samplers_validated; 1585bf215546Sopenharmony_ci } 1586bf215546Sopenharmony_ci 1587bf215546Sopenharmony_ci /* If the uniform is an image, update the mapping from image 1588bf215546Sopenharmony_ci * uniforms to image units present in the shader data structure. 1589bf215546Sopenharmony_ci */ 1590bf215546Sopenharmony_ci if (uni->type->is_image()) { 1591bf215546Sopenharmony_ci for (int i = 0; i < MESA_SHADER_STAGES; i++) { 1592bf215546Sopenharmony_ci struct gl_linked_shader *sh = shProg->_LinkedShaders[i]; 1593bf215546Sopenharmony_ci 1594bf215546Sopenharmony_ci /* If the shader stage doesn't use the image uniform, skip this. */ 1595bf215546Sopenharmony_ci if (!uni->opaque[i].active) 1596bf215546Sopenharmony_ci continue; 1597bf215546Sopenharmony_ci 1598bf215546Sopenharmony_ci for (int j = 0; j < count; j++) { 1599bf215546Sopenharmony_ci unsigned unit = uni->opaque[i].index + offset + j; 1600bf215546Sopenharmony_ci unsigned value = ((unsigned *)values)[j]; 1601bf215546Sopenharmony_ci 1602bf215546Sopenharmony_ci if (uni->is_bindless) { 1603bf215546Sopenharmony_ci struct gl_bindless_image *image = 1604bf215546Sopenharmony_ci &sh->Program->sh.BindlessImages[unit]; 1605bf215546Sopenharmony_ci 1606bf215546Sopenharmony_ci /* Mark this bindless image as bound to an image unit. 1607bf215546Sopenharmony_ci */ 1608bf215546Sopenharmony_ci image->unit = value; 1609bf215546Sopenharmony_ci image->bound = true; 1610bf215546Sopenharmony_ci sh->Program->sh.HasBoundBindlessImage = true; 1611bf215546Sopenharmony_ci } else { 1612bf215546Sopenharmony_ci sh->Program->sh.ImageUnits[unit] = value; 1613bf215546Sopenharmony_ci } 1614bf215546Sopenharmony_ci } 1615bf215546Sopenharmony_ci } 1616bf215546Sopenharmony_ci 1617bf215546Sopenharmony_ci ctx->NewDriverState |= ST_NEW_IMAGE_UNITS; 1618bf215546Sopenharmony_ci } 1619bf215546Sopenharmony_ci} 1620bf215546Sopenharmony_ci 1621bf215546Sopenharmony_ci 1622bf215546Sopenharmony_cistatic bool 1623bf215546Sopenharmony_cicopy_uniform_matrix_to_storage(struct gl_context *ctx, 1624bf215546Sopenharmony_ci gl_constant_value *storage, 1625bf215546Sopenharmony_ci struct gl_uniform_storage *const uni, 1626bf215546Sopenharmony_ci unsigned count, const void *values, 1627bf215546Sopenharmony_ci const unsigned size_mul, const unsigned offset, 1628bf215546Sopenharmony_ci const unsigned components, 1629bf215546Sopenharmony_ci const unsigned vectors, bool transpose, 1630bf215546Sopenharmony_ci unsigned cols, unsigned rows, 1631bf215546Sopenharmony_ci enum glsl_base_type basicType, bool flush) 1632bf215546Sopenharmony_ci{ 1633bf215546Sopenharmony_ci const unsigned elements = components * vectors; 1634bf215546Sopenharmony_ci const unsigned size = sizeof(storage[0]) * elements * count * size_mul; 1635bf215546Sopenharmony_ci 1636bf215546Sopenharmony_ci if (uni->type->base_type == GLSL_TYPE_FLOAT16) { 1637bf215546Sopenharmony_ci assert(ctx->Const.PackedDriverUniformStorage); 1638bf215546Sopenharmony_ci const unsigned dst_components = align(components, 2); 1639bf215546Sopenharmony_ci const unsigned dst_elements = dst_components * vectors; 1640bf215546Sopenharmony_ci 1641bf215546Sopenharmony_ci if (!transpose) { 1642bf215546Sopenharmony_ci const float *src = (const float *)values; 1643bf215546Sopenharmony_ci uint16_t *dst = (uint16_t*)storage; 1644bf215546Sopenharmony_ci 1645bf215546Sopenharmony_ci unsigned i = 0, r = 0, c = 0; 1646bf215546Sopenharmony_ci 1647bf215546Sopenharmony_ci if (flush) { 1648bf215546Sopenharmony_ci /* Find the first element that's different. */ 1649bf215546Sopenharmony_ci for (; i < count; i++) { 1650bf215546Sopenharmony_ci for (; c < cols; c++) { 1651bf215546Sopenharmony_ci for (; r < rows; r++) { 1652bf215546Sopenharmony_ci if (dst[(c * dst_components) + r] != 1653bf215546Sopenharmony_ci _mesa_float_to_half(src[(c * components) + r])) { 1654bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1655bf215546Sopenharmony_ci flush = false; 1656bf215546Sopenharmony_ci goto break_loops_16bit; 1657bf215546Sopenharmony_ci } 1658bf215546Sopenharmony_ci } 1659bf215546Sopenharmony_ci r = 0; 1660bf215546Sopenharmony_ci } 1661bf215546Sopenharmony_ci c = 0; 1662bf215546Sopenharmony_ci dst += dst_elements; 1663bf215546Sopenharmony_ci src += elements; 1664bf215546Sopenharmony_ci } 1665bf215546Sopenharmony_ci 1666bf215546Sopenharmony_ci break_loops_16bit: 1667bf215546Sopenharmony_ci if (flush) 1668bf215546Sopenharmony_ci return false; /* No change. */ 1669bf215546Sopenharmony_ci } 1670bf215546Sopenharmony_ci 1671bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1672bf215546Sopenharmony_ci * different and that we have flushed. 1673bf215546Sopenharmony_ci */ 1674bf215546Sopenharmony_ci for (; i < count; i++) { 1675bf215546Sopenharmony_ci for (; c < cols; c++) { 1676bf215546Sopenharmony_ci for (; r < rows; r++) { 1677bf215546Sopenharmony_ci dst[(c * dst_components) + r] = 1678bf215546Sopenharmony_ci _mesa_float_to_half(src[(c * components) + r]); 1679bf215546Sopenharmony_ci } 1680bf215546Sopenharmony_ci r = 0; 1681bf215546Sopenharmony_ci } 1682bf215546Sopenharmony_ci c = 0; 1683bf215546Sopenharmony_ci dst += dst_elements; 1684bf215546Sopenharmony_ci src += elements; 1685bf215546Sopenharmony_ci } 1686bf215546Sopenharmony_ci return true; 1687bf215546Sopenharmony_ci } else { 1688bf215546Sopenharmony_ci /* Transpose the matrix. */ 1689bf215546Sopenharmony_ci const float *src = (const float *)values; 1690bf215546Sopenharmony_ci uint16_t *dst = (uint16_t*)storage; 1691bf215546Sopenharmony_ci 1692bf215546Sopenharmony_ci unsigned i = 0, r = 0, c = 0; 1693bf215546Sopenharmony_ci 1694bf215546Sopenharmony_ci if (flush) { 1695bf215546Sopenharmony_ci /* Find the first element that's different. */ 1696bf215546Sopenharmony_ci for (; i < count; i++) { 1697bf215546Sopenharmony_ci for (; r < rows; r++) { 1698bf215546Sopenharmony_ci for (; c < cols; c++) { 1699bf215546Sopenharmony_ci if (dst[(c * dst_components) + r] != 1700bf215546Sopenharmony_ci _mesa_float_to_half(src[c + (r * vectors)])) { 1701bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1702bf215546Sopenharmony_ci flush = false; 1703bf215546Sopenharmony_ci goto break_loops_16bit_transpose; 1704bf215546Sopenharmony_ci } 1705bf215546Sopenharmony_ci } 1706bf215546Sopenharmony_ci c = 0; 1707bf215546Sopenharmony_ci } 1708bf215546Sopenharmony_ci r = 0; 1709bf215546Sopenharmony_ci dst += elements; 1710bf215546Sopenharmony_ci src += elements; 1711bf215546Sopenharmony_ci } 1712bf215546Sopenharmony_ci 1713bf215546Sopenharmony_ci break_loops_16bit_transpose: 1714bf215546Sopenharmony_ci if (flush) 1715bf215546Sopenharmony_ci return false; /* No change. */ 1716bf215546Sopenharmony_ci } 1717bf215546Sopenharmony_ci 1718bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1719bf215546Sopenharmony_ci * different and that we have flushed. 1720bf215546Sopenharmony_ci */ 1721bf215546Sopenharmony_ci for (; i < count; i++) { 1722bf215546Sopenharmony_ci for (; r < rows; r++) { 1723bf215546Sopenharmony_ci for (; c < cols; c++) { 1724bf215546Sopenharmony_ci dst[(c * dst_components) + r] = 1725bf215546Sopenharmony_ci _mesa_float_to_half(src[c + (r * vectors)]); 1726bf215546Sopenharmony_ci } 1727bf215546Sopenharmony_ci c = 0; 1728bf215546Sopenharmony_ci } 1729bf215546Sopenharmony_ci r = 0; 1730bf215546Sopenharmony_ci dst += elements; 1731bf215546Sopenharmony_ci src += elements; 1732bf215546Sopenharmony_ci } 1733bf215546Sopenharmony_ci return true; 1734bf215546Sopenharmony_ci } 1735bf215546Sopenharmony_ci } else if (!transpose) { 1736bf215546Sopenharmony_ci if (!memcmp(storage, values, size)) 1737bf215546Sopenharmony_ci return false; 1738bf215546Sopenharmony_ci 1739bf215546Sopenharmony_ci if (flush) 1740bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1741bf215546Sopenharmony_ci 1742bf215546Sopenharmony_ci memcpy(storage, values, size); 1743bf215546Sopenharmony_ci return true; 1744bf215546Sopenharmony_ci } else if (basicType == GLSL_TYPE_FLOAT) { 1745bf215546Sopenharmony_ci /* Transpose the matrix. */ 1746bf215546Sopenharmony_ci const float *src = (const float *)values; 1747bf215546Sopenharmony_ci float *dst = (float*)storage; 1748bf215546Sopenharmony_ci 1749bf215546Sopenharmony_ci unsigned i = 0, r = 0, c = 0; 1750bf215546Sopenharmony_ci 1751bf215546Sopenharmony_ci if (flush) { 1752bf215546Sopenharmony_ci /* Find the first element that's different. */ 1753bf215546Sopenharmony_ci for (; i < count; i++) { 1754bf215546Sopenharmony_ci for (; r < rows; r++) { 1755bf215546Sopenharmony_ci for (; c < cols; c++) { 1756bf215546Sopenharmony_ci if (dst[(c * components) + r] != src[c + (r * vectors)]) { 1757bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1758bf215546Sopenharmony_ci flush = false; 1759bf215546Sopenharmony_ci goto break_loops; 1760bf215546Sopenharmony_ci } 1761bf215546Sopenharmony_ci } 1762bf215546Sopenharmony_ci c = 0; 1763bf215546Sopenharmony_ci } 1764bf215546Sopenharmony_ci r = 0; 1765bf215546Sopenharmony_ci dst += elements; 1766bf215546Sopenharmony_ci src += elements; 1767bf215546Sopenharmony_ci } 1768bf215546Sopenharmony_ci 1769bf215546Sopenharmony_ci break_loops: 1770bf215546Sopenharmony_ci if (flush) 1771bf215546Sopenharmony_ci return false; /* No change. */ 1772bf215546Sopenharmony_ci } 1773bf215546Sopenharmony_ci 1774bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1775bf215546Sopenharmony_ci * different and that we have flushed. 1776bf215546Sopenharmony_ci */ 1777bf215546Sopenharmony_ci for (; i < count; i++) { 1778bf215546Sopenharmony_ci for (; r < rows; r++) { 1779bf215546Sopenharmony_ci for (; c < cols; c++) 1780bf215546Sopenharmony_ci dst[(c * components) + r] = src[c + (r * vectors)]; 1781bf215546Sopenharmony_ci c = 0; 1782bf215546Sopenharmony_ci } 1783bf215546Sopenharmony_ci r = 0; 1784bf215546Sopenharmony_ci dst += elements; 1785bf215546Sopenharmony_ci src += elements; 1786bf215546Sopenharmony_ci } 1787bf215546Sopenharmony_ci return true; 1788bf215546Sopenharmony_ci } else { 1789bf215546Sopenharmony_ci assert(basicType == GLSL_TYPE_DOUBLE); 1790bf215546Sopenharmony_ci const double *src = (const double *)values; 1791bf215546Sopenharmony_ci double *dst = (double*)storage; 1792bf215546Sopenharmony_ci 1793bf215546Sopenharmony_ci unsigned i = 0, r = 0, c = 0; 1794bf215546Sopenharmony_ci 1795bf215546Sopenharmony_ci if (flush) { 1796bf215546Sopenharmony_ci /* Find the first element that's different. */ 1797bf215546Sopenharmony_ci for (; i < count; i++) { 1798bf215546Sopenharmony_ci for (; r < rows; r++) { 1799bf215546Sopenharmony_ci for (; c < cols; c++) { 1800bf215546Sopenharmony_ci if (dst[(c * components) + r] != src[c + (r * vectors)]) { 1801bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 1802bf215546Sopenharmony_ci flush = false; 1803bf215546Sopenharmony_ci goto break_loops2; 1804bf215546Sopenharmony_ci } 1805bf215546Sopenharmony_ci } 1806bf215546Sopenharmony_ci c = 0; 1807bf215546Sopenharmony_ci } 1808bf215546Sopenharmony_ci r = 0; 1809bf215546Sopenharmony_ci dst += elements; 1810bf215546Sopenharmony_ci src += elements; 1811bf215546Sopenharmony_ci } 1812bf215546Sopenharmony_ci 1813bf215546Sopenharmony_ci break_loops2: 1814bf215546Sopenharmony_ci if (flush) 1815bf215546Sopenharmony_ci return false; /* No change. */ 1816bf215546Sopenharmony_ci } 1817bf215546Sopenharmony_ci 1818bf215546Sopenharmony_ci /* Set the remaining elements. We know that at least 1 element is 1819bf215546Sopenharmony_ci * different and that we have flushed. 1820bf215546Sopenharmony_ci */ 1821bf215546Sopenharmony_ci for (; i < count; i++) { 1822bf215546Sopenharmony_ci for (; r < rows; r++) { 1823bf215546Sopenharmony_ci for (; c < cols; c++) 1824bf215546Sopenharmony_ci dst[(c * components) + r] = src[c + (r * vectors)]; 1825bf215546Sopenharmony_ci c = 0; 1826bf215546Sopenharmony_ci } 1827bf215546Sopenharmony_ci r = 0; 1828bf215546Sopenharmony_ci dst += elements; 1829bf215546Sopenharmony_ci src += elements; 1830bf215546Sopenharmony_ci } 1831bf215546Sopenharmony_ci return true; 1832bf215546Sopenharmony_ci } 1833bf215546Sopenharmony_ci} 1834bf215546Sopenharmony_ci 1835bf215546Sopenharmony_ci 1836bf215546Sopenharmony_ci/** 1837bf215546Sopenharmony_ci * Called by glUniformMatrix*() functions. 1838bf215546Sopenharmony_ci * Note: cols=2, rows=4 ==> array[2] of vec4 1839bf215546Sopenharmony_ci */ 1840bf215546Sopenharmony_ciextern "C" void 1841bf215546Sopenharmony_ci_mesa_uniform_matrix(GLint location, GLsizei count, 1842bf215546Sopenharmony_ci GLboolean transpose, const void *values, 1843bf215546Sopenharmony_ci struct gl_context *ctx, struct gl_shader_program *shProg, 1844bf215546Sopenharmony_ci GLuint cols, GLuint rows, enum glsl_base_type basicType) 1845bf215546Sopenharmony_ci{ 1846bf215546Sopenharmony_ci unsigned offset; 1847bf215546Sopenharmony_ci struct gl_uniform_storage *const uni = 1848bf215546Sopenharmony_ci validate_uniform_parameters(location, count, &offset, 1849bf215546Sopenharmony_ci ctx, shProg, "glUniformMatrix"); 1850bf215546Sopenharmony_ci if (uni == NULL) 1851bf215546Sopenharmony_ci return; 1852bf215546Sopenharmony_ci 1853bf215546Sopenharmony_ci /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE. 1854bf215546Sopenharmony_ci * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml 1855bf215546Sopenharmony_ci */ 1856bf215546Sopenharmony_ci if (transpose) { 1857bf215546Sopenharmony_ci if (ctx->API == API_OPENGLES2 && ctx->Version < 30) { 1858bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 1859bf215546Sopenharmony_ci "glUniformMatrix(matrix transpose is not GL_FALSE)"); 1860bf215546Sopenharmony_ci return; 1861bf215546Sopenharmony_ci } 1862bf215546Sopenharmony_ci } 1863bf215546Sopenharmony_ci 1864bf215546Sopenharmony_ci if (!uni->type->is_matrix()) { 1865bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1866bf215546Sopenharmony_ci "glUniformMatrix(non-matrix uniform)"); 1867bf215546Sopenharmony_ci return; 1868bf215546Sopenharmony_ci } 1869bf215546Sopenharmony_ci 1870bf215546Sopenharmony_ci assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE); 1871bf215546Sopenharmony_ci const unsigned size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1; 1872bf215546Sopenharmony_ci 1873bf215546Sopenharmony_ci assert(!uni->type->is_sampler()); 1874bf215546Sopenharmony_ci const unsigned vectors = uni->type->matrix_columns; 1875bf215546Sopenharmony_ci const unsigned components = uni->type->vector_elements; 1876bf215546Sopenharmony_ci 1877bf215546Sopenharmony_ci /* Verify that the types are compatible. This is greatly simplified for 1878bf215546Sopenharmony_ci * matrices because they can only have a float base type. 1879bf215546Sopenharmony_ci */ 1880bf215546Sopenharmony_ci if (vectors != cols || components != rows) { 1881bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1882bf215546Sopenharmony_ci "glUniformMatrix(matrix size mismatch)"); 1883bf215546Sopenharmony_ci return; 1884bf215546Sopenharmony_ci } 1885bf215546Sopenharmony_ci 1886bf215546Sopenharmony_ci /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec 1887bf215546Sopenharmony_ci * says: 1888bf215546Sopenharmony_ci * 1889bf215546Sopenharmony_ci * "If any of the following conditions occur, an INVALID_OPERATION 1890bf215546Sopenharmony_ci * error is generated by the Uniform* commands, and no uniform values 1891bf215546Sopenharmony_ci * are changed: 1892bf215546Sopenharmony_ci * 1893bf215546Sopenharmony_ci * ... 1894bf215546Sopenharmony_ci * 1895bf215546Sopenharmony_ci * - if the uniform declared in the shader is not of type boolean and 1896bf215546Sopenharmony_ci * the type indicated in the name of the Uniform* command used does 1897bf215546Sopenharmony_ci * not match the type of the uniform" 1898bf215546Sopenharmony_ci * 1899bf215546Sopenharmony_ci * There are no Boolean matrix types, so we do not need to allow 1900bf215546Sopenharmony_ci * GLSL_TYPE_BOOL here (as _mesa_uniform does). 1901bf215546Sopenharmony_ci */ 1902bf215546Sopenharmony_ci if (uni->type->base_type != basicType && 1903bf215546Sopenharmony_ci !(uni->type->base_type == GLSL_TYPE_FLOAT16 && 1904bf215546Sopenharmony_ci basicType == GLSL_TYPE_FLOAT)) { 1905bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 1906bf215546Sopenharmony_ci "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)", 1907bf215546Sopenharmony_ci cols, rows, uni->name.string, location, 1908bf215546Sopenharmony_ci glsl_type_name(uni->type->base_type), 1909bf215546Sopenharmony_ci glsl_type_name(basicType)); 1910bf215546Sopenharmony_ci return; 1911bf215546Sopenharmony_ci } 1912bf215546Sopenharmony_ci 1913bf215546Sopenharmony_ci if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { 1914bf215546Sopenharmony_ci log_uniform(values, uni->type->base_type, components, vectors, count, 1915bf215546Sopenharmony_ci bool(transpose), shProg, location, uni); 1916bf215546Sopenharmony_ci } 1917bf215546Sopenharmony_ci 1918bf215546Sopenharmony_ci /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 1919bf215546Sopenharmony_ci * 1920bf215546Sopenharmony_ci * "When loading N elements starting at an arbitrary position k in a 1921bf215546Sopenharmony_ci * uniform declared as an array, elements k through k + N - 1 in the 1922bf215546Sopenharmony_ci * array will be replaced with the new values. Values for any array 1923bf215546Sopenharmony_ci * element that exceeds the highest array element index used, as 1924bf215546Sopenharmony_ci * reported by GetActiveUniform, will be ignored by the GL." 1925bf215546Sopenharmony_ci * 1926bf215546Sopenharmony_ci * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 1927bf215546Sopenharmony_ci * will have already generated an error. 1928bf215546Sopenharmony_ci */ 1929bf215546Sopenharmony_ci if (uni->array_elements != 0) { 1930bf215546Sopenharmony_ci count = MIN2(count, (int) (uni->array_elements - offset)); 1931bf215546Sopenharmony_ci } 1932bf215546Sopenharmony_ci 1933bf215546Sopenharmony_ci /* Store the data in the "actual type" backing storage for the uniform. 1934bf215546Sopenharmony_ci */ 1935bf215546Sopenharmony_ci gl_constant_value *storage; 1936bf215546Sopenharmony_ci const unsigned elements = components * vectors; 1937bf215546Sopenharmony_ci if (ctx->Const.PackedDriverUniformStorage) { 1938bf215546Sopenharmony_ci bool flushed = false; 1939bf215546Sopenharmony_ci 1940bf215546Sopenharmony_ci for (unsigned s = 0; s < uni->num_driver_storage; s++) { 1941bf215546Sopenharmony_ci unsigned dword_components = components; 1942bf215546Sopenharmony_ci 1943bf215546Sopenharmony_ci /* 16-bit uniforms are packed. */ 1944bf215546Sopenharmony_ci if (glsl_base_type_is_16bit(uni->type->base_type)) 1945bf215546Sopenharmony_ci dword_components = DIV_ROUND_UP(dword_components, 2); 1946bf215546Sopenharmony_ci 1947bf215546Sopenharmony_ci storage = (gl_constant_value *) 1948bf215546Sopenharmony_ci uni->driver_storage[s].data + 1949bf215546Sopenharmony_ci (size_mul * offset * dword_components * vectors); 1950bf215546Sopenharmony_ci 1951bf215546Sopenharmony_ci if (copy_uniform_matrix_to_storage(ctx, storage, uni, count, values, 1952bf215546Sopenharmony_ci size_mul, offset, components, 1953bf215546Sopenharmony_ci vectors, transpose, cols, rows, 1954bf215546Sopenharmony_ci basicType, !flushed)) 1955bf215546Sopenharmony_ci flushed = true; 1956bf215546Sopenharmony_ci } 1957bf215546Sopenharmony_ci } else { 1958bf215546Sopenharmony_ci storage = &uni->storage[size_mul * elements * offset]; 1959bf215546Sopenharmony_ci if (copy_uniform_matrix_to_storage(ctx, storage, uni, count, values, 1960bf215546Sopenharmony_ci size_mul, offset, components, vectors, 1961bf215546Sopenharmony_ci transpose, cols, rows, basicType, 1962bf215546Sopenharmony_ci true)) 1963bf215546Sopenharmony_ci _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); 1964bf215546Sopenharmony_ci } 1965bf215546Sopenharmony_ci} 1966bf215546Sopenharmony_ci 1967bf215546Sopenharmony_cistatic void 1968bf215546Sopenharmony_ciupdate_bound_bindless_sampler_flag(struct gl_program *prog) 1969bf215546Sopenharmony_ci{ 1970bf215546Sopenharmony_ci unsigned i; 1971bf215546Sopenharmony_ci 1972bf215546Sopenharmony_ci if (likely(!prog->sh.HasBoundBindlessSampler)) 1973bf215546Sopenharmony_ci return; 1974bf215546Sopenharmony_ci 1975bf215546Sopenharmony_ci for (i = 0; i < prog->sh.NumBindlessSamplers; i++) { 1976bf215546Sopenharmony_ci struct gl_bindless_sampler *sampler = &prog->sh.BindlessSamplers[i]; 1977bf215546Sopenharmony_ci 1978bf215546Sopenharmony_ci if (sampler->bound) 1979bf215546Sopenharmony_ci return; 1980bf215546Sopenharmony_ci } 1981bf215546Sopenharmony_ci prog->sh.HasBoundBindlessSampler = false; 1982bf215546Sopenharmony_ci} 1983bf215546Sopenharmony_ci 1984bf215546Sopenharmony_cistatic void 1985bf215546Sopenharmony_ciupdate_bound_bindless_image_flag(struct gl_program *prog) 1986bf215546Sopenharmony_ci{ 1987bf215546Sopenharmony_ci unsigned i; 1988bf215546Sopenharmony_ci 1989bf215546Sopenharmony_ci if (likely(!prog->sh.HasBoundBindlessImage)) 1990bf215546Sopenharmony_ci return; 1991bf215546Sopenharmony_ci 1992bf215546Sopenharmony_ci for (i = 0; i < prog->sh.NumBindlessImages; i++) { 1993bf215546Sopenharmony_ci struct gl_bindless_image *image = &prog->sh.BindlessImages[i]; 1994bf215546Sopenharmony_ci 1995bf215546Sopenharmony_ci if (image->bound) 1996bf215546Sopenharmony_ci return; 1997bf215546Sopenharmony_ci } 1998bf215546Sopenharmony_ci prog->sh.HasBoundBindlessImage = false; 1999bf215546Sopenharmony_ci} 2000bf215546Sopenharmony_ci 2001bf215546Sopenharmony_ci/** 2002bf215546Sopenharmony_ci * Called via glUniformHandleui64*ARB() functions. 2003bf215546Sopenharmony_ci */ 2004bf215546Sopenharmony_ciextern "C" void 2005bf215546Sopenharmony_ci_mesa_uniform_handle(GLint location, GLsizei count, const GLvoid *values, 2006bf215546Sopenharmony_ci struct gl_context *ctx, struct gl_shader_program *shProg) 2007bf215546Sopenharmony_ci{ 2008bf215546Sopenharmony_ci unsigned offset; 2009bf215546Sopenharmony_ci struct gl_uniform_storage *uni; 2010bf215546Sopenharmony_ci 2011bf215546Sopenharmony_ci if (_mesa_is_no_error_enabled(ctx)) { 2012bf215546Sopenharmony_ci /* From Section 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec: 2013bf215546Sopenharmony_ci * 2014bf215546Sopenharmony_ci * "If the value of location is -1, the Uniform* commands will 2015bf215546Sopenharmony_ci * silently ignore the data passed in, and the current uniform values 2016bf215546Sopenharmony_ci * will not be changed. 2017bf215546Sopenharmony_ci */ 2018bf215546Sopenharmony_ci if (location == -1) 2019bf215546Sopenharmony_ci return; 2020bf215546Sopenharmony_ci 2021bf215546Sopenharmony_ci uni = shProg->UniformRemapTable[location]; 2022bf215546Sopenharmony_ci if (!uni || uni == INACTIVE_UNIFORM_EXPLICIT_LOCATION) 2023bf215546Sopenharmony_ci return; 2024bf215546Sopenharmony_ci 2025bf215546Sopenharmony_ci /* The array index specified by the uniform location is just the 2026bf215546Sopenharmony_ci * uniform location minus the base location of of the uniform. 2027bf215546Sopenharmony_ci */ 2028bf215546Sopenharmony_ci assert(uni->array_elements > 0 || location == (int)uni->remap_location); 2029bf215546Sopenharmony_ci offset = location - uni->remap_location; 2030bf215546Sopenharmony_ci } else { 2031bf215546Sopenharmony_ci uni = validate_uniform_parameters(location, count, &offset, 2032bf215546Sopenharmony_ci ctx, shProg, "glUniformHandleui64*ARB"); 2033bf215546Sopenharmony_ci if (!uni) 2034bf215546Sopenharmony_ci return; 2035bf215546Sopenharmony_ci 2036bf215546Sopenharmony_ci if (!uni->is_bindless) { 2037bf215546Sopenharmony_ci /* From section "Errors" of the ARB_bindless_texture spec: 2038bf215546Sopenharmony_ci * 2039bf215546Sopenharmony_ci * "The error INVALID_OPERATION is generated by 2040bf215546Sopenharmony_ci * UniformHandleui64{v}ARB if the sampler or image uniform being 2041bf215546Sopenharmony_ci * updated has the "bound_sampler" or "bound_image" layout qualifier." 2042bf215546Sopenharmony_ci * 2043bf215546Sopenharmony_ci * From section 4.4.6 of the ARB_bindless_texture spec: 2044bf215546Sopenharmony_ci * 2045bf215546Sopenharmony_ci * "In the absence of these qualifiers, sampler and image uniforms are 2046bf215546Sopenharmony_ci * considered "bound". Additionally, if GL_ARB_bindless_texture is 2047bf215546Sopenharmony_ci * not enabled, these uniforms are considered "bound"." 2048bf215546Sopenharmony_ci */ 2049bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 2050bf215546Sopenharmony_ci "glUniformHandleui64*ARB(non-bindless sampler/image uniform)"); 2051bf215546Sopenharmony_ci return; 2052bf215546Sopenharmony_ci } 2053bf215546Sopenharmony_ci } 2054bf215546Sopenharmony_ci 2055bf215546Sopenharmony_ci const unsigned components = uni->type->vector_elements; 2056bf215546Sopenharmony_ci const int size_mul = 2; 2057bf215546Sopenharmony_ci 2058bf215546Sopenharmony_ci if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { 2059bf215546Sopenharmony_ci log_uniform(values, GLSL_TYPE_UINT64, components, 1, count, 2060bf215546Sopenharmony_ci false, shProg, location, uni); 2061bf215546Sopenharmony_ci } 2062bf215546Sopenharmony_ci 2063bf215546Sopenharmony_ci /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: 2064bf215546Sopenharmony_ci * 2065bf215546Sopenharmony_ci * "When loading N elements starting at an arbitrary position k in a 2066bf215546Sopenharmony_ci * uniform declared as an array, elements k through k + N - 1 in the 2067bf215546Sopenharmony_ci * array will be replaced with the new values. Values for any array 2068bf215546Sopenharmony_ci * element that exceeds the highest array element index used, as 2069bf215546Sopenharmony_ci * reported by GetActiveUniform, will be ignored by the GL." 2070bf215546Sopenharmony_ci * 2071bf215546Sopenharmony_ci * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 2072bf215546Sopenharmony_ci * will have already generated an error. 2073bf215546Sopenharmony_ci */ 2074bf215546Sopenharmony_ci if (uni->array_elements != 0) { 2075bf215546Sopenharmony_ci count = MIN2(count, (int) (uni->array_elements - offset)); 2076bf215546Sopenharmony_ci } 2077bf215546Sopenharmony_ci 2078bf215546Sopenharmony_ci 2079bf215546Sopenharmony_ci /* Store the data in the "actual type" backing storage for the uniform. 2080bf215546Sopenharmony_ci */ 2081bf215546Sopenharmony_ci if (ctx->Const.PackedDriverUniformStorage) { 2082bf215546Sopenharmony_ci bool flushed = false; 2083bf215546Sopenharmony_ci 2084bf215546Sopenharmony_ci for (unsigned s = 0; s < uni->num_driver_storage; s++) { 2085bf215546Sopenharmony_ci void *storage = (gl_constant_value *) 2086bf215546Sopenharmony_ci uni->driver_storage[s].data + (size_mul * offset * components); 2087bf215546Sopenharmony_ci unsigned size = sizeof(uni->storage[0]) * components * count * size_mul; 2088bf215546Sopenharmony_ci 2089bf215546Sopenharmony_ci if (!memcmp(storage, values, size)) 2090bf215546Sopenharmony_ci continue; 2091bf215546Sopenharmony_ci 2092bf215546Sopenharmony_ci if (!flushed) { 2093bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 2094bf215546Sopenharmony_ci flushed = true; 2095bf215546Sopenharmony_ci } 2096bf215546Sopenharmony_ci memcpy(storage, values, size); 2097bf215546Sopenharmony_ci } 2098bf215546Sopenharmony_ci if (!flushed) 2099bf215546Sopenharmony_ci return; 2100bf215546Sopenharmony_ci } else { 2101bf215546Sopenharmony_ci void *storage = &uni->storage[size_mul * components * offset]; 2102bf215546Sopenharmony_ci unsigned size = sizeof(uni->storage[0]) * components * count * size_mul; 2103bf215546Sopenharmony_ci 2104bf215546Sopenharmony_ci if (!memcmp(storage, values, size)) 2105bf215546Sopenharmony_ci return; 2106bf215546Sopenharmony_ci 2107bf215546Sopenharmony_ci _mesa_flush_vertices_for_uniforms(ctx, uni); 2108bf215546Sopenharmony_ci memcpy(storage, values, size); 2109bf215546Sopenharmony_ci _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); 2110bf215546Sopenharmony_ci } 2111bf215546Sopenharmony_ci 2112bf215546Sopenharmony_ci if (uni->type->is_sampler()) { 2113bf215546Sopenharmony_ci /* Mark this bindless sampler as not bound to a texture unit because 2114bf215546Sopenharmony_ci * it refers to a texture handle. 2115bf215546Sopenharmony_ci */ 2116bf215546Sopenharmony_ci for (int i = 0; i < MESA_SHADER_STAGES; i++) { 2117bf215546Sopenharmony_ci struct gl_linked_shader *const sh = shProg->_LinkedShaders[i]; 2118bf215546Sopenharmony_ci 2119bf215546Sopenharmony_ci /* If the shader stage doesn't use the sampler uniform, skip this. */ 2120bf215546Sopenharmony_ci if (!uni->opaque[i].active) 2121bf215546Sopenharmony_ci continue; 2122bf215546Sopenharmony_ci 2123bf215546Sopenharmony_ci for (int j = 0; j < count; j++) { 2124bf215546Sopenharmony_ci unsigned unit = uni->opaque[i].index + offset + j; 2125bf215546Sopenharmony_ci struct gl_bindless_sampler *sampler = 2126bf215546Sopenharmony_ci &sh->Program->sh.BindlessSamplers[unit]; 2127bf215546Sopenharmony_ci 2128bf215546Sopenharmony_ci sampler->bound = false; 2129bf215546Sopenharmony_ci } 2130bf215546Sopenharmony_ci 2131bf215546Sopenharmony_ci update_bound_bindless_sampler_flag(sh->Program); 2132bf215546Sopenharmony_ci } 2133bf215546Sopenharmony_ci } 2134bf215546Sopenharmony_ci 2135bf215546Sopenharmony_ci if (uni->type->is_image()) { 2136bf215546Sopenharmony_ci /* Mark this bindless image as not bound to an image unit because it 2137bf215546Sopenharmony_ci * refers to a texture handle. 2138bf215546Sopenharmony_ci */ 2139bf215546Sopenharmony_ci for (int i = 0; i < MESA_SHADER_STAGES; i++) { 2140bf215546Sopenharmony_ci struct gl_linked_shader *sh = shProg->_LinkedShaders[i]; 2141bf215546Sopenharmony_ci 2142bf215546Sopenharmony_ci /* If the shader stage doesn't use the sampler uniform, skip this. */ 2143bf215546Sopenharmony_ci if (!uni->opaque[i].active) 2144bf215546Sopenharmony_ci continue; 2145bf215546Sopenharmony_ci 2146bf215546Sopenharmony_ci for (int j = 0; j < count; j++) { 2147bf215546Sopenharmony_ci unsigned unit = uni->opaque[i].index + offset + j; 2148bf215546Sopenharmony_ci struct gl_bindless_image *image = 2149bf215546Sopenharmony_ci &sh->Program->sh.BindlessImages[unit]; 2150bf215546Sopenharmony_ci 2151bf215546Sopenharmony_ci image->bound = false; 2152bf215546Sopenharmony_ci } 2153bf215546Sopenharmony_ci 2154bf215546Sopenharmony_ci update_bound_bindless_image_flag(sh->Program); 2155bf215546Sopenharmony_ci } 2156bf215546Sopenharmony_ci } 2157bf215546Sopenharmony_ci} 2158bf215546Sopenharmony_ci 2159bf215546Sopenharmony_ciextern "C" bool 2160bf215546Sopenharmony_ci_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg, 2161bf215546Sopenharmony_ci char *errMsg, size_t errMsgLength) 2162bf215546Sopenharmony_ci{ 2163bf215546Sopenharmony_ci /* Shader does not have samplers. */ 2164bf215546Sopenharmony_ci if (shProg->data->NumUniformStorage == 0) 2165bf215546Sopenharmony_ci return true; 2166bf215546Sopenharmony_ci 2167bf215546Sopenharmony_ci if (!shProg->SamplersValidated) { 2168bf215546Sopenharmony_ci snprintf(errMsg, errMsgLength, 2169bf215546Sopenharmony_ci "active samplers with a different type " 2170bf215546Sopenharmony_ci "refer to the same texture image unit"); 2171bf215546Sopenharmony_ci return false; 2172bf215546Sopenharmony_ci } 2173bf215546Sopenharmony_ci return true; 2174bf215546Sopenharmony_ci} 2175bf215546Sopenharmony_ci 2176bf215546Sopenharmony_ciextern "C" bool 2177bf215546Sopenharmony_ci_mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline) 2178bf215546Sopenharmony_ci{ 2179bf215546Sopenharmony_ci /* Section 2.11.11 (Shader Execution), subheading "Validation," of the 2180bf215546Sopenharmony_ci * OpenGL 4.1 spec says: 2181bf215546Sopenharmony_ci * 2182bf215546Sopenharmony_ci * "[INVALID_OPERATION] is generated by any command that transfers 2183bf215546Sopenharmony_ci * vertices to the GL if: 2184bf215546Sopenharmony_ci * 2185bf215546Sopenharmony_ci * ... 2186bf215546Sopenharmony_ci * 2187bf215546Sopenharmony_ci * - Any two active samplers in the current program object are of 2188bf215546Sopenharmony_ci * different types, but refer to the same texture image unit. 2189bf215546Sopenharmony_ci * 2190bf215546Sopenharmony_ci * - The number of active samplers in the program exceeds the 2191bf215546Sopenharmony_ci * maximum number of texture image units allowed." 2192bf215546Sopenharmony_ci */ 2193bf215546Sopenharmony_ci 2194bf215546Sopenharmony_ci GLbitfield mask; 2195bf215546Sopenharmony_ci GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; 2196bf215546Sopenharmony_ci unsigned active_samplers = 0; 2197bf215546Sopenharmony_ci const struct gl_program **prog = 2198bf215546Sopenharmony_ci (const struct gl_program **) pipeline->CurrentProgram; 2199bf215546Sopenharmony_ci 2200bf215546Sopenharmony_ci 2201bf215546Sopenharmony_ci memset(TexturesUsed, 0, sizeof(TexturesUsed)); 2202bf215546Sopenharmony_ci 2203bf215546Sopenharmony_ci for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) { 2204bf215546Sopenharmony_ci if (!prog[idx]) 2205bf215546Sopenharmony_ci continue; 2206bf215546Sopenharmony_ci 2207bf215546Sopenharmony_ci mask = prog[idx]->SamplersUsed; 2208bf215546Sopenharmony_ci while (mask) { 2209bf215546Sopenharmony_ci const int s = u_bit_scan(&mask); 2210bf215546Sopenharmony_ci GLuint unit = prog[idx]->SamplerUnits[s]; 2211bf215546Sopenharmony_ci GLuint tgt = prog[idx]->sh.SamplerTargets[s]; 2212bf215546Sopenharmony_ci 2213bf215546Sopenharmony_ci /* FIXME: Samplers are initialized to 0 and Mesa doesn't do a 2214bf215546Sopenharmony_ci * great job of eliminating unused uniforms currently so for now 2215bf215546Sopenharmony_ci * don't throw an error if two sampler types both point to 0. 2216bf215546Sopenharmony_ci */ 2217bf215546Sopenharmony_ci if (unit == 0) 2218bf215546Sopenharmony_ci continue; 2219bf215546Sopenharmony_ci 2220bf215546Sopenharmony_ci if (TexturesUsed[unit] & ~(1 << tgt)) { 2221bf215546Sopenharmony_ci pipeline->InfoLog = 2222bf215546Sopenharmony_ci ralloc_asprintf(pipeline, 2223bf215546Sopenharmony_ci "Program %d: " 2224bf215546Sopenharmony_ci "Texture unit %d is accessed with 2 different types", 2225bf215546Sopenharmony_ci prog[idx]->Id, unit); 2226bf215546Sopenharmony_ci return false; 2227bf215546Sopenharmony_ci } 2228bf215546Sopenharmony_ci 2229bf215546Sopenharmony_ci TexturesUsed[unit] |= (1 << tgt); 2230bf215546Sopenharmony_ci } 2231bf215546Sopenharmony_ci 2232bf215546Sopenharmony_ci active_samplers += prog[idx]->info.num_textures; 2233bf215546Sopenharmony_ci } 2234bf215546Sopenharmony_ci 2235bf215546Sopenharmony_ci if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) { 2236bf215546Sopenharmony_ci pipeline->InfoLog = 2237bf215546Sopenharmony_ci ralloc_asprintf(pipeline, 2238bf215546Sopenharmony_ci "the number of active samplers %d exceed the " 2239bf215546Sopenharmony_ci "maximum %d", 2240bf215546Sopenharmony_ci active_samplers, MAX_COMBINED_TEXTURE_IMAGE_UNITS); 2241bf215546Sopenharmony_ci return false; 2242bf215546Sopenharmony_ci } 2243bf215546Sopenharmony_ci 2244bf215546Sopenharmony_ci return true; 2245bf215546Sopenharmony_ci} 2246