/** * Called by glUniformMatrix*() functions. * Note: cols=2, rows=4 ==> array[2] of vec4 */ extern "C" void _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, GLuint cols, GLuint rows, GLint location, GLsizei count, GLboolean transpose, const GLvoid *values, enum glsl_base_type basicType) { unsigned offset; unsigned vectors; unsigned components; unsigned elements; int size_mul; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, count, &offset, "glUniformMatrix"); if (uni == NULL) return; if (!uni->type->is_matrix()) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(non-matrix uniform)"); return; } assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE); size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1; assert(!uni->type->is_sampler()); vectors = uni->type->matrix_columns; components = uni->type->vector_elements; /* Verify that the types are compatible. This is greatly simplified for * matrices because they can only have a float base type. */ if (vectors != cols || components != rows) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(matrix size mismatch)"); return; } /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE. * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml */ if (transpose) { if (ctx->API == API_OPENGLES2 && ctx->Version < 30) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(matrix transpose is not GL_FALSE)"); return; } } /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec * says: * * "If any of the following conditions occur, an INVALID_OPERATION * error is generated by the Uniform* commands, and no uniform values * are changed: * * ... * * - if the uniform declared in the shader is not of type boolean and * the type indicated in the name of the Uniform* command used does * not match the type of the uniform" * * There are no Boolean matrix types, so we do not need to allow * GLSL_TYPE_BOOL here (as _mesa_uniform does). */ if (uni->type->base_type != basicType) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)", cols, rows, uni->name, location, glsl_type_name(uni->type->base_type), glsl_type_name(basicType)); return; } if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { log_uniform(values, uni->type->base_type, components, vectors, count, bool(transpose), shProg, location, uni); } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { count = MIN2(count, (int) (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ elements = components * vectors; if (!transpose) { memcpy(&uni->storage[elements * offset], values, sizeof(uni->storage[0]) * elements * count * size_mul); } else if (basicType == GLSL_TYPE_FLOAT) { /* Copy and transpose the matrix. */ const float *src = (const float *)values; float *dst = &uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { for (unsigned r = 0; r < rows; r++) { for (unsigned c = 0; c < cols; c++) { dst[(c * components) + r] = src[c + (r * vectors)]; } } dst += elements; src += elements; } } else { assert(basicType == GLSL_TYPE_DOUBLE); const double *src = (const double *)values; double *dst = (double *)&uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { for (unsigned r = 0; r < rows; r++) { for (unsigned c = 0; c < cols; c++) { dst[(c * components) + r] = src[c + (r * vectors)]; } } dst += elements; src += elements; } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); }
/** * Called via glUniform*() functions. */ extern "C" void _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, GLint location, GLsizei count, const GLvoid *values, enum glsl_base_type basicType, unsigned src_components) { unsigned offset; int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, count, &offset, "glUniform"); if (uni == NULL) return; if (uni->type->is_matrix()) { /* Can't set matrix uniforms (like mat4) with glUniform */ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform%u(uniform \"%s\"@%d is matrix)", src_components, uni->name, location); return; } /* Verify that the types are compatible. */ const unsigned components = uni->type->is_sampler() ? 1 : uni->type->vector_elements; if (components != src_components) { /* glUniformN() must match float/vecN type */ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform%u(\"%s\"@%u has %u components, not %u)", src_components, uni->name, location, components, src_components); return; } bool match; switch (uni->type->base_type) { case GLSL_TYPE_BOOL: match = (basicType != GLSL_TYPE_DOUBLE); break; case GLSL_TYPE_SAMPLER: match = (basicType == GLSL_TYPE_INT); break; case GLSL_TYPE_IMAGE: match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx)); break; default: match = (basicType == uni->type->base_type); break; } if (!match) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform%u(\"%s\"@%d is %s, not %s)", src_components, uni->name, location, glsl_type_name(uni->type->base_type), glsl_type_name(basicType)); return; } if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { log_uniform(values, basicType, components, 1, count, false, shProg, location, uni); } /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: * * "Setting a sampler's value to i selects texture image unit number * i. The values of i range from zero to the implementation- dependent * maximum supported number of texture image units." * * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of * the PDF) says: * * "Error Description Offending command * ignored? * ... * INVALID_VALUE Numeric argument out of range Yes" * * Based on that, when an invalid sampler is specified, we generate a * GL_INVALID_VALUE error and ignore the command. */ if (uni->type->is_sampler()) { for (int i = 0; i < count; i++) { const unsigned texUnit = ((unsigned *) values)[i]; /* check that the sampler (tex unit index) is legal */ if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1i(invalid sampler/tex unit index for " "uniform %d)", location); return; } } } if (uni->type->is_image()) { for (int i = 0; i < count; i++) { const int unit = ((GLint *) values)[i]; /* check that the image unit is legal */ if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1i(invalid image unit index for uniform %d)", location); return; } } } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { count = MIN2(count, (int) (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ if (!uni->type->is_boolean()) { memcpy(&uni->storage[size_mul * components * offset], values, sizeof(uni->storage[0]) * components * count * size_mul); } else { const union gl_constant_value *src = (const union gl_constant_value *) values; union gl_constant_value *dst = &uni->storage[components * offset]; const unsigned elems = components * count; for (unsigned i = 0; i < elems; i++) { if (basicType == GLSL_TYPE_FLOAT) { dst[i].i = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0; } else { dst[i].i = src[i].i != 0 ? ctx->Const.UniformBooleanTrue : 0; } } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); /* If the uniform is a sampler, do the extra magic necessary to propagate * the changes through. */ if (uni->type->is_sampler()) { bool flushed = false; for (int i = 0; i < MESA_SHADER_STAGES; i++) { struct gl_shader *const sh = shProg->_LinkedShaders[i]; /* If the shader stage doesn't use the sampler uniform, skip this. */ if (sh == NULL || !uni->sampler[i].active) continue; for (int j = 0; j < count; j++) { sh->SamplerUnits[uni->sampler[i].index + offset + j] = ((unsigned *) values)[j]; } struct gl_program *const prog = sh->Program; assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits)); /* Determine if any of the samplers used by this shader stage have * been modified. */ bool changed = false; for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) { if ((sh->active_samplers & (1U << j)) != 0 && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) { changed = true; break; } } if (changed) { if (!flushed) { FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); flushed = true; } memcpy(prog->SamplerUnits, sh->SamplerUnits, sizeof(sh->SamplerUnits)); _mesa_update_shader_textures_used(shProg, prog); if (ctx->Driver.SamplerUniformChange) ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog); } } } /* If the uniform is an image, update the mapping from image * uniforms to image units present in the shader data structure. */ if (uni->type->is_image()) { for (int i = 0; i < MESA_SHADER_STAGES; i++) { if (uni->image[i].active) { struct gl_shader *sh = shProg->_LinkedShaders[i]; for (int j = 0; j < count; j++) sh->ImageUnits[uni->image[i].index + offset + j] = ((GLint *) values)[j]; } } ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; } }
/** * Called via glGetUniform[fiui]v() to get the current value of a uniform. */ extern "C" void _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, GLsizei bufSize, enum glsl_base_type returnType, GLvoid *paramsOut) { struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv"); unsigned offset; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, 1, &offset, "glGetUniform"); if (uni == NULL) { /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1 * spec says: * * "The error INVALID_OPERATION is generated if program has not been * linked successfully, or if location is not a valid location for * program." * * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec * says: * * "If the value of location is -1, the Uniform* commands will * silently ignore the data passed in, and the current uniform * values will not be changed." * * Allowing -1 for the location parameter of glUniform allows * applications to avoid error paths in the case that, for example, some * uniform variable is removed by the compiler / linker after * optimization. In this case, the new value of the uniform is dropped * on the floor. For the case of glGetUniform, there is nothing * sensible to do for a location of -1. * * If the location was -1, validate_unfirom_parameters will return NULL * without raising an error. Raise the error here. */ if (location == -1) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniform(location=%d)", location); } return; } if ((uni->type->base_type == GLSL_TYPE_DOUBLE && returnType != GLSL_TYPE_DOUBLE) || (uni->type->base_type != GLSL_TYPE_DOUBLE && returnType == GLSL_TYPE_DOUBLE)) { _mesa_error( ctx, GL_INVALID_OPERATION, "glGetnUniform*vARB(incompatible uniform types)"); return; } { unsigned elements = (uni->type->is_sampler()) ? 1 : uni->type->components(); const int dmul = uni->type->base_type == GLSL_TYPE_DOUBLE ? 2 : 1; /* Calculate the source base address *BEFORE* modifying elements to * account for the size of the user's buffer. */ const union gl_constant_value *const src = &uni->storage[offset * elements * dmul]; assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_DOUBLE); /* doubles have a different size than the other 3 types */ unsigned bytes = sizeof(src[0]) * elements * dmul; if (bufSize < 0 || bytes > (unsigned) bufSize) { _mesa_error( ctx, GL_INVALID_OPERATION, "glGetnUniform*vARB(out of bounds: bufSize is %d," " but %u bytes are required)", bufSize, bytes ); return; } /* If the return type and the uniform's native type are "compatible," * just memcpy the data. If the types are not compatible, perform a * slower convert-and-copy process. */ if (returnType == uni->type->base_type || ((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT) && (uni->type->base_type == GLSL_TYPE_INT || uni->type->base_type == GLSL_TYPE_UINT || uni->type->base_type == GLSL_TYPE_SAMPLER || uni->type->base_type == GLSL_TYPE_IMAGE))) { memcpy(paramsOut, src, bytes); } else { union gl_constant_value *const dst = (union gl_constant_value *) paramsOut; /* This code could be optimized by putting the loop inside the switch * statements. However, this is not expected to be * performance-critical code. */ for (unsigned i = 0; i < elements; i++) { switch (returnType) { case GLSL_TYPE_FLOAT: switch (uni->type->base_type) { case GLSL_TYPE_UINT: dst[i].f = (float) src[i].u; break; case GLSL_TYPE_INT: case GLSL_TYPE_SAMPLER: case GLSL_TYPE_IMAGE: dst[i].f = (float) src[i].i; break; case GLSL_TYPE_BOOL: dst[i].f = src[i].i ? 1.0f : 0.0f; break; default: assert(!"Should not get here."); break; } break; case GLSL_TYPE_INT: case GLSL_TYPE_UINT: switch (uni->type->base_type) { case GLSL_TYPE_FLOAT: /* While the GL 3.2 core spec doesn't explicitly * state how conversion of float uniforms to integer * values works, in section 6.2 "State Tables" on * page 267 it says: * * "Unless otherwise specified, when floating * point state is returned as integer values or * integer state is returned as floating-point * values it is converted in the fashion * described in section 6.1.2" * * That section, on page 248, says: * * "If GetIntegerv or GetInteger64v are called, * a floating-point value is rounded to the * nearest integer..." */ dst[i].i = IROUND(src[i].f); break; case GLSL_TYPE_BOOL: dst[i].i = src[i].i ? 1 : 0; break; default: assert(!"Should not get here."); break; } break; default: assert(!"Should not get here."); break; } } } } }
/** * Called by glUniformMatrix*() functions. * Note: cols=2, rows=4 ==> array[2] of vec4 */ extern "C" void _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, GLuint cols, GLuint rows, GLint location, GLsizei count, GLboolean transpose, const GLfloat *values) { unsigned loc, offset; unsigned vectors; unsigned components; unsigned elements; struct gl_uniform_storage *uni; ASSERT_OUTSIDE_BEGIN_END(ctx); if (!validate_uniform_parameters(ctx, shProg, location, count, &loc, &offset, "glUniformMatrix", false)) return; uni = &shProg->UniformStorage[loc]; if (!uni->type->is_matrix()) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(non-matrix uniform)"); return; } assert(!uni->type->is_sampler()); vectors = uni->type->matrix_columns; components = uni->type->vector_elements; /* Verify that the types are compatible. This is greatly simplified for * matrices because they can only have a float base type. */ if (vectors != cols || components != rows) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(matrix size mismatch)"); return; } if (ctx->Shader.Flags & GLSL_UNIFORMS) { log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count, bool(transpose), shProg, location, uni); } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { if (offset >= uni->array_elements) return; count = MIN2(count, (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ elements = components * vectors; if (!transpose) { memcpy(&uni->storage[elements * offset], values, sizeof(uni->storage[0]) * elements * count); } else { /* Copy and transpose the matrix. */ const float *src = values; float *dst = &uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { for (unsigned r = 0; r < rows; r++) { for (unsigned c = 0; c < cols; c++) { dst[(c * components) + r] = src[c + (r * vectors)]; } } dst += elements; src += elements; } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); }
/** * Called via glUniform*() functions. */ extern "C" void _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, GLint location, GLsizei count, const GLvoid *values, GLenum type) { unsigned loc, offset; unsigned components; unsigned src_components; enum glsl_base_type basicType; struct gl_uniform_storage *uni; ASSERT_OUTSIDE_BEGIN_END(ctx); if (!validate_uniform_parameters(ctx, shProg, location, count, &loc, &offset, "glUniform", false)) return; uni = &shProg->UniformStorage[loc]; /* Verify that the types are compatible. */ switch (type) { case GL_FLOAT: basicType = GLSL_TYPE_FLOAT; src_components = 1; break; case GL_FLOAT_VEC2: basicType = GLSL_TYPE_FLOAT; src_components = 2; break; case GL_FLOAT_VEC3: basicType = GLSL_TYPE_FLOAT; src_components = 3; break; case GL_FLOAT_VEC4: basicType = GLSL_TYPE_FLOAT; src_components = 4; break; case GL_UNSIGNED_INT: basicType = GLSL_TYPE_UINT; src_components = 1; break; case GL_UNSIGNED_INT_VEC2: basicType = GLSL_TYPE_UINT; src_components = 2; break; case GL_UNSIGNED_INT_VEC3: basicType = GLSL_TYPE_UINT; src_components = 3; break; case GL_UNSIGNED_INT_VEC4: basicType = GLSL_TYPE_UINT; src_components = 4; break; case GL_INT: basicType = GLSL_TYPE_INT; src_components = 1; break; case GL_INT_VEC2: basicType = GLSL_TYPE_INT; src_components = 2; break; case GL_INT_VEC3: basicType = GLSL_TYPE_INT; src_components = 3; break; case GL_INT_VEC4: basicType = GLSL_TYPE_INT; src_components = 4; break; case GL_BOOL: case GL_BOOL_VEC2: case GL_BOOL_VEC3: case GL_BOOL_VEC4: case GL_FLOAT_MAT2: case GL_FLOAT_MAT2x3: case GL_FLOAT_MAT2x4: case GL_FLOAT_MAT3x2: case GL_FLOAT_MAT3: case GL_FLOAT_MAT3x4: case GL_FLOAT_MAT4x2: case GL_FLOAT_MAT4x3: case GL_FLOAT_MAT4: default: _mesa_problem(NULL, "Invalid type in %s", __func__); return; } if (uni->type->is_sampler()) { components = 1; } else { components = uni->type->vector_elements; } bool match; switch (uni->type->base_type) { case GLSL_TYPE_BOOL: match = true; break; case GLSL_TYPE_SAMPLER: match = (basicType == GLSL_TYPE_INT); break; default: match = (basicType == uni->type->base_type); break; } if (uni->type->is_matrix() || components != src_components || !match) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); return; } if (ctx->Shader.Flags & GLSL_UNIFORMS) { log_uniform(values, basicType, components, 1, count, false, shProg, location, uni); } /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: * * "Setting a sampler's value to i selects texture image unit number * i. The values of i range from zero to the implementation- dependent * maximum supported number of texture image units." * * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of * the PDF) says: * * "Error Description Offending command * ignored? * ... * INVALID_VALUE Numeric argument out of range Yes" * * Based on that, when an invalid sampler is specified, we generate a * GL_INVALID_VALUE error and ignore the command. */ if (uni->type->is_sampler()) { int i; for (i = 0; i < count; i++) { const unsigned texUnit = ((unsigned *) values)[i]; /* check that the sampler (tex unit index) is legal */ if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1i(invalid sampler/tex unit index for " "uniform %d)", location); return; } } } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { if (offset >= uni->array_elements) return; count = MIN2(count, (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ if (!uni->type->is_boolean()) { memcpy(&uni->storage[components * offset], values, sizeof(uni->storage[0]) * components * count); } else { const union gl_constant_value *src = (const union gl_constant_value *) values; union gl_constant_value *dst = &uni->storage[components * offset]; const unsigned elems = components * count; unsigned i; for (i = 0; i < elems; i++) { if (basicType == GLSL_TYPE_FLOAT) { dst[i].i = src[i].f != 0.0f ? 1 : 0; } else { dst[i].i = src[i].i != 0 ? 1 : 0; } } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); /* If the uniform is a sampler, do the extra magic necessary to propagate * the changes through. */ if (uni->type->is_sampler()) { int i; for (i = 0; i < count; i++) { shProg->SamplerUnits[uni->sampler + offset + i] = ((unsigned *) values)[i]; } bool flushed = false; for (i = 0; i < MESA_SHADER_TYPES; i++) { struct gl_program *prog; if (shProg->_LinkedShaders[i] == NULL) continue; prog = shProg->_LinkedShaders[i]->Program; /* If the shader stage doesn't use any samplers, don't bother * checking if any samplers have changed. */ if (prog->SamplersUsed == 0) continue; assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits)); /* Determine if any of the samplers used by this shader stage have * been modified. */ bool changed = false; for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) { if ((prog->SamplersUsed & (1U << j)) != 0 && (prog->SamplerUnits[j] != shProg->SamplerUnits[j])) { changed = true; break; } } if (changed) { if (!flushed) { FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); flushed = true; } memcpy(prog->SamplerUnits, shProg->SamplerUnits, sizeof(shProg->SamplerUnits)); _mesa_update_shader_textures_used(prog); (void) ctx->Driver.ProgramStringNotify(ctx, prog->Target, prog); } } } }
/** * Called via glGetUniform[fiui]v() to get the current value of a uniform. */ extern "C" void _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, GLsizei bufSize, enum glsl_base_type returnType, GLvoid *paramsOut) { struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv"); struct gl_uniform_storage *uni; unsigned loc, offset; if (!validate_uniform_parameters(ctx, shProg, location, 1, &loc, &offset, "glGetUniform", true)) return; uni = &shProg->UniformStorage[loc]; { unsigned elements = (uni->type->is_sampler()) ? 1 : uni->type->components(); /* Calculate the source base address *BEFORE* modifying elements to * account for the size of the user's buffer. */ const union gl_constant_value *const src = &uni->storage[offset * elements]; unsigned bytes = sizeof(uni->storage[0]) * elements; if (bytes > (unsigned) bufSize) { elements = bufSize / sizeof(uni->storage[0]); bytes = bufSize; } /* If the return type and the uniform's native type are "compatible," * just memcpy the data. If the types are not compatible, perform a * slower convert-and-copy process. */ if (returnType == uni->type->base_type || ((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_SAMPLER) && (uni->type->base_type == GLSL_TYPE_INT || uni->type->base_type == GLSL_TYPE_UINT || uni->type->base_type == GLSL_TYPE_SAMPLER))) { memcpy(paramsOut, src, bytes); } else { union gl_constant_value *const dst = (union gl_constant_value *) paramsOut; /* This code could be optimized by putting the loop inside the switch * statements. However, this is not expected to be * performance-critical code. */ for (unsigned i = 0; i < elements; i++) { switch (returnType) { case GLSL_TYPE_FLOAT: switch (uni->type->base_type) { case GLSL_TYPE_UINT: dst[i].f = (float) src[i].u; break; case GLSL_TYPE_INT: case GLSL_TYPE_SAMPLER: dst[i].f = (float) src[i].i; break; case GLSL_TYPE_BOOL: dst[i].f = src[i].i ? 1.0f : 0.0f; break; default: assert(!"Should not get here."); break; } break; case GLSL_TYPE_INT: case GLSL_TYPE_UINT: switch (uni->type->base_type) { case GLSL_TYPE_FLOAT: /* While the GL 3.2 core spec doesn't explicitly * state how conversion of float uniforms to integer * values works, in section 6.2 "State Tables" on * page 267 it says: * * "Unless otherwise specified, when floating * point state is returned as integer values or * integer state is returned as floating-point * values it is converted in the fashion * described in section 6.1.2" * * That section, on page 248, says: * * "If GetIntegerv or GetInteger64v are called, * a floating-point value is rounded to the * nearest integer..." */ dst[i].i = IROUND(src[i].f); break; case GLSL_TYPE_BOOL: dst[i].i = src[i].i ? 1 : 0; break; default: assert(!"Should not get here."); break; } break; default: assert(!"Should not get here."); break; } } } } }