main/shaderapi: GL_GEOMETRY_SHADER_INVOCATIONS GetProgramiv support
[mesa.git] / src / mesa / main / shaderapi.c
index 519b200198100b1461acad2179e9d6beb774a2c8..bf138149087ac8a83f943d393a3f28b494081682 100644 (file)
@@ -383,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
 
@@ -605,6 +606,12 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
       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;
+      if (check_gs_query(ctx, shProg))
+         *params = shProg->Geom.Invocations;
+      return;
    case GL_GEOMETRY_INPUT_TYPE:
       if (!has_core_gs)
          break;
@@ -663,6 +670,24 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
 
       *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;
    }
@@ -994,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)
@@ -1839,12 +1865,20 @@ _mesa_copy_linked_program_data(gl_shader_stage type,
       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;
    }
       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;
    }