st/mesa: use fragment shader to copy stencil buffer
[mesa.git] / src / mesa / main / shader_query.cpp
index a3365107648291bd1b47e2b3d36f11e8da216760..9a16a28d39337e6b4d52b36f905b319c368d0d3a 100644 (file)
@@ -37,7 +37,7 @@
 #include "compiler/glsl/ir.h"
 #include "compiler/glsl/program.h"
 #include "compiler/glsl/string_to_uint_map.h"
-
+#include "util/mesa-sha1.h"
 
 static GLint
 program_resource_location(struct gl_program_resource *res,
@@ -461,7 +461,7 @@ _mesa_program_resource_name(struct gl_program_resource *res)
    case GL_TESS_EVALUATION_SUBROUTINE:
       return RESOURCE_SUB(res)->name;
    default:
-      assert(!"support for resource type not implemented");
+      break;
    }
    return NULL;
 }
@@ -527,6 +527,51 @@ valid_array_index(const GLchar *name, unsigned *array_index)
    return true;
 }
 
+static uint32_t
+compute_resource_key(GLenum programInterface, const char *name)
+{
+   struct mesa_sha1 ctx;
+   unsigned char sha1[20];
+
+   _mesa_sha1_init(&ctx);
+   _mesa_sha1_update(&ctx, &programInterface, sizeof(programInterface));
+   _mesa_sha1_update(&ctx, name, strlen(name));
+   _mesa_sha1_final(&ctx, sha1);
+
+   return _mesa_hash_data(sha1, sizeof(sha1));
+}
+
+static struct gl_program_resource *
+search_resource_hash(struct gl_shader_program *shProg,
+                     GLenum programInterface, const char *name,
+                     unsigned *array_index)
+{
+   const char *base_name_end;
+   long index = parse_program_resource_name(name, &base_name_end);
+   char *name_copy;
+
+   /* If dealing with array, we need to get the basename. */
+   if (index >= 0) {
+      name_copy = (char *) malloc(base_name_end - name + 1);
+      memcpy(name_copy, name, base_name_end - name);
+      name_copy[base_name_end - name] = '\0';
+   } else {
+      name_copy = (char*) name;
+   }
+
+   uint32_t key = compute_resource_key(programInterface, name_copy);
+   struct gl_program_resource *res = (struct gl_program_resource *)
+      _mesa_hash_table_u64_search(shProg->data->ProgramResourceHash, key);
+
+   if (name_copy != name)
+      free(name_copy);
+
+   if (res && array_index)
+      *array_index = index >= 0 ? index : 0;
+
+   return res;
+}
+
 /* Find a program resource with specific name in given interface.
  */
 struct gl_program_resource *
