OSDN Git Service

mesa: Drop PATH_MAX usage.
[android-x86/external-mesa.git] / src / mesa / main / shaderapi.c
index 7680b58..627bc73 100644 (file)
@@ -37,6 +37,7 @@
  */
 
 
+#include <stdbool.h>
 #include "main/glheader.h"
 #include "main/context.h"
 #include "main/dispatch.h"
 #include "main/shaderobj.h"
 #include "main/transformfeedback.h"
 #include "main/uniforms.h"
+#include "compiler/glsl/glsl_parser_extras.h"
+#include "compiler/glsl/ir.h"
+#include "compiler/glsl/ir_uniform.h"
+#include "compiler/glsl/program.h"
 #include "program/program.h"
 #include "program/prog_print.h"
 #include "program/prog_parameter.h"
 #include "util/ralloc.h"
 #include "util/hash_table.h"
 #include "util/mesa-sha1.h"
-#include <stdbool.h>
-#include "../glsl/glsl_parser_extras.h"
-#include "../glsl/ir.h"
-#include "../glsl/ir_uniform.h"
-#include "../glsl/program.h"
-
 
 /**
  * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
@@ -96,6 +95,22 @@ _mesa_get_shader_flags(void)
    return flags;
 }
 
+/**
+ * Memoized version of getenv("MESA_SHADER_CAPTURE_PATH").
+ */
+const char *
+_mesa_get_shader_capture_path(void)
+{
+   static bool read_env_var = false;
+   static const char *path = NULL;
+
+   if (!read_env_var) {
+      path = getenv("MESA_SHADER_CAPTURE_PATH");
+      read_env_var = true;
+   }
+
+   return path;
+}
 
 /**
  * Initialize context's shader state.
@@ -208,7 +223,7 @@ _mesa_validate_shader_target(const struct gl_context *ctx, GLenum type)
    case GL_TESS_EVALUATION_SHADER:
       return ctx == NULL || _mesa_has_tessellation(ctx);
    case GL_COMPUTE_SHADER:
-      return ctx == NULL || ctx->Extensions.ARB_compute_shader;
+      return ctx == NULL || _mesa_has_compute_shaders(ctx);
    default:
       return false;
    }
@@ -264,7 +279,7 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
          _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
          return;
       } else if (same_type_disallowed &&
-                 shProg->Shaders[i]->Type == sh->Type) {
+                 shProg->Shaders[i]->Stage == sh->Stage) {
         /* Shader with the same type is already attached to this program,
          * OpenGL ES 2.0 and 3.0 specs say:
          *
@@ -300,13 +315,17 @@ create_shader(struct gl_context *ctx, GLenum type)
    GLuint name;
 
    if (!_mesa_validate_shader_target(ctx, type)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
+      _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(%s)",
+                  _mesa_enum_to_string(type));
       return 0;
    }
 
+   _mesa_HashLockMutex(ctx->Shared->ShaderObjects);
    name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
-   sh = ctx->Driver.NewShader(ctx, name, type);
-   _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
+   sh = _mesa_new_shader(name, _mesa_shader_enum_to_shader_stage(type));
+   sh->Type = type;
+   _mesa_HashInsertLocked(ctx->Shared->ShaderObjects, name, sh);
+   _mesa_HashUnlockMutex(ctx->Shared->ShaderObjects);
 
    return name;
 }
@@ -318,14 +337,18 @@ create_shader_program(struct gl_context *ctx)
    GLuint name;
    struct gl_shader_program *shProg;
 
+   _mesa_HashLockMutex(ctx->Shared->ShaderObjects);
+
    name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
 
-   shProg = ctx->Driver.NewShaderProgram(name);
+   shProg = _mesa_new_shader_program(name);
 
-   _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
+   _mesa_HashInsertLocked(ctx->Shared->ShaderObjects, name, shProg);
 
    assert(shProg->RefCount == 1);
 
+   _mesa_HashUnlockMutex(ctx->Shared->ShaderObjects);
+
    return name;
 }
 
@@ -422,11 +445,11 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
 #ifdef DEBUG
          /* sanity check - make sure the new list's entries are sensible */
          for (j = 0; j < shProg->NumShaders; j++) {
-            assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
-                   shProg->Shaders[j]->Type == GL_TESS_CONTROL_SHADER ||
-                   shProg->Shaders[j]->Type == GL_TESS_EVALUATION_SHADER ||
-                   shProg->Shaders[j]->Type == GL_GEOMETRY_SHADER ||
-                   shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
+            assert(shProg->Shaders[j]->Stage == MESA_SHADER_VERTEX ||
+                   shProg->Shaders[j]->Stage == MESA_SHADER_TESS_CTRL ||
+                   shProg->Shaders[j]->Stage == MESA_SHADER_TESS_EVAL ||
+                   shProg->Shaders[j]->Stage == MESA_SHADER_GEOMETRY ||
+                   shProg->Shaders[j]->Stage == MESA_SHADER_FRAGMENT);
             assert(shProg->Shaders[j]->RefCount > 0);
          }
 #endif
