[Mesa-dev] [PATCH v2 09/24] mesa: implementation of glGetProgramResourceiv
Tapani Pälli
tapani.palli at intel.com
Tue Apr 14 01:20:02 PDT 2015
On 04/13/2015 05:14 PM, Martin Peres wrote:
> 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?
As discussed IRL, this is what happens here. There can be > 1 props
written. I'll squash this a bit with just returning when error happened
to get rid of if/else.
>> + } 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