@@ -534,9 +579,20 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg,
                                  GLenum programInterface, const char *name,
                                  unsigned *array_index)
 {
-   struct gl_program_resource *res = shProg->data->ProgramResourceList;
-   for (unsigned i = 0; i < shProg->data->NumProgramResourceList;
-        i++, res++) {
+   struct gl_program_resource *res = NULL;
+
+   if (name == NULL)
+      return NULL;
+
+   /* If we have a name, try the ProgramResourceHash first. */
+   if (shProg->data->ProgramResourceHash)
+      res = search_resource_hash(shProg, programInterface, name, array_index);
+
+   if (res)
+      return res;
+
+   res = shProg->data->ProgramResourceList;
+   for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) {
       if (res->Type != programInterface)
          continue;
 
@@ -638,6 +694,119 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg,
    return NULL;
 }
 
+/* Find an uniform or buffer variable program resource with an specific offset
+ * inside a block with an specific binding.
+ *
+ * Valid interfaces are GL_BUFFER_VARIABLE and GL_UNIFORM.
+ */
+static struct gl_program_resource *
+program_resource_find_binding_offset(struct gl_shader_program *shProg,
+                                     GLenum programInterface,
+                                     const GLuint binding,
+                                     const GLint offset)
+{
+
+   /* First we need to get the BLOCK_INDEX from the BUFFER_BINDING */
+   GLenum blockInterface;
+
+   switch (programInterface) {
+   case GL_BUFFER_VARIABLE:
+      blockInterface = GL_SHADER_STORAGE_BLOCK;
+      break;
+   case GL_UNIFORM:
+      blockInterface = GL_UNIFORM_BLOCK;
+      break;
+   default:
+      assert("Invalid program interface");
+      return NULL;
+   }
+
+   int block_index = -1;
+   int starting_index = -1;
+   struct gl_program_resource *res = shProg->data->ProgramResourceList;
+
+   /* Blocks are added to the resource list in the same order that they are
+    * added to UniformBlocks/ShaderStorageBlocks. Furthermore, all the blocks
+    * of each type (UBO/SSBO) are contiguous, so we can infer block_index from
+    * the resource list.
+    */
+   for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) {
+      if (res->Type != blockInterface)
+         continue;
+
+      /* Store the first index where a resource of the specific interface is. */
+      if (starting_index == -1)
+         starting_index = i;
+
+      const struct gl_uniform_block *block = RESOURCE_UBO(res);
+
+      if (block->Binding == binding) {
+         /* For arrays, or arrays of arrays of blocks, we want the resource
+          * for the block with base index. Most properties for members of each
+          * block are inherited from the block with the base index, including
+          * a uniform being active or not.
+          */
+         block_index = i - starting_index - block->linearized_array_index;
+         break;
+      }
+   }
+
+   if (block_index == -1)
+      return NULL;
+
+   /* We now look for the resource corresponding to the uniform or buffer
+    * variable using the BLOCK_INDEX and OFFSET.
+    */
+   res = shProg->data->ProgramResourceList;
+   for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) {
+      if (res->Type != programInterface)
+         continue;
+
+      const struct gl_uniform_storage *uniform = RESOURCE_UNI(res);
+
+      if (uniform->block_index == block_index && uniform->offset == offset) {
+         return res;
+      }
+   }
+
+   return NULL;
+}
+
+/* Checks if an uniform or buffer variable is in the active program resource
+ * list.
+ *
+ * It takes into accout that for variables coming from SPIR-V binaries their
+ * names could not be available (ARB_gl_spirv). In that case, it will use the
+ * the offset and the block binding to locate the resource.
+ *
+ * Valid interfaces are GL_BUFFER_VARIABLE and GL_UNIFORM.
+ */
+struct gl_program_resource *
+_mesa_program_resource_find_active_variable(struct gl_shader_program *shProg,
+                                            GLenum programInterface,
+                                            const gl_uniform_block *block,
+                                            unsigned index)
+{
+   struct gl_program_resource *res;
+   struct gl_uniform_buffer_variable uni = block->Uniforms[index];
+
+   assert(programInterface == GL_UNIFORM ||
+          programInterface == GL_BUFFER_VARIABLE);
+
+   if (uni.IndexName) {
+      res = _mesa_program_resource_find_name(shProg, programInterface, uni.IndexName,
+                                             NULL);
+   } else {
+      /* As the resource has no associated name (ARB_gl_spirv),
+       * we can use the UBO/SSBO binding and offset to find it.
+       */
+      res = program_resource_find_binding_offset(shProg, programInterface,
+                                                 block->Binding, uni.Offset);
+   }
+
+   return res;
+}
+
 static GLuint
 calc_resource_index(struct gl_shader_program *shProg,
                     struct gl_program_resource *res)
@@ -938,17 +1107,9 @@ _mesa_program_resource_location(struct gl_shader_program *shProg,
    return program_resource_location(res, array_index);
 }
 
