Merge branch '7.8'
[mesa.git] / src / mesa / shader / slang / slang_link.c
index 21497b34e258ca2f16c9991ff2ecf43ab025c1ef..f71fde1d7271741081bd367f27e0caf0c55513b8 100644 (file)
@@ -68,7 +68,7 @@ static void
 link_error(struct gl_shader_program *shProg, const char *msg)
 {
    if (shProg->InfoLog) {
-      _mesa_free(shProg->InfoLog);
+      free(shProg->InfoLog);
    }
    shProg->InfoLog = _mesa_strdup(msg);
    shProg->LinkStatus = GL_FALSE;
@@ -86,6 +86,107 @@ bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit)
 }
 
 
+/**
+ * Examine the outputs/varyings written by the vertex shader and
+ * append the names of those outputs onto the Varyings list.
+ * This will only capture the pre-defined/built-in varyings like
+ * gl_Position, not user-defined varyings.
+ */
+static void
+update_varying_var_list(GLcontext *ctx, struct gl_shader_program *shProg)
+{
+   if (shProg->VertexProgram) {
+      GLbitfield64 written = shProg->VertexProgram->Base.OutputsWritten;
+      GLuint i;
+      for (i = 0; written && i < VERT_RESULT_MAX; i++) {
+         if (written & BITFIELD64_BIT(i)) {
+            const char *name = _slang_vertex_output_name(i);            
+            if (name)
+               _mesa_add_varying(shProg->Varying, name, 1, GL_FLOAT_VEC4, 0x0);
+            written &= ~BITFIELD64_BIT(i);
+         }
+      }
+   }
+}
+
+
+/**
+ * Do link error checking related to transform feedback.
+ */
+static GLboolean
+link_transform_feedback(GLcontext *ctx, struct gl_shader_program *shProg)
+{
+   GLbitfield varyingMask;
+   GLuint totalComps, maxComps, i;
+
+   if (shProg->TransformFeedback.NumVarying == 0) {
+      /* nothing to do */
+      return GL_TRUE;
+   }
+
+   /* Check that there's a vertex shader */
+   if (shProg->TransformFeedback.NumVarying > 0 &&
+       !shProg->VertexProgram) {
+      link_error(shProg, "Transform feedback without vertex shader");
+      return GL_FALSE;
+   }
+
+   /* Check that all named variables exist, and that none are duplicated.
+    * Also, build a count of the number of varying components to feedback.
+    */
+   totalComps = 0;
+   varyingMask = 0x0;
+   for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
+      const GLchar *name = shProg->TransformFeedback.VaryingNames[i];
+      GLint v = _mesa_lookup_parameter_index(shProg->Varying, -1, name);
+      struct gl_program_parameter *p;
+
+      if (v < 0) {
+         char msg[100];
+         _mesa_snprintf(msg, sizeof(msg),
+                        "vertex shader does not emit %s", name);
+         link_error(shProg, msg);
+         return GL_FALSE;
+      }
+
+      assert(v < MAX_VARYING);
+
+      /* already seen this varying name? */
+      if (varyingMask & (1 << v)) {
+         char msg[100];
+         _mesa_snprintf(msg, sizeof(msg),
+                        "duplicated transform feedback varying name: %s",
+                        name);
+         link_error(shProg, msg);
+         return GL_FALSE;
+      }
+
+      varyingMask |= (1 << v);
+
+      p = &shProg->Varying->Parameters[v];
+      
+      totalComps += _mesa_sizeof_glsl_type(p->DataType);
+   }
+
+   if (shProg->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS)
+      maxComps = ctx->Const.MaxTransformFeedbackInterleavedComponents;
+   else
+      maxComps = ctx->Const.MaxTransformFeedbackSeparateComponents;
+
+   /* check max varying components against the limit */
+   if (totalComps > maxComps) {
+      char msg[100];
+      _mesa_snprintf(msg, sizeof(msg),
+                     "Too many feedback components: %u, max is %u",
+                     totalComps, maxComps);
+      link_error(shProg, msg);
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+}
+
+
 /**
  * Linking varying vars involves rearranging varying vars so that the
  * vertex program's output varyings matches the order of the fragment
@@ -103,7 +204,7 @@ link_varying_vars(GLcontext *ctx,
    GLuint *map, i, firstVarying, newFile;
    GLbitfield *inOutFlags;
 
-   map = (GLuint *) _mesa_malloc(prog->Varying->NumParameters * sizeof(GLuint));
+   map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint));
    if (!map)
       return GL_FALSE;
 
@@ -134,35 +235,35 @@ link_varying_vars(GLcontext *ctx,
             &shProg->Varying->Parameters[j];
          if (var->Size != v->Size) {
             link_error(shProg, "mismatched varying variable types");
-            _mesa_free(map);
+            free(map);
             return GL_FALSE;
          }
          if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) {
             char msg[100];
             _mesa_snprintf(msg, sizeof(msg),
-                           "centroid modifier mismatch for '%s'", var->Name);
+                    "centroid modifier mismatch for '%s'", var->Name);
             link_error(shProg, msg);
-            _mesa_free(map);
+            free(map);
             return GL_FALSE;
          }
          if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) {
             char msg[100];
             _mesa_snprintf(msg, sizeof(msg),
-                           "invariant modifier mismatch for '%s'", var->Name);
+                    "invariant modifier mismatch for '%s'", var->Name);
             link_error(shProg, msg);
-            _mesa_free(map);
+            free(map);
             return GL_FALSE;
          }
       }
       else {
          /* not already in linked list */
          j = _mesa_add_varying(shProg->Varying, var->Name, var->Size,
-                               var->Flags);
+                               var->DataType, var->Flags);
       }
 
       if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) {
          link_error(shProg, "Too many varying variables");
-         _mesa_free(map);
+         free(map);
          return GL_FALSE;
       }
 
