*/
#include <stdlib.h>
+#include <inttypes.h> /* for PRIx64 macro */
+#include <math.h>
-#include "main/core.h"
#include "main/context.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
}
static struct gl_uniform_storage *
-validate_uniform_parameters(struct gl_context *ctx,
- struct gl_shader_program *shProg,
- GLint location, GLsizei count,
- unsigned *array_index,
- const char *caller)
+validate_uniform_parameters(GLint location, GLsizei count,
+ unsigned *array_index,
+ struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ const char *caller)
{
if (shProg == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller);
unsigned offset;
struct gl_uniform_storage *const uni =
- validate_uniform_parameters(ctx, shProg, location, 1,
- &offset, "glGetUniform");
+ validate_uniform_parameters(location, 1, &offset,
+ ctx, shProg, "glGetUniform");
if (uni == NULL) {
/* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1
* spec says:
}
{
- unsigned elements = (uni->type->is_sampler())
- ? 1 : uni->type->components();
- const int dmul = uni->type->is_64bit() ? 2 : 1;
+ unsigned elements = uni->type->components();
const int rmul = glsl_base_type_is_64bit(returnType) ? 2 : 1;
+ int dmul = (uni->type->is_64bit()) ? 2 : 1;
+
+ if ((uni->type->is_sampler() || uni->type->is_image()) &&
+ !uni->is_bindless) {
+ /* Non-bindless samplers/images are represented using unsigned integer
+ * 32-bit, while bindless handles are 64-bit.
+ */
+ dmul = 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];
+ const union gl_constant_value *src;
+ if (ctx->Const.PackedDriverUniformStorage &&
+ (uni->is_bindless || !uni->type->contains_opaque())) {
+ src = (gl_constant_value *) uni->driver_storage[0].data +
+ (offset * elements * dmul);
+ } else {
+ 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 * rmul;
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;
+ _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))
- || ((returnType == GLSL_TYPE_UINT64 ||
- returnType == GLSL_TYPE_INT64 ) &&
- (uni->type->base_type == GLSL_TYPE_UINT64 ||
- uni->type->base_type == GLSL_TYPE_INT64))) {
- memcpy(paramsOut, src, bytes);
+ if (returnType == uni->type->base_type ||
+ ((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT) &&
+ (uni->type->is_sampler() || uni->type->is_image())) ||
+ (returnType == GLSL_TYPE_UINT64 && uni->is_bindless)) {
+ memcpy(paramsOut, src, bytes);
} else {
- union gl_constant_value *const dst =
- (union gl_constant_value *) paramsOut;
- /* This code could be optimized by putting the loop inside the switch
- * statements. However, this is not expected to be
- * performance-critical code.
- */
- for (unsigned i = 0; i < elements; i++) {
- int sidx = i * dmul;
- int didx = i * rmul;
-
- switch (returnType) {
- case GLSL_TYPE_FLOAT:
- switch (uni->type->base_type) {
- case GLSL_TYPE_UINT:
- dst[didx].f = (float) src[sidx].u;
- break;
- case GLSL_TYPE_INT:
- case GLSL_TYPE_SAMPLER:
+ union gl_constant_value *const dst =
+ (union gl_constant_value *) paramsOut;
+ /* This code could be optimized by putting the loop inside the switch
+ * statements. However, this is not expected to be
+ * performance-critical code.
+ */
+ for (unsigned i = 0; i < elements; i++) {
+ int sidx = i * dmul;
+ int didx = i * rmul;
+
+ switch (returnType) {
+ case GLSL_TYPE_FLOAT:
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_UINT:
+ dst[didx].f = (float) src[sidx].u;
+ break;
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_SAMPLER:
case GLSL_TYPE_IMAGE:
- dst[didx].f = (float) src[sidx].i;
- break;
- case GLSL_TYPE_BOOL:
- dst[didx].f = src[sidx].i ? 1.0f : 0.0f;
- break;
+ dst[didx].f = (float) src[sidx].i;
+ break;
+ case GLSL_TYPE_BOOL:
+ dst[didx].f = src[sidx].i ? 1.0f : 0.0f;
+ break;
case GLSL_TYPE_DOUBLE: {
double tmp;
memcpy(&tmp, &src[sidx].f, sizeof(tmp));
dst[didx].f = tmp;
- break;
+ break;
}
case GLSL_TYPE_UINT64: {
uint64_t tmp;
memcpy(&tmp, &src[sidx].u, sizeof(tmp));
dst[didx].f = tmp;
break;
- }
+ }
case GLSL_TYPE_INT64: {
uint64_t tmp;
memcpy(&tmp, &src[sidx].i, sizeof(tmp));
dst[didx].f = tmp;
break;
}
- default:
- assert(!"Should not get here.");
- break;
- }
- break;
- case GLSL_TYPE_DOUBLE:
- switch (uni->type->base_type) {
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+
+ case GLSL_TYPE_DOUBLE:
+ switch (uni->type->base_type) {
case GLSL_TYPE_UINT: {
double tmp = src[sidx].u;
memcpy(&dst[didx].f, &tmp, sizeof(tmp));
- break;
+ break;
}
- case GLSL_TYPE_INT:
- case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_SAMPLER:
case GLSL_TYPE_IMAGE: {
double tmp = src[sidx].i;
memcpy(&dst[didx].f, &tmp, sizeof(tmp));
- break;
+ break;
}
case GLSL_TYPE_BOOL: {
double tmp = src[sidx].i ? 1.0 : 0.0;
memcpy(&dst[didx].f, &tmp, sizeof(tmp));
- break;
+ break;
}
case GLSL_TYPE_FLOAT: {
double tmp = src[sidx].f;
memcpy(&dst[didx].f, &tmp, sizeof(tmp));
- break;
+ break;
}
case GLSL_TYPE_UINT64: {
uint64_t tmpu;
memcpy(&dst[didx].f, &tmp, sizeof(tmp));
break;
}
- default:
- assert(!"Should not get here.");
- break;
- }
- break;
- case GLSL_TYPE_INT:
- case GLSL_TYPE_UINT:
- switch (uni->type->base_type) {
- 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[didx].i = IROUND(src[sidx].f);
- break;
- case GLSL_TYPE_BOOL:
- dst[didx].i = src[sidx].i ? 1 : 0;
- break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+
+ case GLSL_TYPE_INT:
+ 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[didx].i = (int64_t) roundf(src[sidx].f);
+ break;
+ case GLSL_TYPE_BOOL:
+ dst[didx].i = src[sidx].i ? 1 : 0;
+ break;
+ case GLSL_TYPE_UINT:
+ dst[didx].i = MIN2(src[sidx].i, INT_MAX);
+ break;
case GLSL_TYPE_DOUBLE: {
double tmp;
memcpy(&tmp, &src[sidx].f, sizeof(tmp));
- dst[didx].i = IROUNDD(tmp);
- break;
+ dst[didx].i = (int64_t) round(tmp);
+ break;
}
case GLSL_TYPE_UINT64: {
uint64_t tmp;
dst[didx].i = tmp;
break;
}
- default:
- assert(!"Should not get here.");
- break;
- }
- break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+
+ case GLSL_TYPE_UINT:
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ /* The spec isn't terribly clear how to handle negative
+ * values with an unsigned return type.
+ *
+ * GL 4.5 section 2.2.2 ("Data Conversions for State
+ * Query Commands") says:
+ *
+ * "If a value is so large in magnitude that it cannot be
+ * represented by the returned data type, then the nearest
+ * value representable using the requested type is
+ * returned."
+ */
+ dst[didx].u = src[sidx].f < 0.0f ?
+ 0u : (uint32_t) roundf(src[sidx].f);
+ break;
+ case GLSL_TYPE_BOOL:
+ dst[didx].i = src[sidx].i ? 1 : 0;
+ break;
+ case GLSL_TYPE_INT:
+ dst[didx].i = MAX2(src[sidx].i, 0);
+ break;
+ case GLSL_TYPE_DOUBLE: {
+ double tmp;
+ memcpy(&tmp, &src[sidx].f, sizeof(tmp));
+ dst[didx].u = tmp < 0.0 ? 0u : (uint32_t) round(tmp);
+ break;
+ }
+ case GLSL_TYPE_UINT64: {
+ uint64_t tmp;
+ memcpy(&tmp, &src[sidx].u, sizeof(tmp));
+ dst[didx].i = MIN2(tmp, INT_MAX);
+ break;
+ }
+ case GLSL_TYPE_INT64: {
+ int64_t tmp;
+ memcpy(&tmp, &src[sidx].i, sizeof(tmp));
+ dst[didx].i = MAX2(tmp, 0);
+ break;
+ }
+ default:
+ unreachable("invalid uniform type");
+ }
+ break;
+
case GLSL_TYPE_INT64:
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_UINT: {
+ uint64_t tmp = src[sidx].u;
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_IMAGE: {
+ int64_t tmp = src[sidx].i;
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_BOOL: {
+ int64_t tmp = src[sidx].i ? 1.0f : 0.0f;
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_UINT64: {
+ uint64_t u64;
+ memcpy(&u64, &src[sidx].u, sizeof(u64));
+ int64_t tmp = MIN2(u64, INT_MAX);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_FLOAT: {
+ int64_t tmp = (int64_t) roundf(src[sidx].f);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_DOUBLE: {
+ double d;
+ memcpy(&d, &src[sidx].f, sizeof(d));
+ int64_t tmp = (int64_t) round(d);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+
case GLSL_TYPE_UINT64:
switch (uni->type->base_type) {
- case GLSL_TYPE_UINT:
- *(int64_t *)&dst[didx].u = (int64_t) src[sidx].u;
+ case GLSL_TYPE_UINT: {
+ uint64_t tmp = src[sidx].u;
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
break;
+ }
case GLSL_TYPE_INT:
case GLSL_TYPE_SAMPLER:
- case GLSL_TYPE_IMAGE:
- *(int64_t *)&dst[didx].u = (int64_t) src[sidx].i;
+ case GLSL_TYPE_IMAGE: {
+ int64_t tmp = MAX2(src[sidx].i, 0);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
break;
- case GLSL_TYPE_BOOL:
- *(int64_t *)&dst[didx].u = src[sidx].i ? 1.0f : 0.0f;
+ }
+ case GLSL_TYPE_BOOL: {
+ int64_t tmp = src[sidx].i ? 1.0f : 0.0f;
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
break;
- case GLSL_TYPE_FLOAT:
- *(int64_t *)&dst[didx].u = (int64_t) src[sidx].f;
+ }
+ case GLSL_TYPE_INT64: {
+ uint64_t i64;
+ memcpy(&i64, &src[sidx].i, sizeof(i64));
+ uint64_t tmp = MAX2(i64, 0);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
break;
+ }
+ case GLSL_TYPE_FLOAT: {
+ uint64_t tmp = src[sidx].f < 0.0f ?
+ 0ull : (uint64_t) roundf(src[sidx].f);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
+ case GLSL_TYPE_DOUBLE: {
+ double d;
+ memcpy(&d, &src[sidx].f, sizeof(d));
+ uint64_t tmp = (d < 0.0) ? 0ull : (uint64_t) round(d);
+ memcpy(&dst[didx].u, &tmp, sizeof(tmp));
+ break;
+ }
default:
assert(!"Should not get here.");
break;
}
break;
- default:
- assert(!"Should not get here.");
- break;
- }
- }
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
}
}
}
case GLSL_TYPE_INT:
printf("%d ", v[i].i);
break;
- case GLSL_TYPE_UINT64:
- printf("%lu ", *(uint64_t* )&v[i * 2].u);
+ case GLSL_TYPE_UINT64: {
+ uint64_t tmp;
+ memcpy(&tmp, &v[i * 2].u, sizeof(tmp));
+ printf("%" PRIu64 " ", tmp);
break;
- case GLSL_TYPE_INT64:
- printf("%ld ", *(int64_t* )&v[i * 2].u);
+ }
+ case GLSL_TYPE_INT64: {
+ int64_t tmp;
+ memcpy(&tmp, &v[i * 2].u, sizeof(tmp));
+ printf("%" PRId64 " ", tmp);
break;
+ }
case GLSL_TYPE_FLOAT:
printf("%g ", v[i].f);
break;
printf("Program %d %s shader parameters:\n",
shProg->Name, _mesa_shader_stage_to_string(i));
for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) {
- printf("%s: %p %f %f %f %f\n",
+ unsigned pvo = prog->Parameters->ParameterValueOffset[j];
+ printf("%s: %u %p %f %f %f %f\n",
prog->Parameters->Parameters[j].Name,
- prog->Parameters->ParameterValues[j],
- prog->Parameters->ParameterValues[j][0].f,
- prog->Parameters->ParameterValues[j][1].f,
- prog->Parameters->ParameterValues[j][2].f,
- prog->Parameters->ParameterValues[j][3].f);
+ pvo,
+ prog->Parameters->ParameterValues + pvo,
+ prog->Parameters->ParameterValues[pvo].f,
+ prog->Parameters->ParameterValues[pvo + 1].f,
+ prog->Parameters->ParameterValues[pvo + 2].f,
+ prog->Parameters->ParameterValues[pvo + 3].f);
}
}
fflush(stdout);
{
unsigned i;
- /* vector_elements and matrix_columns can be 0 for samplers.
- */
- const unsigned components = MAX2(1, uni->type->vector_elements);
- const unsigned vectors = MAX2(1, uni->type->matrix_columns);
+ const unsigned components = uni->type->vector_elements;
+ const unsigned vectors = uni->type->matrix_columns;
const int dmul = uni->type->is_64bit() ? 2 : 1;
/* Store the data in the driver's requested type in the driver's storage
}
-/**
- * Called via glUniform*() functions.
- */
-extern "C" void
-_mesa_uniform(GLint location, GLsizei count, const GLvoid *values,
- struct gl_context *ctx, struct gl_shader_program *shProg,
- enum glsl_base_type basicType, unsigned src_components)
+static struct gl_uniform_storage *
+validate_uniform(GLint location, GLsizei count, const GLvoid *values,
+ unsigned *offset, struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ enum glsl_base_type basicType, unsigned src_components)
{
- unsigned offset;
- int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1;
-
struct gl_uniform_storage *const uni =
- validate_uniform_parameters(ctx, shProg, location, count,
- &offset, "glUniform");
+ validate_uniform_parameters(location, count, offset,
+ ctx, shProg, "glUniform");
if (uni == NULL)
- return;
+ return NULL;
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;
+ return NULL;
}
- /* Verify that the types are compatible.
- */
- const unsigned components = uni->type->is_sampler()
- ? 1 : uni->type->vector_elements;
+ /* Verify that the types are compatible. */
+ const unsigned components = uni->type->vector_elements;
if (components != src_components) {
/* glUniformN() must match float/vecN type */
"glUniform%u(\"%s\"@%u has %u components, not %u)",
src_components, uni->name, location,
components, src_components);
- return;
+ return NULL;
}
bool match;
src_components, uni->name, location,
glsl_type_name(uni->type->base_type),
glsl_type_name(basicType));
- return;
+ return NULL;
}
if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
log_uniform(values, basicType, components, 1, count,
- false, shProg, location, uni);
+ false, shProg, location, uni);
}
/* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
*/
if (uni->type->is_sampler()) {
for (int i = 0; i < count; i++) {
- const unsigned texUnit = ((unsigned *) values)[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;
+ "uniform %d)", location);
+ return NULL;
}
}
/* We need to reset the validate flag on changes to samplers in case
_mesa_error(ctx, GL_INVALID_VALUE,
"glUniform1i(invalid image unit index for uniform %d)",
location);
- return;
+ return NULL;
}
}
}
+ return uni;
+}
+
+void
+_mesa_flush_vertices_for_uniforms(struct gl_context *ctx,
+ const struct gl_uniform_storage *uni)
+{
+ /* Opaque uniforms have no storage unless they are bindless */
+ if (!uni->is_bindless && uni->type->contains_opaque()) {
+ FLUSH_VERTICES(ctx, 0);
+ return;
+ }
+
+ uint64_t new_driver_state = 0;
+ unsigned mask = uni->active_shader_mask;
+
+ while (mask) {
+ unsigned index = u_bit_scan(&mask);
+
+ assert(index < MESA_SHADER_STAGES);
+ new_driver_state |= ctx->DriverFlags.NewShaderConstants[index];
+ }
+
+ FLUSH_VERTICES(ctx, new_driver_state ? 0 : _NEW_PROGRAM_CONSTANTS);
+ ctx->NewDriverState |= new_driver_state;
+}
+
+static void
+copy_uniforms_to_storage(gl_constant_value *storage,
+ struct gl_uniform_storage *uni,
+ struct gl_context *ctx, GLsizei count,
+ const GLvoid *values, const int size_mul,
+ const unsigned offset, const unsigned components,
+ enum glsl_base_type basicType)
+{
+ if (!uni->type->is_boolean() && !uni->is_bindless) {
+ memcpy(storage, values,
+ sizeof(storage[0]) * components * count * size_mul);
+ } else if (uni->is_bindless) {
+ const union gl_constant_value *src =
+ (const union gl_constant_value *) values;
+ GLuint64 *dst = (GLuint64 *)&storage->i;
+ const unsigned elems = components * count;
+
+ for (unsigned i = 0; i < elems; i++) {
+ dst[i] = src[i].i;
+ }
+ } else {
+ const union gl_constant_value *src =
+ (const union gl_constant_value *) values;
+ union gl_constant_value *dst = storage;
+ 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;
+ }
+ }
+ }
+}
+
+
+/**
+ * Called via glUniform*() functions.
+ */
+extern "C" void
+_mesa_uniform(GLint location, GLsizei count, const GLvoid *values,
+ struct gl_context *ctx, struct gl_shader_program *shProg,
+ enum glsl_base_type basicType, unsigned src_components)
+{
+ unsigned offset;
+ int size_mul = glsl_base_type_is_64bit(basicType) ? 2 : 1;
+
+ struct gl_uniform_storage *uni;
+ if (_mesa_is_no_error_enabled(ctx)) {
+ /* From Seciton 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec:
+ *
+ * "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.
+ */
+ if (location == -1)
+ return;
+
+ uni = shProg->UniformRemapTable[location];
+
+ /* The array index specified by the uniform location is just the
+ * uniform location minus the base location of of the uniform.
+ */
+ assert(uni->array_elements > 0 || location == (int)uni->remap_location);
+ offset = location - uni->remap_location;
+ } else {
+ uni = validate_uniform(location, count, values, &offset, ctx, shProg,
+ basicType, src_components);
+ if (!uni)
+ return;
+ }
+
+ const unsigned components = uni->type->vector_elements;
+
/* 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
count = MIN2(count, (int) (uni->array_elements - offset));
}
- FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+ /* We check samplers for changes and flush if needed in the sampler
+ * handling code further down, so just skip them here.
+ */
+ if (!uni->type->is_sampler()) {
+ _mesa_flush_vertices_for_uniforms(ctx, uni);
+ }
/* 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);
+ gl_constant_value *storage;
+ if (ctx->Const.PackedDriverUniformStorage &&
+ (uni->is_bindless || !uni->type->contains_opaque())) {
+ for (unsigned s = 0; s < uni->num_driver_storage; s++) {
+ storage = (gl_constant_value *)
+ uni->driver_storage[s].data + (size_mul * offset * components);
+
+ copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul,
+ offset, components, basicType);
+ }
} 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;
+ storage = &uni->storage[size_mul * components * offset];
+ copy_uniforms_to_storage(storage, uni, ctx, count, values, size_mul,
+ offset, components, basicType);
- 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;
- }
- }
+ _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
}
- _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;
+
+ shProg->SamplersValidated = GL_TRUE;
+
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
- struct gl_linked_shader *const sh = shProg->_LinkedShaders[i];
+ struct gl_linked_shader *const sh = shProg->_LinkedShaders[i];
- /* If the shader stage doesn't use the sampler uniform, skip this. */
- if (!uni->opaque[i].active)
- continue;
+ /* If the shader stage doesn't use the sampler uniform, skip this. */
+ if (!uni->opaque[i].active)
+ continue;
bool changed = false;
for (int j = 0; j < count; j++) {
unsigned unit = uni->opaque[i].index + offset + j;
- if (sh->Program->SamplerUnits[unit] != ((unsigned *) values)[j]) {
- sh->Program->SamplerUnits[unit] = ((unsigned *) values)[j];
- changed = true;
+ unsigned value = ((unsigned *)values)[j];
+
+ if (uni->is_bindless) {
+ struct gl_bindless_sampler *sampler =
+ &sh->Program->sh.BindlessSamplers[unit];
+
+ /* Mark this bindless sampler as bound to a texture unit.
+ */
+ if (sampler->unit != value || !sampler->bound) {
+ sampler->unit = value;
+ changed = true;
+ }
+ sampler->bound = true;
+ sh->Program->sh.HasBoundBindlessSampler = true;
+ } else {
+ if (sh->Program->SamplerUnits[unit] != value) {
+ sh->Program->SamplerUnits[unit] = value;
+ changed = true;
+ }
}
}
- if (changed) {
- if (!flushed) {
- FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
- flushed = true;
- }
+ if (changed) {
+ if (!flushed) {
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT | _NEW_PROGRAM);
+ flushed = true;
+ }
struct gl_program *const prog = sh->Program;
- _mesa_update_shader_textures_used(shProg, prog);
+ _mesa_update_shader_textures_used(shProg, prog);
if (ctx->Driver.SamplerUniformChange)
- ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
- }
+ ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
+ }
}
}
*/
if (uni->type->is_image()) {
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
- if (uni->opaque[i].active) {
- struct gl_linked_shader *sh = shProg->_LinkedShaders[i];
+ struct gl_linked_shader *sh = shProg->_LinkedShaders[i];
+
+ /* If the shader stage doesn't use the image uniform, skip this. */
+ if (!uni->opaque[i].active)
+ continue;
- for (int j = 0; j < count; j++)
- sh->Program->sh.ImageUnits[uni->opaque[i].index + offset + j] =
- ((GLint *) values)[j];
+ for (int j = 0; j < count; j++) {
+ unsigned unit = uni->opaque[i].index + offset + j;
+ unsigned value = ((unsigned *)values)[j];
+
+ if (uni->is_bindless) {
+ struct gl_bindless_image *image =
+ &sh->Program->sh.BindlessImages[unit];
+
+ /* Mark this bindless image as bound to an image unit.
+ */
+ image->unit = value;
+ image->bound = true;
+ sh->Program->sh.HasBoundBindlessImage = true;
+ } else {
+ sh->Program->sh.ImageUnits[unit] = value;
+ }
}
}
}
}
+
+static void
+copy_uniform_matrix_to_storage(gl_constant_value *storage,
+ GLsizei count, const void *values,
+ const unsigned size_mul, const unsigned offset,
+ const unsigned components,
+ const unsigned vectors, bool transpose,
+ unsigned cols, unsigned rows,
+ enum glsl_base_type basicType)
+{
+ const unsigned elements = components * vectors;
+
+ if (!transpose) {
+ memcpy(storage, values,
+ sizeof(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 = &storage->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 *)&storage->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;
+ }
+ }
+}
+
+
/**
* Called by glUniformMatrix*() functions.
* Note: cols=2, rows=4 ==> array[2] of vec4
{
unsigned offset;
struct gl_uniform_storage *const uni =
- validate_uniform_parameters(ctx, shProg, location, count,
- &offset, "glUniformMatrix");
+ validate_uniform_parameters(location, count, &offset,
+ ctx, shProg, "glUniformMatrix");
if (uni == NULL)
return;
count = MIN2(count, (int) (uni->array_elements - offset));
}
- FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+ _mesa_flush_vertices_for_uniforms(ctx, uni);
/* Store the data in the "actual type" backing storage for the uniform.
*/
+ gl_constant_value *storage;
const unsigned elements = components * vectors;
+ if (ctx->Const.PackedDriverUniformStorage) {
+ for (unsigned s = 0; s < uni->num_driver_storage; s++) {
+ storage = (gl_constant_value *)
+ uni->driver_storage[s].data + (size_mul * offset * elements);
+
+ copy_uniform_matrix_to_storage(storage, count, values, size_mul,
+ offset, components, vectors,
+ transpose, cols, rows, basicType);
+ }
+ } else {
+ storage = &uni->storage[size_mul * elements * offset];
+ copy_uniform_matrix_to_storage(storage, count, values, size_mul, offset,
+ components, vectors, transpose, cols,
+ rows, basicType);
- if (!transpose) {
- memcpy(&uni->storage[size_mul * elements * offset], values,
- sizeof(uni->storage[0]) * elements * count * size_mul);
- } else if (basicType == GLSL_TYPE_FLOAT) {
- /* Copy and transpose the matrix.
+ _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
+ }
+}
+
+static void
+update_bound_bindless_sampler_flag(struct gl_program *prog)
+{
+ unsigned i;
+
+ if (likely(!prog->sh.HasBoundBindlessSampler))
+ return;
+
+ for (i = 0; i < prog->sh.NumBindlessSamplers; i++) {
+ struct gl_bindless_sampler *sampler = &prog->sh.BindlessSamplers[i];
+
+ if (sampler->bound)
+ return;
+ }
+ prog->sh.HasBoundBindlessSampler = false;
+}
+
+static void
+update_bound_bindless_image_flag(struct gl_program *prog)
+{
+ unsigned i;
+
+ if (likely(!prog->sh.HasBoundBindlessImage))
+ return;
+
+ for (i = 0; i < prog->sh.NumBindlessImages; i++) {
+ struct gl_bindless_image *image = &prog->sh.BindlessImages[i];
+
+ if (image->bound)
+ return;
+ }
+ prog->sh.HasBoundBindlessImage = false;
+}
+
+/**
+ * Called via glUniformHandleui64*ARB() functions.
+ */
+extern "C" void
+_mesa_uniform_handle(GLint location, GLsizei count, const GLvoid *values,
+ struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+ unsigned offset;
+ struct gl_uniform_storage *uni;
+
+ if (_mesa_is_no_error_enabled(ctx)) {
+ /* From Section 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 spec:
+ *
+ * "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.
*/
- const float *src = (const float *)values;
- float *dst = &uni->storage[elements * offset].f;
+ if (location == -1)
+ return;
- 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)];
- }
- }
+ uni = shProg->UniformRemapTable[location];
- dst += elements;
- src += elements;
+ /* The array index specified by the uniform location is just the
+ * uniform location minus the base location of of the uniform.
+ */
+ assert(uni->array_elements > 0 || location == (int)uni->remap_location);
+ offset = location - uni->remap_location;
+ } else {
+ uni = validate_uniform_parameters(location, count, &offset,
+ ctx, shProg, "glUniformHandleui64*ARB");
+ if (!uni)
+ return;
+
+ if (!uni->is_bindless) {
+ /* From section "Errors" of the ARB_bindless_texture spec:
+ *
+ * "The error INVALID_OPERATION is generated by
+ * UniformHandleui64{v}ARB if the sampler or image uniform being
+ * updated has the "bound_sampler" or "bound_image" layout qualifier."
+ *
+ * From section 4.4.6 of the ARB_bindless_texture spec:
+ *
+ * "In the absence of these qualifiers, sampler and image uniforms are
+ * considered "bound". Additionally, if GL_ARB_bindless_texture is
+ * not enabled, these uniforms are considered "bound"."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniformHandleui64*ARB(non-bindless sampler/image uniform)");
+ return;
+ }
+ }
+
+ const unsigned components = uni->type->vector_elements;
+ const int size_mul = 2;
+
+ if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
+ log_uniform(values, GLSL_TYPE_UINT64, components, 1, count,
+ false, 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));
+ }
+
+ _mesa_flush_vertices_for_uniforms(ctx, uni);
+
+ /* Store the data in the "actual type" backing storage for the uniform.
+ */
+ gl_constant_value *storage;
+ if (ctx->Const.PackedDriverUniformStorage) {
+ for (unsigned s = 0; s < uni->num_driver_storage; s++) {
+ storage = (gl_constant_value *)
+ uni->driver_storage[s].data + (size_mul * offset * components);
+ memcpy(storage, values,
+ sizeof(uni->storage[0]) * components * count * size_mul);
}
} else {
- assert(basicType == GLSL_TYPE_DOUBLE);
- const double *src = (const double *)values;
- double *dst = (double *)&uni->storage[elements * offset].f;
+ memcpy(&uni->storage[size_mul * components * offset], values,
+ sizeof(uni->storage[0]) * components * count * size_mul);
- 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)];
- }
- }
+ _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
+ }
- dst += elements;
- src += elements;
+ if (uni->type->is_sampler()) {
+ /* Mark this bindless sampler as not bound to a texture unit because
+ * it refers to a texture handle.
+ */
+ for (int i = 0; i < MESA_SHADER_STAGES; i++) {
+ struct gl_linked_shader *const sh = shProg->_LinkedShaders[i];
+
+ /* If the shader stage doesn't use the sampler uniform, skip this. */
+ if (!uni->opaque[i].active)
+ continue;
+
+ for (int j = 0; j < count; j++) {
+ unsigned unit = uni->opaque[i].index + offset + j;
+ struct gl_bindless_sampler *sampler =
+ &sh->Program->sh.BindlessSamplers[unit];
+
+ sampler->bound = false;
+ }
+
+ update_bound_bindless_sampler_flag(sh->Program);
}
}
- _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
-}
+ if (uni->type->is_image()) {
+ /* Mark this bindless image as not bound to an image unit because it
+ * refers to a texture handle.
+ */
+ for (int i = 0; i < MESA_SHADER_STAGES; i++) {
+ struct gl_linked_shader *sh = shProg->_LinkedShaders[i];
+
+ /* If the shader stage doesn't use the sampler uniform, skip this. */
+ if (!uni->opaque[i].active)
+ continue;
+
+ for (int j = 0; j < count; j++) {
+ unsigned unit = uni->opaque[i].index + offset + j;
+ struct gl_bindless_image *image =
+ &sh->Program->sh.BindlessImages[unit];
+ image->bound = false;
+ }
+
+ update_bound_bindless_image_flag(sh->Program);
+ }
+ }
+}
extern "C" bool
_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
return true;
if (!shProg->SamplersValidated) {
- _mesa_snprintf(errMsg, errMsgLength,
+ snprintf(errMsg, errMsgLength,
"active samplers with a different type "
"refer to the same texture image unit");
return false;