main/shaderapi: GL_GEOMETRY_SHADER_INVOCATIONS GetProgramiv support
[mesa.git] / src / mesa / main / shaderapi.c
index 4c0484aaf0c9253eb13de5624a50d7425e633b75..bf138149087ac8a83f943d393a3f28b494081682 100644 (file)
@@ -108,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;
@@ -117,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();
@@ -130,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);
@@ -171,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_has_geometry_shaders(ctx);
+      return ctx == NULL || _mesa_has_geometry_shaders(ctx);
+   case GL_COMPUTE_SHADER:
+      return ctx == NULL || ctx->Extensions.ARB_compute_shader;
    default:
       return false;
    }
@@ -273,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;
    }
@@ -374,30 +383,31 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
          _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
 
          /* alloc new, smaller array */
-         newList =
-            malloc((n - 1) * sizeof(struct gl_shader *));
+         newList = malloc((n - 1) * sizeof(struct gl_shader *));
          if (!newList) {
             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
             return;
          }
+         /* Copy old list entries to new list, skipping removed entry at [i] */
          for (j = 0; j < i; j++) {
             newList[j] = shProg->Shaders[j];
          }
-         while (++i < n)
+         while (++i < n) {
             newList[j++] = shProg->Shaders[i];
-         free(shProg->Shaders);
+         }
 
+         /* Free old list and install new one */
+         free(shProg->Shaders);
          shProg->Shaders = newList;
          shProg->NumShaders = n - 1;
 
 #ifdef DEBUG
-         /* sanity check */
-         {
-            for (j = 0; j < shProg->NumShaders; j++) {
-               assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
-                      shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
-               assert(shProg->Shaders[j]->RefCount > 0);
-            }
+         /* 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_GEOMETRY_SHADER ||
+                   shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
+            assert(shProg->Shaders[j]->RefCount > 0);
          }
 #endif
 
@@ -414,7 +424,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;
    }
 }
@@ -459,6 +469,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
@@ -477,9 +512,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_has_geometry_shaders(ctx);
+   const bool has_core_gs = _mesa_is_desktop_gl(ctx) && ctx->Version >= 32;
 
    /* Are uniform buffer objects available in this context?
     */
@@ -564,20 +600,29 @@ 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;
+      if (check_gs_query(ctx, shProg))
+         *params = shProg->Geom.VerticesOut;
+      return;
+   case GL_GEOMETRY_SHADER_INVOCATIONS:
+      if (!has_core_gs || !ctx->Extensions.ARB_gpu_shader5)
          break;
-      *params = shProg->Geom.VerticesOut;
+      if (check_gs_query(ctx, shProg))
+         *params = shProg->Geom.Invocations;
       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;
@@ -619,6 +664,30 @@ 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;
+   case GL_COMPUTE_WORK_GROUP_SIZE: {
+      int i;
+      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_compute_shader)
+         break;
+      if (!shProg->LinkStatus) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(program not "
+                     "linked)");
+         return;
+      }
+      if (shProg->_LinkedShaders[MESA_SHADER_COMPUTE] == NULL) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(no compute "
+                     "shaders)");
+         return;
+      }
+      for (i = 0; i < 3; i++)
+         params[i] = shProg->Comp.LocalSize[i];
+      return;
+   }
    default:
       break;
    }
@@ -743,13 +812,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
    if (!sh)
       return;
 
-   /* Geometry shaders are not yet fully supported, so issue a warning message
-    * if we're compiling one.
-    */
-   if (sh->Type == GL_GEOMETRY_SHADER)
-      printf("WARNING: Geometry shader support is currently experimental.\n");
-
-   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;
@@ -762,7 +825,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);
       }
 
@@ -794,8 +857,10 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
    if (!sh->CompileStatus) {
       if (ctx->Shader.Flags & GLSL_DUMP_ON_ERROR) {
          fprintf(stderr, "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);
          fprintf(stderr, "%s\n", sh->Source);
+         fprintf(stderr, "Info Log:\n%s\n", sh->InfoLog);
+         fflush(stderr);
       }
 
       if (ctx->Shader.Flags & GLSL_REPORT_ERRORS) {
@@ -867,7 +932,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);
    }
@@ -903,37 +968,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);
@@ -949,6 +993,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,
@@ -959,10 +1006,8 @@ use_shader_program(struct gl_context *ctx, GLenum type,
       }
 
       _mesa_reference_shader_program(ctx, target, shProg);
-      return true;
+      return;
    }
-
-   return false;
 }
 
 /**
@@ -974,6 +1019,7 @@ _mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
    use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
    use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
    use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
+   use_shader_program(ctx, GL_COMPUTE_SHADER, shProg);
    _mesa_active_program(ctx, shProg, "glUseProgram");
 
    if (ctx->Driver.UseProgram)
@@ -1504,10 +1550,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,
@@ -1637,55 +1683,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 < 0 ||
-          (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
@@ -1759,7 +1756,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;
    }
@@ -1856,26 +1853,32 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
  * object to a specific gl_program object.
  */
 void
-_mesa_copy_linked_program_data(gl_shader_type type,
+_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: {
-      struct gl_vertex_program *dst_vp = (struct gl_vertex_program *) dst;
-      dst_vp->UsesClipDistance = src->Vert.UsesClipDistance;
-   }
+   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->Invocations = src->Geom.Invocations;
       dst_gp->InputType = src->Geom.InputType;
       dst_gp->OutputType = src->Geom.OutputType;
-      dst_gp->UsesClipDistance = src->Geom.UsesClipDistance;
+      dst->UsesClipDistanceOut = src->Geom.UsesClipDistance;
       dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
    }
       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];
+   }
+      break;
    default:
       break;
    }