mesa: add shader_storage_block_binding() helper
[mesa.git] / src / mesa / main / shaderapi.c
index f63215a07be5cfbf66be9cd1dcbcacdd9031d1d8..0e46a09e7db1a5d74f06ed3dea93e7e48e554928 100644 (file)
@@ -77,6 +77,8 @@ _mesa_get_shader_flags(void)
          flags |= GLSL_DUMP;
       if (strstr(env, "log"))
          flags |= GLSL_LOG;
+      if (strstr(env, "cache_fb"))
+         flags |= GLSL_CACHE_FALLBACK;
       if (strstr(env, "cache_info"))
          flags |= GLSL_CACHE_INFO;
       if (strstr(env, "nopvert"))
@@ -242,7 +244,27 @@ is_shader(struct gl_context *ctx, GLuint name)
  * Attach shader to a shader program.
  */
 static void
-attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
+attach_shader(struct gl_context *ctx, struct gl_shader_program *shProg,
+              struct gl_shader *sh)
+{
+   GLuint n = shProg->NumShaders;
+
+   shProg->Shaders = realloc(shProg->Shaders,
+                             (n + 1) * sizeof(struct gl_shader *));
+   if (!shProg->Shaders) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
+      return;
+   }
+
+   /* append */
+   shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
+   _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
+   shProg->NumShaders++;
+}
+
+static void
+attach_shader_err(struct gl_context *ctx, GLuint program, GLuint shader,
+                  const char *caller)
 {
    struct gl_shader_program *shProg;
    struct gl_shader *sh;
@@ -250,11 +272,11 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
 
    const bool same_type_disallowed = _mesa_is_gles(ctx);
 
-   shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
+   shProg = _mesa_lookup_shader_program_err(ctx, program, caller);
    if (!shProg)
       return;
 
-   sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
+   sh = _mesa_lookup_shader_err(ctx, shader, caller);
    if (!sh) {
       return;
    }
@@ -268,7 +290,7 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
           *     "The error INVALID_OPERATION is generated by AttachObjectARB
           *     if <obj> is already attached to <containerObj>."
           */
-         _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
+         _mesa_error(ctx, GL_INVALID_OPERATION, caller);
          return;
       } else if (same_type_disallowed &&
                  shProg->Shaders[i]->Stage == sh->Stage) {
@@ -280,25 +302,25 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
          *      is generated if [...] another shader object of the same type
          *      as shader is already attached to program."
          */
-         _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
+         _mesa_error(ctx, GL_INVALID_OPERATION, caller);
          return;
       }
    }
 
-   /* grow list */
-   shProg->Shaders = realloc(shProg->Shaders,
-                             (n + 1) * sizeof(struct gl_shader *));
-   if (!shProg->Shaders) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
-      return;
-   }
-
-   /* append */
-   shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
-   _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
-   shProg->NumShaders++;
+   attach_shader(ctx, shProg, sh);
 }
 
+static void
+attach_shader_no_error(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+   struct gl_shader_program *shProg;
+   struct gl_shader *sh;
+
+   shProg = _mesa_lookup_shader_program(ctx, program);
+   sh = _mesa_lookup_shader(ctx, shader);
+
+   attach_shader(ctx, shProg, sh);
+}
 
 static GLuint
 create_shader(struct gl_context *ctx, GLenum type)
@@ -306,12 +328,6 @@ create_shader(struct gl_context *ctx, GLenum type)
    struct gl_shader *sh;
    GLuint name;
 
-   if (!_mesa_validate_shader_target(ctx, 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 = _mesa_new_shader(name, _mesa_shader_enum_to_shader_stage(type));
@@ -323,6 +339,19 @@ create_shader(struct gl_context *ctx, GLenum type)
 }
 
 
+static GLuint
+create_shader_err(struct gl_context *ctx, GLenum type, const char *caller)
+{
+   if (!_mesa_validate_shader_target(ctx, type)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)",
+                  caller, _mesa_enum_to_string(type));
+      return 0;
+   }
+
+   return create_shader(ctx, type);
+}
+
+
 static GLuint
 create_shader_program(struct gl_context *ctx)
 {
@@ -1323,12 +1352,27 @@ validate_program(struct gl_context *ctx, GLuint program)
 }
 
 
+void GLAPIENTRY
+_mesa_AttachObjectARB_no_error(GLhandleARB program, GLhandleARB shader)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   attach_shader_no_error(ctx, program, shader);
+}
+
 
 void GLAPIENTRY
 _mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader)
 {
    GET_CURRENT_CONTEXT(ctx);
-   attach_shader(ctx, program, shader);
+   attach_shader_err(ctx, program, shader, "glAttachObjectARB");
+}
+
+
+void GLAPIENTRY
+_mesa_AttachShader_no_error(GLuint program, GLuint shader)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   attach_shader_no_error(ctx, program, shader);
 }
 
 
@@ -1336,7 +1380,7 @@ void GLAPIENTRY
 _mesa_AttachShader(GLuint program, GLuint shader)
 {
    GET_CURRENT_CONTEXT(ctx);
-   attach_shader(ctx, program, shader);
+   attach_shader_err(ctx, program, shader, "glAttachShader");
 }
 
 
@@ -1351,12 +1395,30 @@ _mesa_CompileShader(GLuint shaderObj)
 }
 
 