-/**
- * Function implements following index queries:
- *    glGetFragDataIndex
- */
-GLint
-_mesa_program_resource_location_index(struct gl_shader_program *shProg,
-                                      GLenum programInterface, const char *name)
+static GLint
+_get_resource_location_index(struct gl_program_resource *res)
 {
-   struct gl_program_resource *res =
-      _mesa_program_resource_find_name(shProg, programInterface, name, NULL);
-
    /* Non-existent variable or resource is not referenced by fragment stage. */
    if (!res || !(res->StageReferences & (1 << MESA_SHADER_FRAGMENT)))
       return -1;
@@ -963,6 +1124,20 @@ _mesa_program_resource_location_index(struct gl_shader_program *shProg,
    return RESOURCE_VAR(res)->index;
 }
 
+/**
+ * Function implements following index queries:
+ *    glGetFragDataIndex
+ */
+GLint
+_mesa_program_resource_location_index(struct gl_shader_program *shProg,
+                                      GLenum programInterface, const char *name)
+{
+   struct gl_program_resource *res =
+      _mesa_program_resource_find_name(shProg, programInterface, name, NULL);
+
+   return _get_resource_location_index(res);
+}
+
 static uint8_t
 stage_from_enum(GLenum ref)
 {
@@ -1033,10 +1208,13 @@ get_buffer_property(struct gl_shader_program *shProg,
       case GL_NUM_ACTIVE_VARIABLES:
          *val = 0;
          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,
-                                                NULL);
+               _mesa_program_resource_find_active_variable(
+                  shProg,
+                  GL_UNIFORM,
+                  RESOURCE_UBO(res),
+                  i);
+
             if (!uni)
                continue;
             (*val)++;
@@ -1045,10 +1223,13 @@ get_buffer_property(struct gl_shader_program *shProg,
       case GL_ACTIVE_VARIABLES: {
          unsigned num_values = 0;
          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,
-                                                NULL);
+               _mesa_program_resource_find_active_variable(
+                  shProg,
+                  GL_UNIFORM,
+                  RESOURCE_UBO(res),
+                  i);
+
             if (!uni)
                continue;
             *val++ =
@@ -1069,10 +1250,13 @@ get_buffer_property(struct gl_shader_program *shProg,
       case GL_NUM_ACTIVE_VARIABLES:
          *val = 0;
          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_BUFFER_VARIABLE,
-                                                iname, NULL);
+               _mesa_program_resource_find_active_variable(
+                  shProg,
+                  GL_BUFFER_VARIABLE,
+                  RESOURCE_UBO(res),
+                  i);
+
             if (!uni)
                continue;
             (*val)++;
@@ -1081,10 +1265,13 @@ get_buffer_property(struct gl_shader_program *shProg,
       case GL_ACTIVE_VARIABLES: {
          unsigned num_values = 0;
          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_BUFFER_VARIABLE,
-                                                iname, NULL);
+               _mesa_program_resource_find_active_variable(
+                  shProg,
+                  GL_BUFFER_VARIABLE,
+                  RESOURCE_UBO(res),
+                  i);
+
             if (!uni)
                continue;
             *val++ =
@@ -1320,8 +1507,7 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg,
       if (tmp == -1)
          *val = -1;
       else
-         *val = _mesa_program_resource_location_index(shProg, res->Type,
-                                                      RESOURCE_VAR(res)->name);
+         *val = _get_resource_location_index(res);
       return 1;
    }
    case GL_NUM_COMPATIBLE_SUBROUTINES:
@@ -1720,3 +1906,23 @@ _mesa_validate_pipeline_io(struct gl_pipeline_object *pipeline)
    }
    return true;
 }
+
+extern "C" void
+_mesa_create_program_resource_hash(struct gl_shader_program *shProg)
+{
+   /* Rebuild resource hash. */
+   if (shProg->data->ProgramResourceHash)
+      _mesa_hash_table_u64_destroy(shProg->data->ProgramResourceHash, NULL);
+
+   shProg->data->ProgramResourceHash = _mesa_hash_table_u64_create(shProg);
+
+   struct gl_program_resource *res = shProg->data->ProgramResourceList;
+   for (unsigned i = 0; i < shProg->data->NumProgramResourceList; i++, res++) {
+      const char *name = _mesa_program_resource_name(res);
+      if (name) {
+         uint32_t key = compute_resource_key(res->Type, name);
+         _mesa_hash_table_u64_insert(shProg->data->ProgramResourceHash, key,
+                                     res);
+      }
+   }
+}