{
unsigned elements = uni->type->components();
- /* XXX: Remove the sampler/image check workarounds when bindless is fully
- * implemented.
- */
- const int dmul =
- (uni->type->is_64bit() && !uni->type->is_sampler() && !uni->type->is_image()) ? 2 : 1;
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.
*/
if (returnType == uni->type->base_type ||
((returnType == GLSL_TYPE_INT || returnType == GLSL_TYPE_UINT) &&
- (uni->type->is_sampler() || uni->type->is_image()))) {
+ (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 =
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;
+}
/**
* Called via glUniform*() functions.
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()) {
+ if (!uni->type->is_boolean() && !uni->is_bindless) {
memcpy(&uni->storage[size_mul * components * offset], values,
sizeof(uni->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 *)&uni->storage[components * offset].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;
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 (!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;
+ }
+ }
}
ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;
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.
*/
_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.
*/
struct gl_context *ctx, struct gl_shader_program *shProg)
{
unsigned offset;
- struct gl_uniform_storage *const uni =
- validate_uniform_parameters(location, count, &offset,
- ctx, shProg, "glUniformHandleui64*ARB");
- if (uni == NULL)
- return;
+ struct gl_uniform_storage *uni;
- 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:
+ if (_mesa_is_no_error_enabled(ctx)) {
+ /* From Section 7.6 (UNIFORM VARIABLES) of the OpenGL 4.5 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"."
+ * "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.
*/
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniformHandleui64*ARB(non-bindless sampler/image uniform)");
- return;
+ 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_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;
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.
*/
sizeof(uni->storage[0]) * components * count * size_mul);
_mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
+
+ 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);
+ }
+ }
+
+ 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