mesa/cs: Add a MESA_SHADER_COMPUTE stage and update switch statements.
[mesa.git] / src / mesa / main / shaderapi.c
index 4cc0357b1a4879b2d62e43a518845b0b9db1008d..519b200198100b1461acad2179e9d6beb774a2c8 100644 (file)
@@ -42,6 +42,7 @@
 #include "main/dispatch.h"
 #include "main/enums.h"
 #include "main/hash.h"
+#include "main/hash_table.h"
 #include "main/mtypes.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
@@ -71,7 +72,9 @@ get_shader_flags(void)
    const char *env = _mesa_getenv("MESA_GLSL");
 
    if (env) {
-      if (strstr(env, "dump"))
+      if (strstr(env, "dump_on_error"))
+         flags |= GLSL_DUMP_ON_ERROR;
+      else if (strstr(env, "dump"))
          flags |= GLSL_DUMP;
       if (strstr(env, "log"))
          flags |= GLSL_LOG;
@@ -105,7 +108,7 @@ _mesa_init_shader_state(struct gl_context *ctx)
     * are generated by the GLSL compiler.
     */
    struct gl_shader_compiler_options options;
-   gl_shader_type sh;
+   gl_shader_stage sh;
 
    memset(&options, 0, sizeof(options));
    options.MaxUnrollIterations = 32;
@@ -114,7 +117,7 @@ _mesa_init_shader_state(struct gl_context *ctx)
    /* Default pragma settings */
    options.DefaultPragmas.Optimize = GL_TRUE;
 
-   for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+   for (sh = 0; sh < MESA_SHADER_STAGES; ++sh)
       memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
 
    ctx->Shader.Flags = get_shader_flags();
@@ -127,11 +130,11 @@ _mesa_init_shader_state(struct gl_context *ctx)
 void
 _mesa_free_shader_state(struct gl_context *ctx)
 {
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
-                                 NULL);
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
-                                 NULL);
+   int i;
+   for (i = 0; i < MESA_SHADER_STAGES; i++) {
+      _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram[i],
+                                     NULL);
+   }
    _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
                                  NULL);
    _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
@@ -168,16 +171,25 @@ _mesa_copy_string(GLchar *dst, GLsizei maxLength,
  * \param type  Shader target
  *
  */
-static bool
-validate_shader_target(const struct gl_context *ctx, GLenum type)
-{
+bool
+_mesa_validate_shader_target(const struct gl_context *ctx, GLenum type)
+{
+   /* Note: when building built-in GLSL functions, this function may be
+    * invoked with ctx == NULL.  In that case, we can only validate that it's
+    * a shader target we recognize, not that it's supported in the current
+    * context.  But that's fine--we don't need any further validation than
+    * that when building built-in GLSL functions.
+    */
+
    switch (type) {
    case GL_FRAGMENT_SHADER:
-      return ctx->Extensions.ARB_fragment_shader;
+      return ctx == NULL || ctx->Extensions.ARB_fragment_shader;
    case GL_VERTEX_SHADER:
-      return ctx->Extensions.ARB_vertex_shader;
+      return ctx == NULL || ctx->Extensions.ARB_vertex_shader;
    case GL_GEOMETRY_SHADER_ARB:
-      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+      return ctx == NULL || _mesa_has_geometry_shaders(ctx);
+   case GL_COMPUTE_SHADER:
+      return ctx == NULL || ctx->Extensions.ARB_compute_shader;
    default:
       return false;
    }
@@ -270,7 +282,7 @@ create_shader(struct gl_context *ctx, GLenum type)
    struct gl_shader *sh;
    GLuint name;
 
-   if (!validate_shader_target(ctx, type)) {
+   if (!_mesa_validate_shader_target(ctx, type)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
       return 0;
    }
@@ -411,7 +423,7 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
          err = GL_INVALID_OPERATION;
       else
          err = GL_INVALID_VALUE;
-      _mesa_error(ctx, err, "glDetachProgram(shader)");
+      _mesa_error(ctx, err, "glDetachShader(shader)");
       return;
    }
 }
@@ -456,6 +468,31 @@ get_handle(struct gl_context *ctx, GLenum pname)
 }
 
 
+/**
+ * Check if a geometry shader query is valid at this time.  If not, report an
+ * error and return false.
+ *
+ * From GL 3.2 section 6.1.16 (Shader and Program Queries):
+ *
+ *     "If GEOMETRY_VERTICES_OUT, GEOMETRY_INPUT_TYPE, or GEOMETRY_OUTPUT_TYPE
+ *     are queried for a program which has not been linked successfully, or
+ *     which does not contain objects to form a geometry shader, then an
+ *     INVALID_OPERATION error is generated."
+ */
+static bool
+check_gs_query(struct gl_context *ctx, const struct gl_shader_program *shProg)
+{
+   if (shProg->LinkStatus &&
+       shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
+      return true;
+   }
+
+   _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glGetProgramv(linked geometry shader required)");
+   return false;
+}
+
+
 /**
  * glGetProgramiv() - get shader program state.
  * Note that this is for GLSL shader programs, not ARB vertex/fragment
@@ -474,10 +511,10 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
       || ctx->API == API_OPENGL_CORE
       || _mesa_is_gles3(ctx);
 
-   /* Are geometry shaders available in this context?
+   /* True if geometry shaders (of the form that was adopted into GLSL 1.50
+    * and GL 3.2) are available in this context
     */
-   const bool has_gs =
-      _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+   const bool has_core_gs = _mesa_is_desktop_gl(ctx) && ctx->Version >= 32;
 
    /* Are uniform buffer objects available in this context?
     */
@@ -562,20 +599,23 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
          break;
       *params = shProg->TransformFeedback.BufferMode;
       return;
-   case GL_GEOMETRY_VERTICES_OUT_ARB:
-      if (!has_gs)
+   case GL_GEOMETRY_VERTICES_OUT:
+      if (!has_core_gs)
          break;
-      *params = shProg->Geom.VerticesOut;
+      if (check_gs_query(ctx, shProg))
+         *params = shProg->Geom.VerticesOut;
       return;
-   case GL_GEOMETRY_INPUT_TYPE_ARB:
-      if (!has_gs)
+   case GL_GEOMETRY_INPUT_TYPE:
+      if (!has_core_gs)
          break;
-      *params = shProg->Geom.InputType;
+      if (check_gs_query(ctx, shProg))
+         *params = shProg->Geom.InputType;
       return;
-   case GL_GEOMETRY_OUTPUT_TYPE_ARB:
-      if (!has_gs)
+   case GL_GEOMETRY_OUTPUT_TYPE:
+      if (!has_core_gs)
          break;
-      *params = shProg->Geom.OutputType;
+      if (check_gs_query(ctx, shProg))
+         *params = shProg->Geom.OutputType;
       return;
    case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: {
       unsigned i;
@@ -617,6 +657,12 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
    case GL_PROGRAM_BINARY_LENGTH:
       *params = 0;
       return;
+   case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS:
+      if (!ctx->Extensions.ARB_shader_atomic_counters)
+         break;
+
+      *params = shProg->NumAtomicBuffers;
+      return;
    default:
       break;
    }
@@ -741,7 +787,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
    if (!sh)
       return;
 
-   options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
+   options = &ctx->ShaderCompilerOptions[sh->Stage];
 
    /* set default pragma state for shader */
    sh->Pragmas = options->DefaultPragmas;
@@ -754,7 +800,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
    } else {
       if (ctx->Shader.Flags & GLSL_DUMP) {
          printf("GLSL source for %s shader %d:\n",
-                _mesa_glsl_shader_target_name(sh->Type), sh->Name);
+                _mesa_shader_stage_to_string(sh->Stage), sh->Name);
          printf("%s\n", sh->Source);
       }
 