+GLuint GLAPIENTRY
+_mesa_CreateShader_no_error(GLenum type)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   return create_shader(ctx, type);
+}
+
+
 GLuint GLAPIENTRY
 _mesa_CreateShader(GLenum type)
 {
    GET_CURRENT_CONTEXT(ctx);
+
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glCreateShader %s\n", _mesa_enum_to_string(type));
+
+   return create_shader_err(ctx, type, "glCreateShader");
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateShaderObjectARB_no_error(GLenum type)
+{
+   GET_CURRENT_CONTEXT(ctx);
    return create_shader(ctx, type);
 }
 
@@ -1365,7 +1427,7 @@ GLhandleARB GLAPIENTRY
 _mesa_CreateShaderObjectARB(GLenum type)
 {
    GET_CURRENT_CONTEXT(ctx);
-   return create_shader(ctx, type);
+   return create_shader_err(ctx, type, "glCreateShaderObjectARB");
 }
 
 
@@ -1803,8 +1865,8 @@ _mesa_ShaderSource(GLuint shaderObj, GLsizei count,
 }
 
 
-void GLAPIENTRY
-_mesa_UseProgram(GLuint program)
+static ALWAYS_INLINE void
+use_program(GLuint program, bool no_error)
 {
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg = NULL;
@@ -1812,26 +1874,33 @@ _mesa_UseProgram(GLuint program)
    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)");
-      return;
-   }
-
-   if (program) {
-      shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
-      if (!shProg) {
-         return;
+   if (no_error) {
+      if (program) {
+         shProg = _mesa_lookup_shader_program(ctx, program);
       }
-      if (!shProg->data->LinkStatus) {
+   } else {
+      if (_mesa_is_xfb_active_and_unpaused(ctx)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glUseProgram(program %u not linked)", program);
+                     "glUseProgram(transform feedback active)");
          return;
       }
 
-      /* debug code */
-      if (ctx->_Shader->Flags & GLSL_USE_PROG) {
-         print_shader_info(shProg);
+      if (program) {
+         shProg =
+            _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
+         if (!shProg)
+            return;
+
+         if (!shProg->data->LinkStatus) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glUseProgram(program %u not linked)", program);
+            return;
+         }
+
+         /* debug code */
+         if (ctx->_Shader->Flags & GLSL_USE_PROG) {
+            print_shader_info(shProg);
+         }
       }
    }
 
@@ -1844,7 +1913,7 @@ _mesa_UseProgram(GLuint program)
     *     object (section 2.14.PPO), the program bound to the appropriate
     *     stage of the pipeline object is considered current."
     */
-   if (program) {
+   if (shProg) {
       /* Attach shader state to the binding point */
       _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
       /* Update the program */
@@ -1853,15 +1922,33 @@ _mesa_UseProgram(GLuint program)
       /* Must be done first: detach the progam */
       _mesa_use_shader_program(ctx, shProg);
       /* Unattach shader_state binding point */
-      _mesa_reference_pipeline_object(ctx, &ctx->_Shader, ctx->Pipeline.Default);
+      _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+                                      ctx->Pipeline.Default);
       /* If a pipeline was bound, rebind it */
       if (ctx->Pipeline.Current) {
-         _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name);
+         if (no_error)
+            _mesa_BindProgramPipeline_no_error(ctx->Pipeline.Current->Name);
+         else
+            _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name);
       }
    }
 }
 
 
+void GLAPIENTRY
+_mesa_UseProgram_no_error(GLuint program)
+{
+   use_program(program, true);
+}
+
+
+void GLAPIENTRY
+_mesa_UseProgram(GLuint program)
+{
+   use_program(program, false);
+}
+
+
 void GLAPIENTRY
 _mesa_ValidateProgram(GLuint program)
 {
@@ -2206,7 +2293,7 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count,
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   const GLuint shader = create_shader(ctx, type);
+   const GLuint shader = create_shader_err(ctx, type, "glCreateShaderProgramv");
    GLuint program = 0;
 
    /*
@@ -2235,7 +2322,7 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count,
 
         get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
         if (compiled) {
-           attach_shader(ctx, program, shader);
+           attach_shader_err(ctx, program, shader, "glCreateShaderProgramv");
            _mesa_link_program(ctx, shProg);
            detach_shader(ctx, program, shader);
 
@@ -2327,11 +2414,6 @@ _mesa_GetSubroutineUniformLocation(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return -1;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return -1;
@@ -2362,11 +2444,6 @@ _mesa_GetSubroutineIndex(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return -1;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return -1;
@@ -2406,11 +2483,6 @@ _mesa_GetActiveSubroutineUniformiv(GLuint program, GLenum shadertype,
    GLenum resource_type;
    int count, i, j;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
@@ -2493,11 +2565,6 @@ _mesa_GetActiveSubroutineUniformName(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
@@ -2532,11 +2599,6 @@ _mesa_GetActiveSubroutineName(GLuint program, GLenum shadertype,
    GLenum resource_type;
    gl_shader_stage stage;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
@@ -2566,11 +2628,6 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
    gl_shader_stage stage;
    int i;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
@@ -2589,6 +2646,7 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
    }
 
    i = 0;
+   bool flushed = false;
    do {
       struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i];
       if (uni == NULL) {
@@ -2596,6 +2654,11 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
          continue;
       }
 
+      if (!flushed) {
+         _mesa_flush_vertices_for_uniforms(ctx, uni);
+         flushed = true;
+      }
+
       int uni_count = uni->array_elements ? uni->array_elements : 1;
       int j, k, f;
 
@@ -2628,8 +2691,6 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
       }
       i += uni_count;
    } while(i < count);
-
-   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
 }
 
 
@@ -2641,11 +2702,6 @@ _mesa_GetUniformSubroutineuiv(GLenum shadertype, GLint location,
    const char *api_name = "glGetUniformSubroutineuiv";
    gl_shader_stage stage;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;
@@ -2677,11 +2733,6 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype,
    struct gl_linked_shader *sh;
    gl_shader_stage stage;
 
-   if (!_mesa_has_ARB_shader_subroutine(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
-      return;
-   }
-
    if (!_mesa_validate_shader_target(ctx, shadertype)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
       return;