/* * Mesa 3-D graphics library * * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. * Copyright © 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * \file uniforms.c * Functions related to GLSL uniform variables. * \author Brian Paul */ /** * XXX things to do: * 1. Check that the right error code is generated for all _mesa_error() calls. * 2. Insert FLUSH_VERTICES calls in various places */ #include "main/glheader.h" #include "main/context.h" #include "main/dispatch.h" #include "main/shaderapi.h" #include "main/shaderobj.h" #include "main/uniforms.h" #include "main/enums.h" #include "ir_uniform.h" #include "glsl_types.h" /** * Update the vertex/fragment program's TexturesUsed array. * * This needs to be called after glUniform(set sampler var) is called. * A call to glUniform(samplerVar, value) causes a sampler to point to a * particular texture unit. We know the sampler's texture target * (1D/2D/3D/etc) from compile time but the sampler's texture unit is * set by glUniform() calls. * * So, scan the program->SamplerUnits[] and program->SamplerTargets[] * information to update the prog->TexturesUsed[] values. * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX, * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc. * We'll use that info for state validation before rendering. */ void _mesa_update_shader_textures_used(struct gl_shader_program *shProg, struct gl_program *prog) { GLuint s; memcpy(prog->SamplerUnits, shProg->SamplerUnits, sizeof(prog->SamplerUnits)); memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed)); for (s = 0; s < MAX_SAMPLERS; s++) { if (prog->SamplersUsed & (1 << s)) { GLuint unit = shProg->SamplerUnits[s]; GLuint tgt = shProg->SamplerTargets[s]; assert(unit < Elements(prog->TexturesUsed)); assert(tgt < NUM_TEXTURE_TARGETS); prog->TexturesUsed[unit] |= (1 << tgt); } } } /** * Connect a piece of driver storage with a part of a uniform * * \param uni The uniform with which the storage will be associated * \param element_stride Byte-stride between array elements. * \sa gl_uniform_driver_storage::element_stride. * \param vector_stride Byte-stride between vectors (in a matrix). * \sa gl_uniform_driver_storage::vector_stride. * \param format Conversion from native format to driver format * required by the driver. * \param data Location to dump the data. */ void _mesa_uniform_attach_driver_storage(struct gl_uniform_storage *uni, unsigned element_stride, unsigned vector_stride, enum gl_uniform_driver_format format, void *data) { uni->driver_storage = realloc(uni->driver_storage, sizeof(struct gl_uniform_driver_storage) * (uni->num_driver_storage + 1)); uni->driver_storage[uni->num_driver_storage].element_stride = element_stride; uni->driver_storage[uni->num_driver_storage].vector_stride = vector_stride; uni->driver_storage[uni->num_driver_storage].format = (uint8_t) format; uni->driver_storage[uni->num_driver_storage].data = data; uni->num_driver_storage++; } /** * Sever all connections with all pieces of driver storage for all uniforms * * \warning * This function does \b not release any of the \c data pointers * previously passed in to \c _mesa_uniform_attach_driver_stoarge. */ void _mesa_uniform_detach_all_driver_storage(struct gl_uniform_storage *uni) { free(uni->driver_storage); uni->driver_storage = NULL; uni->num_driver_storage = 0; } void GLAPIENTRY _mesa_Uniform1f(GLint location, GLfloat v0) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_FLOAT); } void GLAPIENTRY _mesa_Uniform2f(GLint location, GLfloat v0, GLfloat v1) { GET_CURRENT_CONTEXT(ctx); GLfloat v[2]; v[0] = v0; v[1] = v1; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC2); } void GLAPIENTRY _mesa_Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { GET_CURRENT_CONTEXT(ctx); GLfloat v[3]; v[0] = v0; v[1] = v1; v[2] = v2; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC3); } void GLAPIENTRY _mesa_Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { GET_CURRENT_CONTEXT(ctx); GLfloat v[4]; v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC4); } void GLAPIENTRY _mesa_Uniform1i(GLint location, GLint v0) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_INT); } void GLAPIENTRY _mesa_Uniform2i(GLint location, GLint v0, GLint v1) { GET_CURRENT_CONTEXT(ctx); GLint v[2]; v[0] = v0; v[1] = v1; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC2); } void GLAPIENTRY _mesa_Uniform3i(GLint location, GLint v0, GLint v1, GLint v2) { GET_CURRENT_CONTEXT(ctx); GLint v[3]; v[0] = v0; v[1] = v1; v[2] = v2; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC3); } void GLAPIENTRY _mesa_Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { GET_CURRENT_CONTEXT(ctx); GLint v[4]; v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC4); } void GLAPIENTRY _mesa_Uniform1fv(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT); } void GLAPIENTRY _mesa_Uniform2fv(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC2); } void GLAPIENTRY _mesa_Uniform3fv(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC3); } void GLAPIENTRY _mesa_Uniform4fv(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC4); } void GLAPIENTRY _mesa_Uniform1iv(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT); } void GLAPIENTRY _mesa_Uniform2iv(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC2); } void GLAPIENTRY _mesa_Uniform3iv(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC3); } void GLAPIENTRY _mesa_Uniform4iv(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC4); } /** OpenGL 3.0 GLuint-valued functions **/ void GLAPIENTRY _mesa_Uniform1ui(GLint location, GLuint v0) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_UNSIGNED_INT); } void GLAPIENTRY _mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1) { GET_CURRENT_CONTEXT(ctx); GLuint v[2]; v[0] = v0; v[1] = v1; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC2); } void GLAPIENTRY _mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { GET_CURRENT_CONTEXT(ctx); GLuint v[3]; v[0] = v0; v[1] = v1; v[2] = v2; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC3); } void GLAPIENTRY _mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { GET_CURRENT_CONTEXT(ctx); GLuint v[4]; v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC4); } void GLAPIENTRY _mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT); } void GLAPIENTRY _mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC2); } void GLAPIENTRY _mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC3); } void GLAPIENTRY _mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC4); } void GLAPIENTRY _mesa_UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 2, 2, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 3, 3, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 4, 4, location, count, transpose, value); } /** * Non-square UniformMatrix are OpenGL 2.1 */ void GLAPIENTRY _mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 2, 3, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 3, 2, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 2, 4, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 4, 2, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 3, 4, location, count, transpose, value); } void GLAPIENTRY _mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram, 4, 3, location, count, transpose, value); } void GLAPIENTRY _mesa_GetnUniformfvARB(GLhandleARB program, GLint location, GLsizei bufSize, GLfloat *params) { GET_CURRENT_CONTEXT(ctx); _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_FLOAT, params); } void GLAPIENTRY _mesa_GetUniformfv(GLhandleARB program, GLint location, GLfloat *params) { _mesa_GetnUniformfvARB(program, location, INT_MAX, params); } void GLAPIENTRY _mesa_GetnUniformivARB(GLhandleARB program, GLint location, GLsizei bufSize, GLint *params) { GET_CURRENT_CONTEXT(ctx); _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_INT, params); } void GLAPIENTRY _mesa_GetUniformiv(GLhandleARB program, GLint location, GLint *params) { _mesa_GetnUniformivARB(program, location, INT_MAX, params); } /* GL3 */ void GLAPIENTRY _mesa_GetnUniformuivARB(GLhandleARB program, GLint location, GLsizei bufSize, GLuint *params) { GET_CURRENT_CONTEXT(ctx); _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_UINT, params); } void GLAPIENTRY _mesa_GetUniformuiv(GLhandleARB program, GLint location, GLuint *params) { _mesa_GetnUniformuivARB(program, location, INT_MAX, params); } /* GL4 */ void GLAPIENTRY _mesa_GetnUniformdvARB(GLhandleARB program, GLint location, GLsizei bufSize, GLdouble *params) { GET_CURRENT_CONTEXT(ctx); (void) program; (void) location; (void) bufSize; (void) params; /* _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_DOUBLE, params); */ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformdvARB" "(GL_ARB_gpu_shader_fp64 not implemented)"); } void GLAPIENTRY _mesa_GetUniformdv(GLhandleARB program, GLint location, GLdouble *params) { _mesa_GetnUniformdvARB(program, location, INT_MAX, params); } GLint GLAPIENTRY _mesa_GetUniformLocation(GLhandleARB programObj, const GLcharARB *name) { struct gl_shader_program *shProg; GLuint index, offset; GET_CURRENT_CONTEXT(ctx); shProg = _mesa_lookup_shader_program_err(ctx, programObj, "glGetUniformLocation"); if (!shProg) return -1; /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says: * * "If program has not been successfully linked, the error * INVALID_OPERATION is generated." */ if (shProg->LinkStatus == GL_FALSE) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformLocation(program not linked)"); return -1; } index = _mesa_get_uniform_location(ctx, shProg, name, &offset); if (index == GL_INVALID_INDEX) return -1; /* From the GL_ARB_uniform_buffer_object spec: * * "The value -1 will be returned if <name> does not correspond to an * active uniform variable name in <program>, if <name> is associated * with a named uniform block, or if <name> starts with the reserved * prefix "gl_"." */ if (shProg->UniformStorage[index].block_index != -1) return -1; return _mesa_uniform_merge_location_offset(index, offset); } GLuint GLAPIENTRY _mesa_GetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) { GET_CURRENT_CONTEXT(ctx); GLuint i; struct gl_shader_program *shProg; if (!ctx->Extensions.ARB_uniform_buffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformBlockIndex"); return GL_INVALID_INDEX; } shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetUniformBlockIndex"); if (!shProg) return GL_INVALID_INDEX; for (i = 0; i < shProg->NumUniformBlocks; i++) { if (!strcmp(shProg->UniformBlocks[i].Name, uniformBlockName)) return i; } return GL_INVALID_INDEX; } void GLAPIENTRY _mesa_GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar * const *uniformNames, GLuint *uniformIndices) { GET_CURRENT_CONTEXT(ctx); GLsizei i; struct gl_shader_program *shProg; if (!ctx->Extensions.ARB_uniform_buffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformIndices"); return; } shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetUniformIndices"); if (!shProg) return; if (uniformCount < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformIndices(uniformCount < 0)"); return; } for (i = 0; i < uniformCount; i++) { unsigned offset; uniformIndices[i] = _mesa_get_uniform_location(ctx, shProg, uniformNames[i], &offset); } } void GLAPIENTRY _mesa_UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; if (!ctx->Extensions.ARB_uniform_buffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformBlockBinding"); return; } shProg = _mesa_lookup_shader_program_err(ctx, program, "glUniformBlockBinding"); if (!shProg) return; if (uniformBlockIndex >= shProg->NumUniformBlocks) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformBlockBinding(block index %u >= %u)", uniformBlockIndex, shProg->NumUniformBlocks); return; } if (uniformBlockBinding >= ctx->Const.MaxUniformBufferBindings) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformBlockBinding(block binding %u >= %u)", uniformBlockBinding, ctx->Const.MaxUniformBufferBindings); return; } if (shProg->UniformBlocks[uniformBlockIndex].Binding != uniformBlockBinding) { int i; FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; shProg->UniformBlocks[uniformBlockIndex].Binding = uniformBlockBinding; for (i = 0; i < MESA_SHADER_TYPES; i++) { int stage_index = shProg->UniformBlockStageIndex[i][uniformBlockIndex]; if (stage_index != -1) { struct gl_shader *sh = shProg->_LinkedShaders[i]; sh->UniformBlocks[stage_index].Binding = uniformBlockBinding; } } } } void GLAPIENTRY _mesa_GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; struct gl_uniform_block *block; unsigned i; if (!ctx->Extensions.ARB_uniform_buffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetActiveUniformBlockiv"); return; } shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniformBlockiv"); if (!shProg) return; if (uniformBlockIndex >= shProg->NumUniformBlocks) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformBlockiv(block index %u >= %u)", uniformBlockIndex, shProg->NumUniformBlocks); return; } block = &shProg->UniformBlocks[uniformBlockIndex]; switch (pname) { case GL_UNIFORM_BLOCK_BINDING: params[0] = block->Binding; return; case GL_UNIFORM_BLOCK_DATA_SIZE: params[0] = block->UniformBufferSize; return; case GL_UNIFORM_BLOCK_NAME_LENGTH: params[0] = strlen(block->Name) + 1; return; case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: params[0] = block->NumUniforms; return; case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: for (i = 0; i < block->NumUniforms; i++) { unsigned offset; params[i] = _mesa_get_uniform_location(ctx, shProg, block->Uniforms[i].IndexName, &offset); } return; case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: params[0] = shProg->UniformBlockStageIndex[MESA_SHADER_VERTEX][uniformBlockIndex] != -1; return; case GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER: params[0] = shProg->UniformBlockStageIndex[MESA_SHADER_GEOMETRY][uniformBlockIndex] != -1; return; case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: params[0] = shProg->UniformBlockStageIndex[MESA_SHADER_FRAGMENT][uniformBlockIndex] != -1; return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformBlockiv(pname 0x%x (%s))", pname, _mesa_lookup_enum_by_nr(pname)); return; } } void GLAPIENTRY _mesa_GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; struct gl_uniform_block *block; if (!ctx->Extensions.ARB_uniform_buffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetActiveUniformBlockiv"); return; } if (bufSize < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformBlockName(bufSize %d < 0)", bufSize); return; } shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniformBlockiv"); if (!shProg) return; if (uniformBlockIndex >= shProg->NumUniformBlocks) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformBlockiv(block index %u >= %u)", uniformBlockIndex, shProg->NumUniformBlocks); return; } block = &shProg->UniformBlocks[uniformBlockIndex]; if (uniformBlockName) { _mesa_copy_string(uniformBlockName, bufSize, length, block->Name); } } void GLAPIENTRY _mesa_GetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; if (!ctx->Extensions.ARB_uniform_buffer_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetActiveUniformBlockiv"); return; } if (bufSize < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformName(bufSize %d < 0)", bufSize); return; } shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniformName"); if (!shProg) return; if (uniformIndex >= shProg->NumUserUniformStorage) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); return; } if (uniformName) { _mesa_get_uniform_name(& shProg->UniformStorage[uniformIndex], bufSize, length, uniformName); } } void _mesa_get_uniform_name(const struct gl_uniform_storage *uni, GLsizei maxLength, GLsizei *length, GLchar *nameOut) { GLsizei localLength; if (length == NULL) length = &localLength; _mesa_copy_string(nameOut, maxLength, length, uni->name); /* Page 61 (page 73 of the PDF) in section 2.11 of the OpenGL ES 3.0 * spec says: * * "If the active uniform is an array, the uniform name returned in * name will always be the name of the uniform array appended with * "[0]"." * * The same text also appears in the OpenGL 4.2 spec. It does not, * however, appear in any previous spec. Previous specifications are * ambiguous in this regard. However, either name can later be passed * to glGetUniformLocation (and related APIs), so there shouldn't be any * harm in always appending "[0]" to uniform array names. */ if (uni->array_elements != 0) { unsigned i; /* The comparison is strange because *length does *NOT* include the * terminating NUL, but maxLength does. */ for (i = 0; i < 3 && (*length + i + 1) < maxLength; i++) nameOut[*length + i] = "[0]"[i]; nameOut[*length + i] = '\0'; *length += i; } }