nir/linker: Compute the offset for non-trivial uniform types.
authorAntia Puentes <apuentes@igalia.com>
Wed, 12 Sep 2018 11:51:57 +0000 (13:51 +0200)
committerAlejandro Piñeiro <apinheiro@igalia.com>
Fri, 12 Jul 2019 21:42:41 +0000 (23:42 +0200)
ARB_gl_spirv points that the offset must be explicit, however this is
true for 'root' types. For complex types, like struct members or
arrays of arraya, it needs to be computed.

We are not using the offset stored in the gl_buffer_variables during
the uniform blocks linking because currently we do not have a way to
relate a gl_buffer_variable with its corresponding gl_uniform_storage.
The GLSL path uses the name for that, but we can not rely on that
because names are optional in SPIR-V.

Notice that uniforms non-backed by a buffer object will have an offset
equal to -1, like in the GLSL path.

v2: add offset and var_is_in_block as per-variable state in
    nir_link_uniforms_state (Arcady)

Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
src/compiler/glsl/gl_nir_link_uniforms.c

index a17d136..4a19ad8 100644 (file)
@@ -247,6 +247,8 @@ struct nir_link_uniforms_state {
    unsigned shader_shadow_samplers;
 
    nir_variable *current_var;
+   int offset;
+   bool var_is_in_block;
 
    struct type_tree_entry *current_type;
 };
@@ -361,16 +363,26 @@ nir_link_uniform(struct gl_context *ctx,
          glsl_type_is_struct_or_ifc(glsl_get_array_element(type))))) {
       int location_count = 0;
       struct type_tree_entry *old_type = state->current_type;
+      unsigned int struct_base_offset = state->offset;
 
       state->current_type = old_type->children;
 
       for (unsigned i = 0; i < glsl_get_length(type); i++) {
          const struct glsl_type *field_type;
 
-         if (glsl_type_is_struct_or_ifc(type))
+         if (glsl_type_is_struct_or_ifc(type)) {
             field_type = glsl_get_struct_field(type, i);
-         else
+            /* Use the offset inside the struct only for variables backed by
+             * a buffer object. For variables not backed by a buffer object,
+             * offset is -1.
+             */
+            if (state->var_is_in_block) {
+               state->offset =
+                  struct_base_offset + glsl_get_struct_field_offset(type, i);
+            }
+         } else {
             field_type = glsl_get_array_element(type);
+         }
 
          int entries = nir_link_uniform(ctx, prog, stage_program, stage,
                                         field_type, type, i, location,
@@ -459,7 +471,7 @@ nir_link_uniform(struct gl_context *ctx,
       uniform->matrix_stride = -1;
       uniform->row_major = false;
 
-      if (nir_variable_is_in_block(state->current_var)) {
+      if (state->var_is_in_block) {
          uniform->array_stride = glsl_type_is_array(type) ?
             glsl_get_explicit_stride(type) : 0;
 
@@ -473,16 +485,13 @@ nir_link_uniform(struct gl_context *ctx,
          }
       }
 
-      if (parent_type)
-         uniform->offset = glsl_get_struct_field_offset(parent_type, index_in_parent);
-      else
-         uniform->offset = 0;
+      uniform->offset = state->var_is_in_block ? state->offset : -1;
 
       int buffer_block_index = -1;
       /* If the uniform is inside a uniform block determine its block index by
        * comparing the bindings, we can not use names.
        */
-      if (nir_variable_is_in_block(state->current_var)) {
+      if (state->var_is_in_block) {
          struct gl_uniform_block *blocks = nir_variable_is_in_ssbo(state->current_var) ?
             prog->data->ShaderStorageBlocks : prog->data->UniformBlocks;
 
@@ -496,6 +505,9 @@ nir_link_uniform(struct gl_context *ctx,
             }
          }
          assert(buffer_block_index >= 0);
+
+         /* Compute the next offset. */
+         state->offset += glsl_get_explicit_size(type, true);
       }
 
       uniform->block_index = buffer_block_index;
@@ -620,6 +632,8 @@ gl_nir_link_uniforms(struct gl_context *ctx,
          var->data.location = prog->data->NumUniformStorage;
 
          state.current_var = var;
+         state.offset = 0;
+         state.var_is_in_block = nir_variable_is_in_block(var);
 
          /*
           * From ARB_program_interface spec, issue (16):
@@ -656,8 +670,7 @@ gl_nir_link_uniforms(struct gl_context *ctx,
           * arrays of instance as a single block.
           */
          const struct glsl_type *type = var->type;
-         if (nir_variable_is_in_block(var) &&
-             glsl_type_is_array(type)) {
+         if (state.var_is_in_block && glsl_type_is_array(type)) {
             type = glsl_without_array(type);
          }