@@ -783,10 +829,19 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
 
    }
 
-   if (sh->CompileStatus == GL_FALSE && 
-       (ctx->Shader.Flags & GLSL_REPORT_ERRORS)) {
-      _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
-                  sh->Name, sh->InfoLog);
+   if (!sh->CompileStatus) {
+      if (ctx->Shader.Flags & GLSL_DUMP_ON_ERROR) {
+         fprintf(stderr, "GLSL source for %s shader %d:\n",
+                 _mesa_shader_stage_to_string(sh->Stage), sh->Name);
+         fprintf(stderr, "%s\n", sh->Source);
+         fprintf(stderr, "Info Log:\n%s\n", sh->InfoLog);
+         fflush(stderr);
+      }
+
+      if (ctx->Shader.Flags & GLSL_REPORT_ERRORS) {
+         _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
+                     sh->Name, sh->InfoLog);
+      }
    }
 }
 
@@ -798,19 +853,19 @@ static void
 link_program(struct gl_context *ctx, GLuint program)
 {
    struct gl_shader_program *shProg;
-   struct gl_transform_feedback_object *obj =
-      ctx->TransformFeedback.CurrentObject;
 
    shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
    if (!shProg)
       return;
 
-   if (obj->Active
-       && (shProg == ctx->Shader.CurrentVertexProgram
-          || shProg == ctx->Shader.CurrentGeometryProgram
-          || shProg == ctx->Shader.CurrentFragmentProgram)) {
+   /* From the ARB_transform_feedback2 specification:
+    * "The error INVALID_OPERATION is generated by LinkProgram if <program> is
+    *  the name of a program being used by one or more transform feedback
+    *  objects, even if the objects are not currently bound or are paused."
+    */
+   if (_mesa_transform_feedback_is_using_program(ctx, shProg)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glLinkProgram(transform feedback active)");
+                  "glLinkProgram(transform feedback is using the program)");
       return;
    }
 
@@ -852,7 +907,7 @@ print_shader_info(const struct gl_shader_program *shProg)
    printf("Mesa: glUseProgram(%u)\n", shProg->Name);
    for (i = 0; i < shProg->NumShaders; i++) {
       printf("  %s shader %u, checksum %u\n",
-             _mesa_glsl_shader_target_name(shProg->Shaders[i]->Type),
+             _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
             shProg->Shaders[i]->Name,
             shProg->Shaders[i]->SourceChecksum);
    }
@@ -888,37 +943,16 @@ _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
 
 /**
  */
-static bool
+static void
 use_shader_program(struct gl_context *ctx, GLenum type,
                   struct gl_shader_program *shProg)
 {
    struct gl_shader_program **target;
+   gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
 
-   switch (type) {
-   case GL_VERTEX_SHADER:
-      target = &ctx->Shader.CurrentVertexProgram;
-      if ((shProg == NULL)
-         || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
-        shProg = NULL;
-      }
-      break;
-   case GL_GEOMETRY_SHADER_ARB:
-      target = &ctx->Shader.CurrentGeometryProgram;
-      if ((shProg == NULL)
-         || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
-        shProg = NULL;
-      }
-      break;
-   case GL_FRAGMENT_SHADER:
-      target = &ctx->Shader.CurrentFragmentProgram;
-      if ((shProg == NULL)
-         || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
-        shProg = NULL;
-      }
-      break;
-   default:
-      return false;
-   }
+   target = &ctx->Shader.CurrentProgram[stage];
+   if ((shProg == NULL) || (shProg->_LinkedShaders[stage] == NULL))
+      shProg = NULL;
 
    if (*target != shProg) {
       FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
@@ -934,6 +968,9 @@ use_shader_program(struct gl_context *ctx, GLenum type,
       case GL_GEOMETRY_SHADER_ARB:
         /* Empty for now. */
         break;
+      case GL_COMPUTE_SHADER:
+         /* Empty for now. */
+         break;
       case GL_FRAGMENT_SHADER:
         if (*target == ctx->Shader._CurrentFragmentProgram) {
            _mesa_reference_shader_program(ctx,
@@ -944,10 +981,8 @@ use_shader_program(struct gl_context *ctx, GLenum type,
       }
 
       _mesa_reference_shader_program(ctx, target, shProg);
-      return true;
+      return;
    }
-
-   return false;
 }
 
 /**
@@ -1489,10 +1524,10 @@ _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
 
    switch (shadertype) {
    case GL_VERTEX_SHADER:
-      limits = &ctx->Const.VertexProgram;
+      limits = &ctx->Const.Program[MESA_SHADER_VERTEX];
       break;
    case GL_FRAGMENT_SHADER:
-      limits = &ctx->Const.FragmentProgram;
+      limits = &ctx->Const.Program[MESA_SHADER_FRAGMENT];
       break;
    default:
       _mesa_error(ctx, GL_INVALID_ENUM,
@@ -1622,55 +1657,6 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
       return;
 
    switch (pname) {
-   case GL_GEOMETRY_VERTICES_OUT_ARB:
-      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
-         break;
-
-      if (value < 1 ||
-          (unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
-                     value);
-         return;
-      }
-      shProg->Geom.VerticesOut = value;
-      return;
-   case GL_GEOMETRY_INPUT_TYPE_ARB:
-      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
-         break;
-
-      switch (value) {
-      case GL_POINTS:
-      case GL_LINES:
-      case GL_LINES_ADJACENCY_ARB:
-      case GL_TRIANGLES:
-      case GL_TRIANGLES_ADJACENCY_ARB:
-         shProg->Geom.InputType = value;
-         break;
-      default:
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glProgramParameteri(geometry input type = %s",
-                     _mesa_lookup_enum_by_nr(value));
-         return;
-      }
-      return;
-   case GL_GEOMETRY_OUTPUT_TYPE_ARB:
-      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
-         break;
-
-      switch (value) {
-      case GL_POINTS:
-      case GL_LINE_STRIP:
-      case GL_TRIANGLE_STRIP:
-         shProg->Geom.OutputType = value;
-         break;
-      default:
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glProgramParameteri(geometry output type = %s",
-                     _mesa_lookup_enum_by_nr(value));
-         return;
-      }
-      return;
    case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
       /* This enum isn't part of the OES extension for OpenGL ES 2.0, but it
        * is part of OpenGL ES 3.0.  For the ES2 case, this function shouldn't
@@ -1744,7 +1730,7 @@ _mesa_UseShaderProgramEXT(GLenum type, GLuint program)
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg = NULL;
 
-   if (!validate_shader_target(ctx, type)) {
+   if (!_mesa_validate_shader_target(ctx, type)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
       return;
    }
@@ -1834,3 +1820,32 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
 
    return program;
 }
+
+
+/**
+ * Copy program-specific data generated by linking from the gl_shader_program
+ * object to a specific gl_program object.
+ */
+void
+_mesa_copy_linked_program_data(gl_shader_stage type,
+                               const struct gl_shader_program *src,
+                               struct gl_program *dst)
+{
+   switch (type) {
+   case MESA_SHADER_VERTEX:
+      dst->UsesClipDistanceOut = src->Vert.UsesClipDistance;
+      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->InputType = src->Geom.InputType;
+      dst_gp->OutputType = src->Geom.OutputType;
+      dst->UsesClipDistanceOut = src->Geom.UsesClipDistance;
+      dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
+   }
+      break;
+   default:
+      break;
+   }
+}