X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fmain%2Funiform_query.cpp;h=db2f173dd2f7ab17b0588dde98cbd8d9570f2ad5;hb=bf188f3494b85f550a39dddbf059669c2a9ee324;hp=e6c78bf69c3276f966f1b82b11466da1ecb01ef3;hpb=3d37cf99c80839326baa0f14bf04f9fd88b4c215;p=mesa.git diff --git a/src/mesa/main/uniform_query.cpp b/src/mesa/main/uniform_query.cpp index e6c78bf69c3..db2f173dd2f 100644 --- a/src/mesa/main/uniform_query.cpp +++ b/src/mesa/main/uniform_query.cpp @@ -26,8 +26,8 @@ #include #include /* for PRIx64 macro */ +#include -#include "main/core.h" #include "main/context.h" #include "main/shaderapi.h" #include "main/shaderobj.h" @@ -322,18 +322,28 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, { 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. */ - 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 || @@ -354,7 +364,8 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, */ 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 = @@ -718,13 +729,15 @@ log_program_parameters(const struct gl_shader_program *shProg) 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); @@ -998,6 +1011,66 @@ validate_uniform(GLint location, GLsizei count, const GLvoid *values, 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. @@ -1052,30 +1125,33 @@ _mesa_uniform(GLint location, GLsizei count, const GLvoid *values, 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. */ @@ -1094,9 +1170,25 @@ _mesa_uniform(GLint location, GLsizei count, const GLvoid *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; + } } } @@ -1125,15 +1217,79 @@ _mesa_uniform(GLint location, GLsizei count, const GLvoid *values, 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; } } + +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 @@ -1229,51 +1385,205 @@ _mesa_uniform_matrix(GLint location, GLsizei count, 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]; + + /* 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; - dst += elements; - src += elements; + 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); + } + + 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; + } - dst += elements; - src += elements; + 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, @@ -1284,7 +1594,7 @@ _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;