@@ -630,9 +653,16 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname,
    case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
       *params = _mesa_longest_attribute_name_length(shProg);
       return;
-   case GL_ACTIVE_UNIFORMS:
-      *params = shProg->NumUniformStorage - shProg->NumHiddenUniforms;
+   case GL_ACTIVE_UNIFORMS: {
+      unsigned i;
+      const unsigned num_uniforms =
+         shProg->NumUniformStorage - shProg->NumHiddenUniforms;
+      for (*params = 0, i = 0; i < num_uniforms; i++) {
+         if (!shProg->UniformStorage[i].is_shader_storage)
+            (*params)++;
+      }
       return;
+   }
    case GL_ACTIVE_UNIFORM_MAX_LENGTH: {
       unsigned i;
       GLint max_len = 0;
@@ -640,6 +670,9 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname,
          shProg->NumUniformStorage - shProg->NumHiddenUniforms;
 
       for (i = 0; i < num_uniforms; i++) {
+         if (shProg->UniformStorage[i].is_shader_storage)
+            continue;
+
         /* Add one for the terminating NUL character for a non-array, and
          * 4 for the "[0]" and the NUL for an array.
          */
@@ -685,26 +718,34 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname,
    case GL_GEOMETRY_VERTICES_OUT:
       if (!has_core_gs)
          break;
-      if (check_gs_query(ctx, shProg))
-         *params = shProg->Geom.VerticesOut;
+      if (check_gs_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+            info.Geom.VerticesOut;
+      }
       return;
    case GL_GEOMETRY_SHADER_INVOCATIONS:
       if (!has_core_gs || !ctx->Extensions.ARB_gpu_shader5)
          break;
-      if (check_gs_query(ctx, shProg))
-         *params = shProg->Geom.Invocations;
+      if (check_gs_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+            info.Geom.Invocations;
+      }
       return;
    case GL_GEOMETRY_INPUT_TYPE:
       if (!has_core_gs)
          break;
-      if (check_gs_query(ctx, shProg))
-         *params = shProg->Geom.InputType;
+      if (check_gs_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+            info.Geom.InputType;
+      }
       return;
    case GL_GEOMETRY_OUTPUT_TYPE:
       if (!has_core_gs)
          break;
-      if (check_gs_query(ctx, shProg))
-         *params = shProg->Geom.OutputType;
+      if (check_gs_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+            info.Geom.OutputType;
+      }
       return;
    case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: {
       unsigned i;
@@ -771,39 +812,50 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname,
       return;
    }
    case GL_PROGRAM_SEPARABLE:
-      *params = shProg->SeparateShader;
+      /* If the program has not been linked, return initial value 0. */
+      *params = (shProg->LinkStatus == GL_FALSE) ? 0 : shProg->SeparateShader;
       return;
 
    /* ARB_tessellation_shader */
    case GL_TESS_CONTROL_OUTPUT_VERTICES:
       if (!has_tess)
          break;
-      if (check_tcs_query(ctx, shProg))
-         *params = shProg->TessCtrl.VerticesOut;
+      if (check_tcs_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL]->
+            info.TessCtrl.VerticesOut;
+      }
       return;
    case GL_TESS_GEN_MODE:
       if (!has_tess)
          break;
-      if (check_tes_query(ctx, shProg))
-         *params = shProg->TessEval.PrimitiveMode;
+      if (check_tes_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
+            info.TessEval.PrimitiveMode;
+      }
       return;
    case GL_TESS_GEN_SPACING:
       if (!has_tess)
          break;
-      if (check_tes_query(ctx, shProg))
-         *params = shProg->TessEval.Spacing;
+      if (check_tes_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
+            info.TessEval.Spacing;
+      }
       return;
    case GL_TESS_GEN_VERTEX_ORDER:
       if (!has_tess)
          break;
-      if (check_tes_query(ctx, shProg))
-         *params = shProg->TessEval.VertexOrder;
+      if (check_tes_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
+            info.TessEval.VertexOrder;
+         }
       return;
    case GL_TESS_GEN_POINT_MODE:
       if (!has_tess)
          break;
-      if (check_tes_query(ctx, shProg))
-         *params = shProg->TessEval.PointMode;
+      if (check_tes_query(ctx, shProg)) {
+         *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
+            info.TessEval.PointMode;
+      }
       return;
    default:
       break;
@@ -930,18 +982,13 @@ get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
  * glShaderSource[ARB].
  */
 static void
-shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
+shader_source(struct gl_shader *sh, const GLchar *source)
 {
-   struct gl_shader *sh;
-
-   sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
-   if (!sh)
-      return;
+   assert(sh);
 
    /* free old shader source string and install new one */
    free((void *)sh->Source);
    sh->Source = source;
-   sh->CompileStatus = GL_FALSE;
 #ifdef DEBUG
    sh->SourceChecksum = _mesa_str_checksum(sh->Source);
 #endif
@@ -951,12 +998,9 @@ shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
 /**
  * Compile a shader.
  */
-static void
-compile_shader(struct gl_context *ctx, GLuint shaderObj)
+void
+_mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh)
 {
-   struct gl_shader *sh;
-
-   sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
    if (!sh)
       return;
 
@@ -983,8 +1027,13 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
 
       if (ctx->_Shader->Flags & GLSL_DUMP) {
          if (sh->CompileStatus) {
-            _mesa_log("GLSL IR for shader %d:\n", sh->Name);
-            _mesa_print_ir(_mesa_get_log_file(), sh->ir, NULL);
+            if (sh->ir) {
+               _mesa_log("GLSL IR for shader %d:\n", sh->Name);
+               _mesa_print_ir(_mesa_get_log_file(), sh->ir, NULL);
+            } else {
+               _mesa_log("No GLSL IR for shader %d (shader may be from "
+                         "cache)\n", sh->Name);
+            }
             _mesa_log("\n\n");
          } else {
             _mesa_log("GLSL shader %d failed to compile.\n", sh->Name);
@@ -1015,12 +1064,9 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
 /**
  * Link a program's shaders.
  */
-static void
-link_program(struct gl_context *ctx, GLuint program)
+void
+_mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg)
 {
-   struct gl_shader_program *shProg;
-
-   shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
    if (!shProg)
       return;
 
@@ -1039,6 +1085,34 @@ link_program(struct gl_context *ctx, GLuint program)
 
    _mesa_glsl_link_shader(ctx, shProg);
 
+   /* Capture .shader_test files. */
+   const char *capture_path = _mesa_get_shader_capture_path();
+   if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) {
+      FILE *file;
+      char *filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
+                                       capture_path, shProg->Name);
+      file = fopen(filename, "w");
+      if (file) {
+         fprintf(file, "[require]\nGLSL%s >= %u.%02u\n",
+                 shProg->IsES ? " ES" : "",
+                 shProg->Version / 100, shProg->Version % 100);
+         if (shProg->SeparateShader)
+            fprintf(file, "GL_ARB_separate_shader_objects\nSSO ENABLED\n");
+         fprintf(file, "\n");
+
+         for (unsigned i = 0; i < shProg->NumShaders; i++) {
+            fprintf(file, "[%s shader]\n%s\n",
+                    _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
+                    shProg->Shaders[i]->Source);
+         }
+         fclose(file);
+      } else {
+         _mesa_warning(ctx, "Failed to open %s", filename);
+      }
+
+      ralloc_free(filename);
+   }
+
    if (shProg->LinkStatus == GL_FALSE &&
        (ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
       _mesa_debug(ctx, "Error linking program %u:\n%s\n",
@@ -1054,9 +1128,9 @@ link_program(struct gl_context *ctx, GLuint program)
                    shProg->LinkStatus ? "Success" : "Failed");
 
       for (i = 0; i < shProg->NumShaders; i++) {
-         printf(" shader %u, type 0x%x\n",
+         printf(" shader %u, stage %u\n",
                       shProg->Shaders[i]->Name,
-                      shProg->Shaders[i]->Type);
+                      shProg->Shaders[i]->Stage);
       }
    }
 }
@@ -1125,6 +1199,9 @@ use_shader_program(struct gl_context *ctx, gl_shader_stage stage,
    if ((shProg != NULL) && (shProg->_LinkedShaders[stage] == NULL))
       shProg = NULL;
 
+   if (shProg)
+      _mesa_shader_program_init_subroutine_defaults(ctx, shProg);
+
    if (*target != shProg) {
       /* Program is current, flush it */
       if (shTarget == ctx->_Shader) {
@@ -1168,10 +1245,6 @@ _mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
    for (i = 0; i < MESA_SHADER_STAGES; i++)
       use_shader_program(ctx, i, shProg, &ctx->Shader);
    _mesa_active_program(ctx, shProg, "glUseProgram");
-
-   _mesa_shader_program_init_subroutine_defaults(shProg);
-   if (ctx->Driver.UseProgram)
-      ctx->Driver.UseProgram(ctx, shProg);
 }
 
 
@@ -1257,12 +1330,13 @@ _mesa_AttachShader(GLuint program, GLuint shader)
 
 
 void GLAPIENTRY
-_mesa_CompileShader(GLhandleARB shaderObj)
+_mesa_CompileShader(GLuint shaderObj)
 {
    GET_CURRENT_CONTEXT(ctx);
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glCompileShader %u\n", shaderObj);
-   compile_shader(ctx, shaderObj);
+   _mesa_compile_shader(ctx, _mesa_lookup_shader_err(ctx, shaderObj,
+                                                     "glCompileShader"));
 }
 
 
@@ -1307,7 +1381,7 @@ _mesa_DeleteObjectARB(GLhandleARB obj)
 {
    if (MESA_VERBOSE & VERBOSE_API) {
       GET_CURRENT_CONTEXT(ctx);
-      _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj);
+      _mesa_debug(ctx, "glDeleteObjectARB(%lu)\n", (unsigned long)obj);
    }
 
    if (obj) {
@@ -1471,8 +1545,8 @@ _mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
 
 
 void GLAPIENTRY
-_mesa_GetShaderSource(GLhandleARB shader, GLsizei maxLength,
-                         GLsizei *length, GLcharARB *sourceOut)
+_mesa_GetShaderSource(GLuint shader, GLsizei maxLength,
+                      GLsizei *length, GLchar *sourceOut)
 {
    GET_CURRENT_CONTEXT(ctx);
    get_shader_source(ctx, shader, maxLength, length, sourceOut);
@@ -1504,10 +1578,13 @@ _mesa_IsShader(GLuint name)
 
 
 void GLAPIENTRY
-_mesa_LinkProgram(GLhandleARB programObj)
+_mesa_LinkProgram(GLuint programObj)
 {
    GET_CURRENT_CONTEXT(ctx);
-   link_program(ctx, programObj);
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glLinkProgram %u\n", programObj);
+   _mesa_link_program(ctx, _mesa_lookup_shader_program_err(ctx, programObj,
+                                                           "glLinkProgram"));
 }
 
 #if defined(HAVE_SHA1)
@@ -1528,9 +1605,9 @@ generate_sha1(const char *source, char sha_str[64])
  *
  * <path>/<stage prefix>_<CHECKSUM>.glsl
  */
-static void
+static char *
 construct_name(const gl_shader_stage stage, const char *source,
-               const char *path, char *name, unsigned length)
+               const char *path)
 {
    char sha[64];
    static const char *types[] = {
@@ -1538,8 +1615,7 @@ construct_name(const gl_shader_stage stage, const char *source,
    };
 
    generate_sha1(source, sha);
-   _mesa_snprintf(name, length, "%s/%s_%s.glsl", path, types[stage],
-                  sha);
+   return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha);
 }
 
 /**
@@ -1548,7 +1624,6 @@ construct_name(const gl_shader_stage stage, const char *source,
 static void
 dump_shader(const gl_shader_stage stage, const char *source)
 {
-   char name[PATH_MAX];
    static bool path_exists = true;
    char *dump_path;
    FILE *f;
@@ -1562,7 +1637,7 @@ dump_shader(const gl_shader_stage stage, const char *source)
       return;
    }
 
-   construct_name(stage, source, dump_path, name, PATH_MAX);
+   char *name = construct_name(stage, source, dump_path);
 
    f = fopen(name, "w");
    if (f) {
@@ -1573,6 +1648,7 @@ dump_shader(const gl_shader_stage stage, const char *source)
       _mesa_warning(ctx, "could not open %s for dumping shader (%s)", name,
                     strerror(errno));
    }
+   ralloc_free(name);
 }
 
 /**
@@ -1582,7 +1658,6 @@ dump_shader(const gl_shader_stage stage, const char *source)
 static GLcharARB *
 read_shader(const gl_shader_stage stage, const char *source)
 {
-   char name[PATH_MAX];
    char *read_path;
    static bool path_exists = true;
    int len, shader_size = 0;
@@ -1598,9 +1673,9 @@ read_shader(const gl_shader_stage stage, const char *source)
       return NULL;
    }
 
-   construct_name(stage, source, read_path, name, PATH_MAX);
-
+   char *name = construct_name(stage, source, read_path);
    f = fopen(name, "r");
+   ralloc_free(name);
    if (!f)
       return NULL;
 
@@ -1631,20 +1706,24 @@ read_shader(const gl_shader_stage stage, const char *source)
  * and pass it to _mesa_shader_source().
  */
 void GLAPIENTRY
-_mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
-                   const GLcharARB * const * string, const GLint * length)
+_mesa_ShaderSource(GLuint shaderObj, GLsizei count,
+                   const GLchar * const * string, const GLint * length)
 {
    GET_CURRENT_CONTEXT(ctx);
    GLint *offsets;
    GLsizei i, totalLength;
    GLcharARB *source;
+   struct gl_shader *sh;
 
 #if defined(HAVE_SHA1)
    GLcharARB *replacement;
-   struct gl_shader *sh;
 #endif /* HAVE_SHA1 */
 
-   if (!shaderObj || string == NULL) {
+   sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB");
+   if (!sh)
+      return;
+
+   if (string == NULL) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
       return;
    }
@@ -1696,8 +1775,6 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
    source[totalLength - 2] = '\0';
 
 #if defined(HAVE_SHA1)
-   sh = _mesa_lookup_shader(ctx, shaderObj);
-
    /* Dump original shader source to MESA_SHADER_DUMP_PATH and replace
     * if corresponding entry found from MESA_SHADER_READ_PATH.
     */
@@ -1710,18 +1787,21 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
    }
 #endif /* HAVE_SHA1 */
 
-   shader_source(ctx, shaderObj, source);
+   shader_source(sh, source);
 
    free(offsets);
 }
 
 
 void GLAPIENTRY
-_mesa_UseProgram(GLhandleARB program)
+_mesa_UseProgram(GLuint program)
 {
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg;
 
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glUseProgram %u\n", program);
+
    if (_mesa_is_xfb_active_and_unpaused(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glUseProgram(transform feedback active)");
@@ -1776,7 +1856,7 @@ _mesa_UseProgram(GLhandleARB program)
 
 
 void GLAPIENTRY
-_mesa_ValidateProgram(GLhandleARB program)
+_mesa_ValidateProgram(GLuint program)
 {
    GET_CURRENT_CONTEXT(ctx);
    validate_program(ctx, program);
@@ -2052,63 +2132,66 @@ _mesa_use_shader_program(struct gl_context *ctx, GLenum type,
 {
    gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
    use_shader_program(ctx, stage, shProg, shTarget);
-
-   if (ctx->Driver.UseProgram)
-      ctx->Driver.UseProgram(ctx, shProg);
 }
 
 
 /**
  * Copy program-specific data generated by linking from the gl_shader_program
- * object to a specific gl_program object.
+ * object to the gl_program object referred to by the gl_linked_shader.
+ *
+ * This function expects _mesa_reference_program() to have been previously
+ * called setting the gl_linked_shaders program reference.
  */
 void
-_mesa_copy_linked_program_data(gl_shader_stage type,
-                               const struct gl_shader_program *src,
-                               struct gl_program *dst)
+_mesa_copy_linked_program_data(const struct gl_shader_program *src,
+                               struct gl_linked_shader *dst_sh)
 {
-   switch (type) {
+   assert(dst_sh->Program);
+
+   struct gl_program *dst = dst_sh->Program;
+
+   dst->info.num_abos = dst_sh->NumAtomicBuffers;
+   dst->info.num_images = dst_sh->NumImages;
+
+   switch (dst_sh->Stage) {
    case MESA_SHADER_VERTEX:
-      dst->UsesClipDistanceOut = src->Vert.UsesClipDistance;
+      dst->ClipDistanceArraySize = src->Vert.ClipDistanceArraySize;
+      dst->CullDistanceArraySize = src->Vert.CullDistanceArraySize;
       break;
    case MESA_SHADER_TESS_CTRL: {
-      struct gl_tess_ctrl_program *dst_tcp =
-         (struct gl_tess_ctrl_program *) dst;
-      dst_tcp->VerticesOut = src->TessCtrl.VerticesOut;
+      dst->info.tcs.vertices_out = dst_sh->info.TessCtrl.VerticesOut;
       break;
    }
    case MESA_SHADER_TESS_EVAL: {
-      struct gl_tess_eval_program *dst_tep =
-         (struct gl_tess_eval_program *) dst;
-      dst_tep->PrimitiveMode = src->TessEval.PrimitiveMode;
-      dst_tep->Spacing = src->TessEval.Spacing;
-      dst_tep->VertexOrder = src->TessEval.VertexOrder;
-      dst_tep->PointMode = src->TessEval.PointMode;
-      dst->UsesClipDistanceOut = src->TessEval.UsesClipDistance;
+      dst->info.tes.primitive_mode = dst_sh->info.TessEval.PrimitiveMode;
+      dst->info.tes.spacing = dst_sh->info.TessEval.Spacing;
+      dst->info.tes.vertex_order = dst_sh->info.TessEval.VertexOrder;
+      dst->info.tes.point_mode = dst_sh->info.TessEval.PointMode;
+      dst->ClipDistanceArraySize = src->TessEval.ClipDistanceArraySize;
+      dst->CullDistanceArraySize = src->TessEval.CullDistanceArraySize;
       break;
    }
    case MESA_SHADER_GEOMETRY: {
-      struct gl_geometry_program *dst_gp = (struct gl_geometry_program *) dst;
-      dst_gp->VerticesIn = src->Geom.VerticesIn;
-      dst_gp->VerticesOut = src->Geom.VerticesOut;
-      dst_gp->Invocations = src->Geom.Invocations;
-      dst_gp->InputType = src->Geom.InputType;
-      dst_gp->OutputType = src->Geom.OutputType;
-      dst->UsesClipDistanceOut = src->Geom.UsesClipDistance;
-      dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
-      dst_gp->UsesStreams = src->Geom.UsesStreams;
+      dst->info.gs.vertices_in = src->Geom.VerticesIn;
+      dst->info.gs.vertices_out = dst_sh->info.Geom.VerticesOut;
+      dst->info.gs.invocations = dst_sh->info.Geom.Invocations;
+      dst->info.gs.input_primitive = dst_sh->info.Geom.InputType;
+      dst->info.gs.output_primitive = dst_sh->info.Geom.OutputType;
+      dst->ClipDistanceArraySize = src->Geom.ClipDistanceArraySize;
+      dst->CullDistanceArraySize = src->Geom.CullDistanceArraySize;
+      dst->info.gs.uses_end_primitive = src->Geom.UsesEndPrimitive;
+      dst->info.gs.uses_streams = src->Geom.UsesStreams;
       break;
    }
    case MESA_SHADER_FRAGMENT: {
-      struct gl_fragment_program *dst_fp = (struct gl_fragment_program *) dst;
-      dst_fp->FragDepthLayout = src->FragDepthLayout;
+      dst->info.fs.depth_layout = src->FragDepthLayout;
+      dst->info.fs.early_fragment_tests = dst_sh->info.EarlyFragmentTests;
       break;
    }
    case MESA_SHADER_COMPUTE: {
-      struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst;
-      int i;
-      for (i = 0; i < 3; i++)
-         dst_cp->LocalSize[i] = src->Comp.LocalSize[i];
+      for (int i = 0; i < 3; i++)
+         dst->info.cs.local_size[i] = src->Comp.LocalSize[i];
+      dst->info.cs.shared_size = src->Comp.SharedSize;
       break;
    }
    default:
@@ -2138,25 +2221,24 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count,
    }
 
    if (shader) {
-      _mesa_ShaderSource(shader, count, strings, NULL);
+      struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
 
-      compile_shader(ctx, shader);
+      _mesa_ShaderSource(shader, count, strings, NULL);
+      _mesa_compile_shader(ctx, sh);
 
       program = create_shader_program(ctx);
       if (program) {
         struct gl_shader_program *shProg;
-        struct gl_shader *sh;
         GLint compiled = GL_FALSE;
 
         shProg = _mesa_lookup_shader_program(ctx, program);
-        sh = _mesa_lookup_shader(ctx, shader);
 
         shProg->SeparateShader = GL_TRUE;
 
         get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
         if (compiled) {
            attach_shader(ctx, program, shader);
-           link_program(ctx, program);
+           _mesa_link_program(ctx, shProg);
            detach_shader(ctx, program, shader);
 
 #if 0
@@ -2247,7 +2329,7 @@ _mesa_GetSubroutineUniformLocation(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return -1;
    }
@@ -2282,7 +2364,7 @@ _mesa_GetSubroutineIndex(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return -1;
    }
@@ -2305,7 +2387,6 @@ _mesa_GetSubroutineIndex(GLuint program, GLenum shadertype,
    resource_type = _mesa_shader_stage_to_subroutine(stage);
    res = _mesa_program_resource_find_name(shProg, resource_type, name, NULL);
    if (!res) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
      return -1;
    }
 
@@ -2320,14 +2401,14 @@ _mesa_GetActiveSubroutineUniformiv(GLuint program, GLenum shadertype,
    GET_CURRENT_CONTEXT(ctx);
    const char *api_name = "glGetActiveSubroutineUniformiv";
    struct gl_shader_program *shProg;
-   struct gl_shader *sh;
+   struct gl_linked_shader *sh;
    gl_shader_stage stage;
    struct gl_program_resource *res;
    const struct gl_uniform_storage *uni;
    GLenum resource_type;
    int count, i, j;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
    }
@@ -2350,6 +2431,11 @@ _mesa_GetActiveSubroutineUniformiv(GLuint program, GLenum shadertype,
       return;
    }
 
+   if (index >= sh->NumSubroutineUniforms) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s: invalid index greater than GL_ACTIVE_SUBROUTINE_UNIFORMS", api_name);
+      return;
+   }
+
    switch (pname) {
    case GL_NUM_COMPATIBLE_SUBROUTINES: {
       res = _mesa_program_resource_find_index(shProg, resource_type, index);
@@ -2387,7 +2473,7 @@ _mesa_GetActiveSubroutineUniformiv(GLuint program, GLenum shadertype,
       res = _mesa_program_resource_find_index(shProg, resource_type, index);
       if (res) {
          values[0] = strlen(_mesa_program_resource_name(res)) + 1
-            + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);;
+            + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);
       }
       break;
    default:
@@ -2408,7 +2494,7 @@ _mesa_GetActiveSubroutineUniformName(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
    }
@@ -2447,7 +2533,7 @@ _mesa_GetActiveSubroutineName(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
    }
@@ -2472,7 +2558,6 @@ _mesa_GetActiveSubroutineName(GLuint program, GLenum shadertype,
                                    length, name, api_name);
 }
 
-
 GLvoid GLAPIENTRY
 _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
                             const GLuint *indices)
@@ -2480,11 +2565,11 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
    GET_CURRENT_CONTEXT(ctx);
    const char *api_name = "glUniformSubroutinesuiv";
    struct gl_shader_program *shProg;
-   struct gl_shader *sh;
+   struct gl_linked_shader *sh;
    gl_shader_stage stage;
    int i;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
    }
@@ -2515,17 +2600,30 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
    i = 0;
    do {
       struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
+      if (uni == NULL) {
+         i++;
+         continue;
+      }
+
       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;
@@ -2534,23 +2632,13 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
             _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
             return;
          }
+
+         ctx->SubroutineIndex[sh->Stage].IndexPtr[j] = indices[j];
       }
       i += uni_count;
    } while(i < count);
 
    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
-   i = 0;
-   do {
-      struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
-      int uni_count = uni->array_elements ? uni->array_elements : 1;
-
-      memcpy(&uni->storage[0], &indices[i],
-             sizeof(GLuint) * uni_count);
-
-      uni->initialized = true;
-      _mesa_propagate_uniforms_to_driver_storage(uni, 0, uni_count);
-      i += uni_count;
-   } while(i < count);
 }
 
 
@@ -2561,10 +2649,10 @@ _mesa_GetUniformSubroutineuiv(GLenum shadertype, GLint location,
    GET_CURRENT_CONTEXT(ctx);
    const char *api_name = "glGetUniformSubroutineuiv";
    struct gl_shader_program *shProg;
-   struct gl_shader *sh;
+   struct gl_linked_shader *sh;
    gl_shader_stage stage;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
    }
@@ -2592,12 +2680,7 @@ _mesa_GetUniformSubroutineuiv(GLenum shadertype, GLint location,
       return;
    }
 
-   {
-      struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[location];
-      int offset = location - uni->subroutine[stage].index;
-      memcpy(params, &uni->storage[offset],
-            sizeof(GLuint));
-   }
+   *params = ctx->SubroutineIndex[sh->Stage].IndexPtr[location];
 }
 
 
@@ -2608,10 +2691,10 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype,
    GET_CURRENT_CONTEXT(ctx);
    const char *api_name = "glGetProgramStageiv";
    struct gl_shader_program *shProg;
-   struct gl_shader *sh;
+   struct gl_linked_shader *sh;
    gl_shader_stage stage;
 
-   if (!_mesa_has_shader_subroutine(ctx)) {
+   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
    }
@@ -2627,8 +2710,25 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype,
 
    stage = _mesa_shader_enum_to_shader_stage(shadertype);
    sh = shProg->_LinkedShaders[stage];
+
+   /* ARB_shader_subroutine doesn't ask the program to be linked, or list any
+    * INVALID_OPERATION in the case of not be linked.
+    *
+    * And for some pnames, like GL_ACTIVE_SUBROUTINE_UNIFORMS, you can ask the
+    * same info using other specs (ARB_program_interface_query), without the
+    * need of the program to be linked, being the value for that case 0.
+    *
+    * But at the same time, some other methods require the program to be
+    * linked for pname related to locations, so it would be inconsistent to
+    * not do the same here. So we are:
+    *   * Return GL_INVALID_OPERATION if not linked only for locations.
+    *   * Setting a default value of 0, to be returned if not linked.
+    */
    if (!sh) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+      values[0] = 0;
+      if (pname == GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+      }
       return;
    }
 
@@ -2640,7 +2740,7 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype,
       values[0] = sh->NumSubroutineUniformRemapTable;
       break;
    case GL_ACTIVE_SUBROUTINE_UNIFORMS:
-      values[0] = sh->NumSubroutineUniformTypes;
+      values[0] = sh->NumSubroutineUniforms;
       break;
    case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
    {
@@ -2690,7 +2790,8 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype,
 }
 
 static int
-find_compat_subroutine(struct gl_shader *sh, const struct glsl_type *type)
+find_compat_subroutine(struct gl_linked_shader *sh,
+                       const struct glsl_type *type)
 {
    int i, j;
 
@@ -2705,29 +2806,71 @@ find_compat_subroutine(struct gl_shader *sh, const struct glsl_type *type)
 }
 
 static void
-_mesa_shader_init_subroutine_defaults(struct gl_shader *sh)
+_mesa_shader_write_subroutine_index(struct gl_context *ctx,
+                                    struct gl_linked_shader *sh)
 {
    int i, j;
 
-   for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
+   if (sh->NumSubroutineUniformRemapTable == 0)
+      return;
+
+   i = 0;
+   do {
       struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
       int uni_count;
       int val;
 
-      if (!uni)
+      if (!uni) {
+         i++;
          continue;
-      uni_count = uni->array_elements ? uni->array_elements : 1;
-      val = find_compat_subroutine(sh, uni->type);
+      }
 
-      for (j = 0; j < uni_count; j++)
+      uni_count = uni->array_elements ? uni->array_elements : 1;
+      for (j = 0; j < uni_count; j++) {
+         val = ctx->SubroutineIndex[sh->Stage].IndexPtr[i + j];
          memcpy(&uni->storage[j], &val, sizeof(int));
-      uni->initialized = true;
+      }
+
       _mesa_propagate_uniforms_to_driver_storage(uni, 0, uni_count);
+      i += uni_count;
+   } while(i < sh->NumSubroutineUniformRemapTable);
+}
+
+void
+_mesa_shader_write_subroutine_indices(struct gl_context *ctx,
+                                      gl_shader_stage stage)
+{
+   if (ctx->_Shader->CurrentProgram[stage] &&
+       ctx->_Shader->CurrentProgram[stage]->_LinkedShaders[stage])
+      _mesa_shader_write_subroutine_index(ctx,
+                                          ctx->_Shader->CurrentProgram[stage]->_LinkedShaders[stage]);
+}
+
+static void
+_mesa_shader_init_subroutine_defaults(struct gl_context *ctx,
+                                      struct gl_linked_shader *sh)
+{
+   int i;
+   struct gl_subroutine_index_binding *binding = &ctx->SubroutineIndex[sh->Stage];
+   if (binding->NumIndex != sh->NumSubroutineUniformRemapTable) {
+      binding->IndexPtr = realloc(binding->IndexPtr,
+                                  sh->NumSubroutineUniformRemapTable * (sizeof(GLuint)));
+      binding->NumIndex = sh->NumSubroutineUniformRemapTable;
+   }
+
+   for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
+      struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
+
+      if (!uni)
+         continue;
+
+      binding->IndexPtr[i] = find_compat_subroutine(sh, uni->type);
    }
 }
 
 void
-_mesa_shader_program_init_subroutine_defaults(struct gl_shader_program *shProg)
+_mesa_shader_program_init_subroutine_defaults(struct gl_context *ctx,
+                                              struct gl_shader_program *shProg)
 {
    int i;
 
@@ -2738,6 +2881,6 @@ _mesa_shader_program_init_subroutine_defaults(struct gl_shader_program *shProg)
       if (!shProg->_LinkedShaders[i])
          continue;
 
-      _mesa_shader_init_subroutine_defaults(shProg->_LinkedShaders[i]);
+      _mesa_shader_init_subroutine_defaults(ctx, shProg->_LinkedShaders[i]);
    }
 }