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

Signed-off-by: Tapani Pälli <tapani.pa...@intel.com>
---
 src/mesa/main/program_resource.c |  23 ++++
 src/mesa/main/shader_query.cpp   | 258 +++++++++++++++++++++++++++++++++++++++
 src/mesa/main/shaderapi.h        |  12 ++
 3 files changed, 293 insertions(+)

diff --git a/src/mesa/main/program_resource.c b/src/mesa/main/program_resource.c
index ae987de..cdd5690 100644
--- a/src/mesa/main/program_resource.c
+++ b/src/mesa/main/program_resource.c
@@ -241,6 +241,29 @@ _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)
+      return;
+
+   /* The error INVALID_VALUE is generated if <propCount> is zero.
+    * Note that we check < 0 here because it makes sense.
+    */
+   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 d3264db..749cd32 100644
--- a/src/mesa/main/shader_query.cpp
+++ b/src/mesa/main/shader_query.cpp
@@ -825,3 +825,261 @@ _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 GLint
+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 ? 1 : 0;
+
+   return (res->StageReferences & (1 << stage));
+}
+
+static bool
+get_buffer_property(struct gl_shader_program *shProg,
+                    struct gl_program_resource *res, const GLenum prop,
+                    GLint *val)
+{
+   if (res->Type != GL_UNIFORM_BLOCK &&
+       res->Type != GL_ATOMIC_COUNTER_BUFFER)
+      return false;
+
+   switch (prop) {
+   case GL_BUFFER_BINDING:
+      if (res->Type == GL_UNIFORM_BLOCK)
+         *val = RESOURCE_UBO(res)->Binding;
+      else if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
+         *val = RESOURCE_ATC(res)->Binding;
+      return true;
+   case GL_BUFFER_DATA_SIZE:
+      if (res->Type == GL_UNIFORM_BLOCK)
+         *val = RESOURCE_UBO(res)->UniformBufferSize;
+      else if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
+         *val = RESOURCE_ATC(res)->MinimumSize;
+      return true;
+   case GL_NUM_ACTIVE_VARIABLES:
+      if (res->Type == GL_UNIFORM_BLOCK)
+         *val = RESOURCE_UBO(res)->NumUniforms;
+      else if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
+         *val = RESOURCE_ATC(res)->NumUniforms;
+      return true;
+   case GL_ACTIVE_VARIABLES:
+      if (res->Type == GL_ATOMIC_COUNTER_BUFFER) {
+         int amount = RESOURCE_ATC(res)->NumUniforms;
+         for (int i = 0; i < amount; i++)
+            *val++ = RESOURCE_ATC(res)->Uniforms[i];
+         return true;
+      }
+      if (res->Type == GL_UNIFORM_BLOCK) {
+         int amount = RESOURCE_UBO(res)->NumUniforms;
+         for (int i = 0; i < amount; i++) {
+            const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
+            *val = program_resource_location(shProg, res, iname);
+         }
+         return true;
+      }
+   default:
+      assert(!"support for property type not implemented");
+   }
+   return false;
+}
+
+bool
+_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 true;
+   case GL_TYPE:
+      switch (res->Type) {
+      case GL_UNIFORM:
+         *val = RESOURCE_UNI(res)->type->gl_type;
+         return true;
+      case GL_PROGRAM_INPUT:
+      case GL_PROGRAM_OUTPUT:
+         *val = RESOURCE_VAR(res)->type->gl_type;
+         return true;
+      case GL_TRANSFORM_FEEDBACK_VARYING:
+         *val = RESOURCE_XFB(res)->Type;
+         return true;
+      default:
+         goto invalid_operation;
+      }
+   case GL_ARRAY_SIZE:
+      switch (res->Type) {
+      case GL_UNIFORM:
+            *val = MAX2(RESOURCE_UNI(res)->array_elements, 1);
+            return true;
+      case GL_PROGRAM_INPUT:
+      case GL_PROGRAM_OUTPUT:
+         *val = MAX2(RESOURCE_VAR(res)->type->length, 1);
+         return true;
+      case GL_TRANSFORM_FEEDBACK_VARYING:
+         *val = MAX2(RESOURCE_XFB(res)->Size, 1);
+         return true;
+      default:
+         goto invalid_operation;
+      }
+   case GL_OFFSET:
+      VALIDATE_TYPE(GL_UNIFORM);
+      *val = RESOURCE_UNI(res)->offset;
+      return true;
+   case GL_BLOCK_INDEX:
+      VALIDATE_TYPE(GL_UNIFORM);
+      *val = RESOURCE_UNI(res)->block_index;
+      return true;
+   case GL_ARRAY_STRIDE:
+      VALIDATE_TYPE(GL_UNIFORM);
+      *val = RESOURCE_UNI(res)->array_stride;
+      return true;
+   case GL_MATRIX_STRIDE:
+      VALIDATE_TYPE(GL_UNIFORM);
+      *val = RESOURCE_UNI(res)->matrix_stride;
+      return true;
+   case GL_IS_ROW_MAJOR:
+      VALIDATE_TYPE(GL_UNIFORM);
+      *val = RESOURCE_UNI(res)->row_major;
+      return true;
+   case GL_ATOMIC_COUNTER_BUFFER_INDEX:
+      VALIDATE_TYPE(GL_UNIFORM);
+      *val = RESOURCE_UNI(res)->atomic_buffer_index;
+      return true;
+   case GL_BUFFER_BINDING:
+   case GL_BUFFER_DATA_SIZE:
+   case GL_NUM_ACTIVE_VARIABLES:
+   case GL_ACTIVE_VARIABLES:
+      if (!get_buffer_property(shProg, res, prop, val))
+         goto invalid_operation;
+      return true;
+   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 true;
+      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 true;
+      default:
+         goto invalid_operation;
+      }
+   case GL_LOCATION_INDEX:
+      if (res->Type != GL_PROGRAM_OUTPUT)
+         goto invalid_operation;
+      *val = RESOURCE_VAR(res)->data.index;
+      return true;
+
+   /* 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 false;
+   }
+
+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 false;
+}
+
+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. */
+   if (!res) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glGetProgramResourceiv(%s index %d)",
+                  _mesa_lookup_enum_by_nr(interface), index);
+      return;
+   }
+
+   /* Write values until error occurs or bufSize reached. */
+   for (int i = 0; i < bufSize; i++, val++, prop++) {
+      if (_mesa_program_resource_prop(shProg, res, index, *prop, val,
+          "glGetProgramResourceiv")) {
+         amount++;
+      } 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..f1d038e 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 bool
+_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
-- 
2.1.0

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to