subroutines: handle explicit indexes properly
authorDave Airlie <airlied@redhat.com>
Tue, 17 May 2016 04:44:47 +0000 (14:44 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 23 May 2016 06:19:57 +0000 (16:19 +1000)
The code didn't deal with explicit function indexes properly.
It also handed out the indexes at link time, when we really
need them in the lowering pass to create the correct if ladder.

So this patch moves assigning the non-explicit indexes earlier,
fixes the lowering pass and the lookups to get the correct values.

This fixes a few of:
GL45-CTS.explicit_uniform_location.subroutine-index-*

Signed-off-by: Dave Airlie <airlied@redhat.com>
src/compiler/glsl/glsl_parser_extras.cpp
src/compiler/glsl/linker.cpp
src/compiler/glsl/lower_subroutine.cpp
src/mesa/main/mtypes.h
src/mesa/main/shaderapi.c

index 771fd197221c4e40b109ad04227e0cf9201113d8..1d0110b0770d22507888ebe853bc5498e84420ff 100644 (file)
@@ -1755,6 +1755,27 @@ set_shader_inout_layout(struct gl_shader *shader,
 
 extern "C" {
 
+static void
+assign_subroutine_indexes(struct gl_shader *sh,
+                         struct _mesa_glsl_parse_state *state)
+{
+   int j, k;
+   int index = 0;
+
+   for (j = 0; j < state->num_subroutines; j++) {
+      while (state->subroutines[j]->subroutine_index == -1) {
+         for (k = 0; k < state->num_subroutines; k++) {
+            if (state->subroutines[k]->subroutine_index == index)
+               break;
+            else if (k == state->num_subroutines - 1) {
+               state->subroutines[j]->subroutine_index = index;
+            }
+         }
+         index++;
+      }
+   }
+}
+
 void
 _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader,
                           bool dump_ast, bool dump_hir)
@@ -1802,6 +1823,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader,
       struct gl_shader_compiler_options *options =
          &ctx->Const.ShaderCompilerOptions[shader->Stage];
 
+      assign_subroutine_indexes(shader, state);
       lower_subroutine(shader->ir, state);
       /* Do some optimization at compile time to reduce shader IR size
        * and reduce later work if the same shader is linked multiple times
index a7b2a19a66b09388180dcdc16a36dc097e09a679..0b8c494369517b6b8d903b8ad774542793815bb4 100644 (file)
@@ -4222,6 +4222,7 @@ link_assign_subroutine_types(struct gl_shader_program *prog)
       if (sh == NULL)
          continue;
 
+      sh->MaxSubroutineFunctionIndex = 0;
       foreach_in_list(ir_instruction, node, sh->ir) {
          ir_function *fn = node->as_function();
          if (!fn)
@@ -4233,6 +4234,8 @@ link_assign_subroutine_types(struct gl_shader_program *prog)
          if (!fn->num_subroutine_types)
             continue;
 
+        /* these should have been calculated earlier. */
+        assert(fn->subroutine_index != -1);
          if (sh->NumSubroutineFunctions + 1 > MAX_SUBROUTINES) {
             linker_error(prog, "Too many subroutine functions declared.\n");
             return;
@@ -4264,24 +4267,13 @@ link_assign_subroutine_types(struct gl_shader_program *prog)
          sh->SubroutineFunctions[sh->NumSubroutineFunctions].index =
             fn->subroutine_index;
 
+         if (fn->subroutine_index > (int)sh->MaxSubroutineFunctionIndex)
+            sh->MaxSubroutineFunctionIndex = fn->subroutine_index;
+
          for (int j = 0; j < fn->num_subroutine_types; j++)
             sh->SubroutineFunctions[sh->NumSubroutineFunctions].types[j] = fn->subroutine_types[j];
          sh->NumSubroutineFunctions++;
       }
-
-      /* Assign index for subroutines without an explicit index*/
-      int index = 0;
-      for (unsigned j = 0; j < sh->NumSubroutineFunctions; j++) {
-         while (sh->SubroutineFunctions[j].index == -1) {
-            for (unsigned k = 0; k < sh->NumSubroutineFunctions; k++) {
-               if (sh->SubroutineFunctions[k].index == index)
-                  break;
-               else if (k == sh->NumSubroutineFunctions - 1)
-                  sh->SubroutineFunctions[j].index = index;
-            }
-            index++;
-         }
-      }
    }
 }
 
index e80c1be768a08aea0768d8f2521c75240446a89b..de178a59b07a2d30c16f38deeb3ad28474d56e26 100644 (file)
@@ -87,8 +87,9 @@ lower_subroutine_visitor::visit_leave(ir_call *ir)
 
    for (int s = this->state->num_subroutines - 1; s >= 0; s--) {
       ir_rvalue *var;
-      ir_constant *lc = new(mem_ctx)ir_constant(s);
       ir_function *fn = this->state->subroutines[s];
+      ir_constant *lc = new(mem_ctx)ir_constant(fn->subroutine_index);
+
       bool is_compat = false;
 
       for (int i = 0; i < fn->num_subroutine_types; i++) {
index 05b205903697d28a94301b96d7c0a707ecb7bba7..f6c6d9733e13d35c6a341a2e8b6b7ad827fe2dc1 100644 (file)
@@ -2445,6 +2445,7 @@ struct gl_shader
     * and storage for them.
     */
    GLuint NumSubroutineFunctions;
+   GLuint MaxSubroutineFunctionIndex;
    struct gl_subroutine_function *SubroutineFunctions;
 };
 
index 6d58fbb492e5d06a03af37acc52c58eee8ed38bb..167e06f3d4f4b1dd4650c5457d8b4ab6a72b35f1 100644 (file)
@@ -2546,16 +2546,24 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
       }
 
       int uni_count = uni->array_elements ? uni->array_elements : 1;
-      int j, k;
+      int j, k, f;
 
       for (j = i; j < i + uni_count; j++) {
-         struct gl_subroutine_function *subfn;
-         if (indices[j] >= sh->NumSubroutineFunctions) {
+         struct gl_subroutine_function *subfn = NULL;
+         if (indices[j] > sh->MaxSubroutineFunctionIndex) {
             _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
             return;
          }
 
-         subfn = &sh->SubroutineFunctions[indices[j]];
+         for (f = 0; f < sh->NumSubroutineFunctions; f++) {
+            if (sh->SubroutineFunctions[f].index == indices[j])
+               subfn = &sh->SubroutineFunctions[f];
+         }
+
+         if (!subfn) {
+            continue;
+         }
+
          for (k = 0; k < subfn->num_compat_types; k++) {
             if (subfn->types[k] == uni->type)
                break;