[Mesa-dev] [PATCH v2 09/24] mesa: implementation of glGetProgramResourceiv
Martin Peres
martin.peres at linux.intel.com
Mon Apr 13 07:14:23 PDT 2015
On 01/04/15 15:14, Tapani Pälli wrote:
> Patch adds required helper functions to shaderapi.h and
> the actual implementation.
>
> The property query functionality can be tested with tests for
> following functions that are refactored by later patches:
>
> GetActiveAtomicCounterBufferiv
> GetActiveUniformBlockiv
> GetActiveUniformsiv
>
> v2: code cleanup (Ilia Mirkin)
> add bufSize < 0 check and error out
> fix is_resource_referenced to return bool
> check for propCount and bufSize, fixes in buffer_prop
>
> Signed-off-by: Tapani Pälli <tapani.palli at intel.com>
> ---
> src/mesa/main/program_resource.c | 22 ++++
> src/mesa/main/shader_query.cpp | 266 +++++++++++++++++++++++++++++++++++++++
> src/mesa/main/shaderapi.h | 12 ++
> 3 files changed, 300 insertions(+)
>
> diff --git a/src/mesa/main/program_resource.c b/src/mesa/main/program_resource.c
> index e381035..b095227 100644
> --- a/src/mesa/main/program_resource.c
> +++ b/src/mesa/main/program_resource.c
> @@ -276,6 +276,28 @@ _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
> const GLenum *props, GLsizei bufSize,
> GLsizei *length, GLint *params)
> {
> + GET_CURRENT_CONTEXT(ctx);
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
> +
> + if (!shProg || !params)
> + return;
> +
> + /* The error INVALID_VALUE is generated if <propCount> is zero.
> + * Note that we check < 0 here because it makes sense to bail early.
> + */
> + if (propCount <= 0) {
> + _mesa_error(ctx, GL_INVALID_VALUE,
> + "glGetProgramResourceiv(propCount <= 0)");
> + return;
> + }
> +
> + /* No need to write any properties, user requested none. */
> + if (bufSize == 0)
> + return;
> +
> + _mesa_get_program_resourceiv(shProg, programInterface, index,
> + propCount, props, bufSize, length, params);
> }
>
> /**
> diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp
> index 8b2281d..ef5e6a2 100644
> --- a/src/mesa/main/shader_query.cpp
> +++ b/src/mesa/main/shader_query.cpp
> @@ -839,3 +839,269 @@ _mesa_program_resource_location_index(struct gl_shader_program *shProg,
>
> return RESOURCE_VAR(res)->data.index;
> }
> +
> +static uint8_t
> +stage_from_enum(GLenum ref)
> +{
> + switch (ref) {
> + case GL_REFERENCED_BY_VERTEX_SHADER:
> + return MESA_SHADER_VERTEX;
> + case GL_REFERENCED_BY_GEOMETRY_SHADER:
> + return MESA_SHADER_GEOMETRY;
> + case GL_REFERENCED_BY_FRAGMENT_SHADER:
> + return MESA_SHADER_FRAGMENT;
> + default:
> + assert(!"shader stage not supported");
> + return MESA_SHADER_STAGES;
> + }
> +}
> +
> +/**
> + * Check if resource is referenced by given 'referenced by' stage enum.
> + * ATC and UBO resources hold stage references of their own.
> + */
> +static bool
> +is_resource_referenced(struct gl_shader_program *shProg,
> + struct gl_program_resource *res,
> + GLuint index, uint8_t stage)
> +{
> + if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
> + return RESOURCE_ATC(res)->StageReferences[stage];
> +
> + if (res->Type == GL_UNIFORM_BLOCK)
> + return shProg->UniformBlockStageIndex[stage][index] != -1;
> +
> + return res->StageReferences & (1 << stage);
> +}
> +
> +static unsigned
> +get_buffer_property(struct gl_shader_program *shProg,
> + struct gl_program_resource *res, const GLenum prop,
> + GLint *val, const char *caller)
> +{
> + GET_CURRENT_CONTEXT(ctx);
Same comment as the previous patch.
> + if (res->Type != GL_UNIFORM_BLOCK &&
> + res->Type != GL_ATOMIC_COUNTER_BUFFER)
> + goto invalid_operation;
> +
> + if (res->Type == GL_UNIFORM_BLOCK) {
> + switch (prop) {
> + case GL_BUFFER_BINDING:
> + *val = RESOURCE_UBO(res)->Binding;
> + return 1;
> + case GL_BUFFER_DATA_SIZE:
> + *val = RESOURCE_UBO(res)->UniformBufferSize;
> + return 1;
> + case GL_NUM_ACTIVE_VARIABLES:
> + *val = RESOURCE_UBO(res)->NumUniforms;
> + return 1;
> + case GL_ACTIVE_VARIABLES:
> + for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
> + const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
> + struct gl_program_resource *uni =
> + _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
> + *val++ =
> + _mesa_program_resource_index(shProg, uni);
> + }
> + return RESOURCE_UBO(res)->NumUniforms;
> + }
> + } else if (res->Type == GL_ATOMIC_COUNTER_BUFFER) {
> + switch (prop) {
> + case GL_BUFFER_BINDING:
> + *val = RESOURCE_ATC(res)->Binding;
> + return 1;
> + case GL_BUFFER_DATA_SIZE:
> + *val = RESOURCE_ATC(res)->MinimumSize;
> + return 1;
> + case GL_NUM_ACTIVE_VARIABLES:
> + *val = RESOURCE_ATC(res)->NumUniforms;
> + return 1;
> + case GL_ACTIVE_VARIABLES:
> + for (unsigned i = 0; i < RESOURCE_ATC(res)->NumUniforms; i++)
> + *val++ = RESOURCE_ATC(res)->Uniforms[i];
> + return RESOURCE_ATC(res)->NumUniforms;
> + }
> + }
> + assert(!"support for property type not implemented");
> +
> +invalid_operation:
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
> + _mesa_lookup_enum_by_nr(res->Type),
> + _mesa_lookup_enum_by_nr(prop));
> +
> + return 0;
> +}
> +
> +unsigned
> +_mesa_program_resource_prop(struct gl_shader_program *shProg,
> + struct gl_program_resource *res, GLuint index,
> + const GLenum prop, GLint *val, const char *caller)
> +{
> + GET_CURRENT_CONTEXT(ctx);
> +
> +#define VALIDATE_TYPE(type)\
> + if (res->Type != type)\
> + goto invalid_operation;
> +
> + switch(prop) {
> + case GL_NAME_LENGTH:
> + if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
> + goto invalid_operation;
> + /* Base name +3 if array '[0]' + terminator. */
> + *val = strlen(_mesa_program_resource_name(res)) +
> + (_mesa_program_resource_array_size(res) > 0 ? 3 : 0) + 1;
> + return 1;
> + case GL_TYPE:
> + switch (res->Type) {
> + case GL_UNIFORM:
> + *val = RESOURCE_UNI(res)->type->gl_type;
> + return 1;
> + case GL_PROGRAM_INPUT:
> + case GL_PROGRAM_OUTPUT:
> + *val = RESOURCE_VAR(res)->type->gl_type;
> + return 1;
> + case GL_TRANSFORM_FEEDBACK_VARYING:
> + *val = RESOURCE_XFB(res)->Type;
> + return 1;
> + default:
> + goto invalid_operation;
> + }
> + case GL_ARRAY_SIZE:
> + switch (res->Type) {
> + case GL_UNIFORM:
> + *val = MAX2(RESOURCE_UNI(res)->array_elements, 1);
> + return 1;
> + case GL_PROGRAM_INPUT:
> + case GL_PROGRAM_OUTPUT:
> + *val = MAX2(RESOURCE_VAR(res)->type->length, 1);
> + return 1;
> + case GL_TRANSFORM_FEEDBACK_VARYING:
> + *val = MAX2(RESOURCE_XFB(res)->Size, 1);
> + return 1;
> + default:
> + goto invalid_operation;
> + }
> + case GL_OFFSET:
> + VALIDATE_TYPE(GL_UNIFORM);
> + *val = RESOURCE_UNI(res)->offset;
> + return 1;
> + case GL_BLOCK_INDEX:
> + VALIDATE_TYPE(GL_UNIFORM);
> + *val = RESOURCE_UNI(res)->block_index;
> + return 1;
> + case GL_ARRAY_STRIDE:
> + VALIDATE_TYPE(GL_UNIFORM);
> + *val = RESOURCE_UNI(res)->array_stride;
> + return 1;
> + case GL_MATRIX_STRIDE:
> + VALIDATE_TYPE(GL_UNIFORM);
> + *val = RESOURCE_UNI(res)->matrix_stride;
> + return 1;
> + case GL_IS_ROW_MAJOR:
> + VALIDATE_TYPE(GL_UNIFORM);
> + *val = RESOURCE_UNI(res)->row_major;
> + return 1;
> + case GL_ATOMIC_COUNTER_BUFFER_INDEX:
> + VALIDATE_TYPE(GL_UNIFORM);
> + *val = RESOURCE_UNI(res)->atomic_buffer_index;
> + return 1;
> + case GL_BUFFER_BINDING:
> + case GL_BUFFER_DATA_SIZE:
> + case GL_NUM_ACTIVE_VARIABLES:
> + case GL_ACTIVE_VARIABLES:
> + return get_buffer_property(shProg, res, prop, val, caller);
> + case GL_REFERENCED_BY_VERTEX_SHADER:
> + case GL_REFERENCED_BY_GEOMETRY_SHADER:
> + case GL_REFERENCED_BY_FRAGMENT_SHADER:
> + switch (res->Type) {
> + case GL_UNIFORM:
> + case GL_PROGRAM_INPUT:
> + case GL_PROGRAM_OUTPUT:
> + case GL_UNIFORM_BLOCK:
> + case GL_ATOMIC_COUNTER_BUFFER:
> + *val = is_resource_referenced(shProg, res, index,
> + stage_from_enum(prop));
> + return 1;
> + default:
> + goto invalid_operation;
> + }
> + case GL_LOCATION:
> + switch (res->Type) {
> + case GL_UNIFORM:
> + case GL_PROGRAM_INPUT:
> + case GL_PROGRAM_OUTPUT:
> + *val = program_resource_location(shProg, res,
> + _mesa_program_resource_name(res));
> + return 1;
> + default:
> + goto invalid_operation;
> + }
> + case GL_LOCATION_INDEX:
> + if (res->Type != GL_PROGRAM_OUTPUT)
> + goto invalid_operation;
> + *val = RESOURCE_VAR(res)->data.index;
> + return 1;
> +
> + /* GL_ARB_tessellation_shader */
> + case GL_IS_PER_PATCH:
> + case GL_REFERENCED_BY_TESS_CONTROL_SHADER:
> + case GL_REFERENCED_BY_TESS_EVALUATION_SHADER:
> + /* GL_ARB_compute_shader */
> + case GL_REFERENCED_BY_COMPUTE_SHADER:
> + default:
> + _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller,
> + _mesa_lookup_enum_by_nr(res->Type),
> + _mesa_lookup_enum_by_nr(prop));
> + return 0;
> + }
> +
> +#undef VALIDATE_TYPE
> +
> +invalid_operation:
> + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
> + _mesa_lookup_enum_by_nr(res->Type),
> + _mesa_lookup_enum_by_nr(prop));
> + return 0;
> +}
> +
> +extern void
> +_mesa_get_program_resourceiv(struct gl_shader_program *shProg,
> + GLenum interface, GLuint index, GLsizei propCount,
> + const GLenum *props, GLsizei bufSize,
> + GLsizei *length, GLint *params)
> +{
> + GET_CURRENT_CONTEXT(ctx);
> + GLint *val = (GLint *) params;
> + const GLenum *prop = props;
> + GLsizei amount = 0;
> +
> + struct gl_program_resource *res =
> + _mesa_program_resource_find_index(shProg, interface, index);
> +
> + /* No such resource found or bufSize negative. */
> + if (!res || bufSize < 0) {
> + _mesa_error(ctx, GL_INVALID_VALUE,
> + "glGetProgramResourceiv(%s index %d bufSize %d)",
> + _mesa_lookup_enum_by_nr(interface), index, bufSize);
> + return;
> + }
> +
> + /* Write propCount values until error occurs or bufSize reached. */
> + for (int i = 0; i < propCount && i < bufSize; i++, val++, prop++) {
> + int props_written =
> + _mesa_program_resource_prop(shProg, res, index, *prop, val,
> + "glGetProgramResourceiv");
> + if (props_written) {
> + amount += props_written;
Not sure this test matters since you should abort the call anyway. How
about just returning?
> + } else {
> + /* Error happened. */
> + return;
> + }
> + }
> +
> + /* If <length> is not NULL, the actual number of integer values
> + * written to <params> will be written to <length>.
> + */
> + if (length)
> + *length = amount;
> +}
> diff --git a/src/mesa/main/shaderapi.h b/src/mesa/main/shaderapi.h
> index 5046018..0cd2fad 100644
> --- a/src/mesa/main/shaderapi.h
> +++ b/src/mesa/main/shaderapi.h
> @@ -252,6 +252,18 @@ extern GLint
> _mesa_program_resource_location_index(struct gl_shader_program *shProg,
> GLenum interface, const char *name);
>
> +extern unsigned
> +_mesa_program_resource_prop(struct gl_shader_program *shProg,
> + struct gl_program_resource *res, GLuint index,
> + const GLenum prop, GLint *val, const char *caller);
> +
> +extern void
> +_mesa_get_program_resourceiv(struct gl_shader_program *shProg,
> + GLenum interface, GLuint index,
> + GLsizei propCount, const GLenum *props,
> + GLsizei bufSize, GLsizei *length,
> + GLint *params);
> +
> #ifdef __cplusplus
> }
> #endif
Other than that:
Reviewed-by: Martin Peres <martin.peres at linux.intel.com>
More information about the mesa-dev
mailing list