@@ -202,7 +303,7 @@ link_varying_vars(GLcontext *ctx,
       }
    }
 
-   _mesa_free(map);
+   free(map);
 
    /* these will get recomputed before linking is completed */
    prog->InputsRead = 0x0;
@@ -269,8 +370,8 @@ link_uniform_vars(GLcontext *ctx,
          GLuint newSampNum = *numSamplers;
          if (newSampNum >= ctx->Const.MaxTextureImageUnits) {
             char s[100];
-            _mesa_sprintf(s, "Too many texture samplers (%u, max is %u)",
-                          newSampNum, ctx->Const.MaxTextureImageUnits);
+            sprintf(s, "Too many texture samplers (%u, max is %u)",
+                   newSampNum, ctx->Const.MaxTextureImageUnits);
             link_error(shProg, s);
             return GL_FALSE;
          }
@@ -563,7 +664,7 @@ remove_extra_version_directives(GLchar *source)
 {
    GLuint verCount = 0;
    while (1) {
-      char *ver = _mesa_strstr(source, "#version");
+      char *ver = strstr(source, "#version");
       if (ver) {
          verCount++;
          if (verCount > 1) {
@@ -594,7 +695,7 @@ concat_shaders(struct gl_shader_program *shProg, GLenum shaderType)
    GLuint totalLen = 0, len = 0;
    GLuint i;
 
-   shaderLengths = (GLuint *)_mesa_malloc(shProg->NumShaders * sizeof(GLuint));
+   shaderLengths = (GLuint *)malloc(shProg->NumShaders * sizeof(GLuint));
    if (!shaderLengths) {
       return NULL;
    }
@@ -603,7 +704,7 @@ concat_shaders(struct gl_shader_program *shProg, GLenum shaderType)
    for (i = 0; i < shProg->NumShaders; i++) {
       const struct gl_shader *shader = shProg->Shaders[i];
       if (shader->Type == shaderType) {
-         shaderLengths[i] = _mesa_strlen(shader->Source);
+         shaderLengths[i] = strlen(shader->Source);
          totalLen += shaderLengths[i];
          if (!firstShader)
             firstShader = shader;
@@ -611,13 +712,13 @@ concat_shaders(struct gl_shader_program *shProg, GLenum shaderType)
    }
 
    if (totalLen == 0) {
-      _mesa_free(shaderLengths);
+      free(shaderLengths);
       return NULL;
    }
 
-   source = (GLchar *) _mesa_malloc(totalLen + 1);
+   source = (GLchar *) malloc(totalLen + 1);
    if (!source) {
-      _mesa_free(shaderLengths);
+      free(shaderLengths);
       return NULL;
    }
 
@@ -625,22 +726,22 @@ concat_shaders(struct gl_shader_program *shProg, GLenum shaderType)
    for (i = 0; i < shProg->NumShaders; i++) {
       const struct gl_shader *shader = shProg->Shaders[i];
       if (shader->Type == shaderType) {
-         _mesa_memcpy(source + len, shader->Source, shaderLengths[i]);
+         memcpy(source + len, shader->Source, shaderLengths[i]);
          len += shaderLengths[i];
       }
    }
    source[len] = '\0';
    /*
-   _mesa_printf("---NEW CONCATENATED SHADER---:\n%s\n------------\n", source);
+   printf("---NEW CONCATENATED SHADER---:\n%s\n------------\n", source);
    */
 
-   _mesa_free(shaderLengths);
+   free(shaderLengths);
 
    remove_extra_version_directives(source);
 
    newShader = CALLOC_STRUCT(gl_shader);
    if (!newShader) {
-      _mesa_free(source);
+      free(source);
       return NULL;
    }
 
@@ -719,6 +820,7 @@ _slang_link(GLcontext *ctx,
 {
    const struct gl_vertex_program *vertProg = NULL;
    const struct gl_fragment_program *fragProg = NULL;
+   GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE;
    GLuint numSamplers = 0;
    GLuint i;
 
@@ -772,7 +874,7 @@ _slang_link(GLcontext *ctx,
    _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
    if (vertProg) {
       struct gl_vertex_program *linked_vprog =
-         vertex_program(_mesa_clone_program(ctx, &vertProg->Base));
+         _mesa_clone_vertex_program(ctx, vertProg);
       shProg->VertexProgram = linked_vprog; /* refcount OK */
       /* vertex program ID not significant; just set Id for debugging purposes */
       shProg->VertexProgram->Base.Id = shProg->Name;
@@ -782,7 +884,7 @@ _slang_link(GLcontext *ctx,
    _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
    if (fragProg) {
       struct gl_fragment_program *linked_fprog = 
-         fragment_program(_mesa_clone_program(ctx, &fragProg->Base));
+         _mesa_clone_fragment_program(ctx, fragProg);
       shProg->FragmentProgram = linked_fprog; /* refcount OK */
       /* vertex program ID not significant; just set Id for debugging purposes */
       shProg->FragmentProgram->Base.Id = shProg->Name;
@@ -865,20 +967,26 @@ _slang_link(GLcontext *ctx,
       }         
    }
 
+   update_varying_var_list(ctx, shProg);
+
+   /* checks related to transform feedback */
+   if (!link_transform_feedback(ctx, shProg)) {
+      return;
+   }
 
    if (fragProg && shProg->FragmentProgram) {
       /* Compute initial program's TexturesUsed info */
       _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base);
 
       /* notify driver that a new fragment program has been compiled/linked */
-      ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
-                                      &shProg->FragmentProgram->Base);
+      vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
+                                                 &shProg->FragmentProgram->Base);
       if (ctx->Shader.Flags & GLSL_DUMP) {
-         _mesa_printf("Mesa pre-link fragment program:\n");
+         printf("Mesa pre-link fragment program:\n");
          _mesa_print_program(&fragProg->Base);
          _mesa_print_program_parameters(ctx, &fragProg->Base);
 
-         _mesa_printf("Mesa post-link fragment program:\n");
+         printf("Mesa post-link fragment program:\n");
          _mesa_print_program(&shProg->FragmentProgram->Base);
          _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);
       }
@@ -889,14 +997,14 @@ _slang_link(GLcontext *ctx,
       _mesa_update_shader_textures_used(&shProg->VertexProgram->Base);
 
       /* notify driver that a new vertex program has been compiled/linked */
-      ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
-                                      &shProg->VertexProgram->Base);
+      fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
+                                                   &shProg->VertexProgram->Base);
       if (ctx->Shader.Flags & GLSL_DUMP) {
-         _mesa_printf("Mesa pre-link vertex program:\n");
+         printf("Mesa pre-link vertex program:\n");
          _mesa_print_program(&vertProg->Base);
          _mesa_print_program_parameters(ctx, &vertProg->Base);
 
-         _mesa_printf("Mesa post-link vertex program:\n");
+         printf("Mesa post-link vertex program:\n");
          _mesa_print_program(&shProg->VertexProgram->Base);
          _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);
       }
@@ -911,13 +1019,19 @@ _slang_link(GLcontext *ctx,
    }
 
    if (ctx->Shader.Flags & GLSL_DUMP) {
-      _mesa_printf("Varying vars:\n");
+      printf("Varying vars:\n");
       _mesa_print_parameter_list(shProg->Varying);
       if (shProg->InfoLog) {
-         _mesa_printf("Info Log: %s\n", shProg->InfoLog);
+         printf("Info Log: %s\n", shProg->InfoLog);
       }
    }
 
-   shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram);
+   if (!vertNotify || !fragNotify) {
+      /* driver rejected one/both of the vertex/fragment programs */
+      link_error(shProg, "Vertex and/or fragment program rejected by driver\n");
+   }
+   else {
+      shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram);
+   }
 }