mesa: Move declarations before code.
[mesa.git] / src / glsl / linker.cpp
index 6a07e4ab0d1e2db17f103c0cde2d51f20787de33..f6b26618552dd87c7054c457b00bac0f68b3cc78 100644 (file)
@@ -1206,6 +1206,7 @@ link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
                                unsigned num_shaders)
 {
    linked_shader->Geom.VerticesOut = 0;
+   linked_shader->Geom.Invocations = 0;
    linked_shader->Geom.InputType = PRIM_UNKNOWN;
    linked_shader->Geom.OutputType = PRIM_UNKNOWN;
 
@@ -1259,6 +1260,18 @@ link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
         }
         linked_shader->Geom.VerticesOut = shader->Geom.VerticesOut;
       }
+
+      if (shader->Geom.Invocations != 0) {
+        if (linked_shader->Geom.Invocations != 0 &&
+            linked_shader->Geom.Invocations != shader->Geom.Invocations) {
+           linker_error(prog, "geometry shader defined with conflicting "
+                        "invocation count (%d and %d)\n",
+                        linked_shader->Geom.Invocations,
+                        shader->Geom.Invocations);
+           return;
+        }
+        linked_shader->Geom.Invocations = shader->Geom.Invocations;
+      }
    }
 
    /* Just do the intrastage -> interstage propagation right now,
@@ -1285,6 +1298,11 @@ link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
       return;
    }
    prog->Geom.VerticesOut = linked_shader->Geom.VerticesOut;
+
+   if (linked_shader->Geom.Invocations == 0)
+      linked_shader->Geom.Invocations = 1;
+
+   prog->Geom.Invocations = linked_shader->Geom.Invocations;
 }
 
 
@@ -2031,6 +2049,46 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
    }
 }
 
+/**
+ * Validate shader image resources.
+ */
+static void
+check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+   unsigned total_image_units = 0;
+   unsigned fragment_outputs = 0;
+
+   if (!ctx->Extensions.ARB_shader_image_load_store)
+      return;
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_shader *sh = prog->_LinkedShaders[i];
+
+      if (sh) {
+         if (sh->NumImages > ctx->Const.Program[i].MaxImageUniforms)
+            linker_error(prog, "Too many %s shader image uniforms",
+                         _mesa_shader_stage_to_string(i));
+
+         total_image_units += sh->NumImages;
+
+         if (i == MESA_SHADER_FRAGMENT) {
+            foreach_list(node, sh->ir) {
+               ir_variable *var = ((ir_instruction *)node)->as_variable();
+               if (var && var->data.mode == ir_var_shader_out)
+                  fragment_outputs += var->type->count_attribute_slots();
+            }
+         }
+      }
+   }
+
+   if (total_image_units > ctx->Const.MaxCombinedImageUniforms)
+      linker_error(prog, "Too many combined image uniforms");
+
+   if (total_image_units + fragment_outputs >
+       ctx->Const.MaxCombinedImageUnitsAndFragmentOutputs)
+      linker_error(prog, "Too many combined image uniforms and fragment outputs");
+}
+
 void
 link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 {
@@ -2109,6 +2167,13 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       goto done;
    }
 
+   /* Compute shaders have additional restrictions. */
+   if (num_shaders[MESA_SHADER_COMPUTE] > 0 &&
+       num_shaders[MESA_SHADER_COMPUTE] != prog->NumShaders) {
+      linker_error(prog, "Compute shaders may not be linked with any other "
+                   "type of shader\n");
+   }
+
    for (unsigned int i = 0; i < MESA_SHADER_STAGES; i++) {
       if (prog->_LinkedShaders[i] != NULL)
         ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]);
@@ -2387,17 +2452,19 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    store_fragdepth_layout(prog);
 
    check_resources(ctx, prog);
+   check_image_resources(ctx, prog);
    link_check_atomic_counter_resources(ctx, prog);
 
    if (!prog->LinkStatus)
       goto done;
 
    /* OpenGL ES requires that a vertex shader and a fragment shader both be
-    * present in a linked program.  By checking prog->IsES, we also
-    * catch the GL_ARB_ES2_compatibility case.
+    * present in a linked program. GL_ARB_ES2_compatibility doesn't say
+    * anything about shader linking when one of the shaders (vertex or
+    * fragment shader) is absent. So, the extension shouldn't change the
+    * behavior specified in GLSL specification.
     */
-   if (!prog->InternalSeparateShader &&
-       (ctx->API == API_OPENGLES2 || prog->IsES)) {
+   if (!prog->InternalSeparateShader && ctx->API == API_OPENGLES2) {
       if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
         linker_error(prog, "program lacks a vertex shader\n");
       } else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) {