mesa: Allow setting GL_TEXTURE_MAX_LEVEL to 0 with GL_TEXTURE_RECTANGLE.
[mesa.git] / src / mesa / main / shaderapi.c
index f981900f1b2f12c17316d1245b9b0cc97f85bfc1..1c8e6b4cf5bbaf1cec517db30b786270a2aaa3b1 100644 (file)
@@ -44,6 +44,7 @@
 #include "main/hash.h"
 #include "main/hash_table.h"
 #include "main/mtypes.h"
+#include "main/pipelineobj.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
 #include "main/transformfeedback.h"
@@ -124,7 +125,7 @@ _mesa_init_shader_state(struct gl_context *ctx)
 
    /* Extended for ARB_separate_shader_objects */
    ctx->Shader.RefCount = 1;
-   _glthread_INIT_MUTEX(ctx->Shader.Mutex);
+   mtx_init(&ctx->Shader.Mutex, mtx_plain);
 }
 
 
@@ -144,8 +145,10 @@ _mesa_free_shader_state(struct gl_context *ctx)
    _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
 
    /* Extended for ARB_separate_shader_objects */
+   _mesa_reference_pipeline_object(ctx, &ctx->_Shader, NULL);
+
    assert(ctx->Shader.RefCount == 1);
-   _glthread_DESTROY_MUTEX(ctx->Shader.Mutex);
+   mtx_destroy(&ctx->Shader.Mutex);
 }
 
 
@@ -465,8 +468,8 @@ static GLuint
 get_handle(struct gl_context *ctx, GLenum pname)
 {
    if (pname == GL_PROGRAM_OBJECT_ARB) {
-      if (ctx->Shader.ActiveProgram)
-         return ctx->Shader.ActiveProgram->Name;
+      if (ctx->_Shader->ActiveProgram)
+         return ctx->_Shader->ActiveProgram->Name;
       else
          return 0;
    }
@@ -837,10 +840,11 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
        */
       sh->CompileStatus = GL_FALSE;
    } else {
-      if (ctx->Shader.Flags & GLSL_DUMP) {
-         printf("GLSL source for %s shader %d:\n",
-                _mesa_shader_stage_to_string(sh->Stage), sh->Name);
-         printf("%s\n", sh->Source);
+      if (ctx->_Shader->Flags & GLSL_DUMP) {
+         fprintf(stderr, "GLSL source for %s shader %d:\n",
+                 _mesa_shader_stage_to_string(sh->Stage), sh->Name);
+         fprintf(stderr, "%s\n", sh->Source);
+         fflush(stderr);
       }
 
       /* this call will set the shader->CompileStatus field to indicate if
@@ -848,28 +852,29 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
        */
       _mesa_glsl_compile_shader(ctx, sh, false, false);
 
-      if (ctx->Shader.Flags & GLSL_LOG) {
+      if (ctx->_Shader->Flags & GLSL_LOG) {
          _mesa_write_shader_to_file(sh);
       }
 
-      if (ctx->Shader.Flags & GLSL_DUMP) {
+      if (ctx->_Shader->Flags & GLSL_DUMP) {
          if (sh->CompileStatus) {
-            printf("GLSL IR for shader %d:\n", sh->Name);
-            _mesa_print_ir(sh->ir, NULL);
-            printf("\n\n");
+            fprintf(stderr, "GLSL IR for shader %d:\n", sh->Name);
+            _mesa_print_ir(stderr, sh->ir, NULL);
+            fprintf(stderr, "\n\n");
          } else {
-            printf("GLSL shader %d failed to compile.\n", sh->Name);
+            fprintf(stderr, "GLSL shader %d failed to compile.\n", sh->Name);
          }
          if (sh->InfoLog && sh->InfoLog[0] != 0) {
-            printf("GLSL shader %d info log:\n", sh->Name);
-            printf("%s\n", sh->InfoLog);
+            fprintf(stderr, "GLSL shader %d info log:\n", sh->Name);
+            fprintf(stderr, "%s\n", sh->InfoLog);
          }
+         fflush(stderr);
       }
 
    }
 
    if (!sh->CompileStatus) {
-      if (ctx->Shader.Flags & GLSL_DUMP_ON_ERROR) {
+      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);
@@ -877,7 +882,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
          fflush(stderr);
       }
 
-      if (ctx->Shader.Flags & GLSL_REPORT_ERRORS) {
+      if (ctx->_Shader->Flags & GLSL_REPORT_ERRORS) {
          _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
                      sh->Name, sh->InfoLog);
       }
@@ -913,7 +918,7 @@ link_program(struct gl_context *ctx, GLuint program)
    _mesa_glsl_link_shader(ctx, shProg);
 
    if (shProg->LinkStatus == GL_FALSE && 
-       (ctx->Shader.Flags & GLSL_REPORT_ERRORS)) {
+       (ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
       _mesa_debug(ctx, "Error linking program %u:\n%s\n",
                   shProg->Name, shProg->InfoLog);
    }
@@ -984,17 +989,21 @@ _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
  */
 static void
 use_shader_program(struct gl_context *ctx, GLenum type,
-                  struct gl_shader_program *shProg)
+                   struct gl_shader_program *shProg,
+                   struct gl_pipeline_object *shTarget)
 {
    struct gl_shader_program **target;
    gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
 
-   target = &ctx->Shader.CurrentProgram[stage];
+   target = &shTarget->CurrentProgram[stage];
    if ((shProg == NULL) || (shProg->_LinkedShaders[stage] == NULL))
       shProg = NULL;
 
    if (*target != shProg) {
-      FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+      /* Program is current, flush it */
+      if (shTarget == ctx->_Shader) {
+         FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+      }
 
       /* If the shader is also bound as the current rendering shader, unbind
        * it from that binding point as well.  This ensures that the correct
@@ -1011,9 +1020,9 @@ use_shader_program(struct gl_context *ctx, GLenum type,
          /* Empty for now. */
          break;
       case GL_FRAGMENT_SHADER:
-        if (*target == ctx->Shader._CurrentFragmentProgram) {
+         if (*target == ctx->_Shader->_CurrentFragmentProgram) {
            _mesa_reference_shader_program(ctx,
-                                          &ctx->Shader._CurrentFragmentProgram,
+                                           &ctx->_Shader->_CurrentFragmentProgram,
                                           NULL);
         }
         break;
@@ -1030,10 +1039,10 @@ use_shader_program(struct gl_context *ctx, GLenum type,
 void
 _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);
+   use_shader_program(ctx, GL_VERTEX_SHADER, shProg, &ctx->Shader);
+   use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg, &ctx->Shader);
+   use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, &ctx->Shader);
+   use_shader_program(ctx, GL_COMPUTE_SHADER, shProg, &ctx->Shader);
    _mesa_active_program(ctx, shProg, "glUseProgram");
 
    if (ctx->Driver.UseProgram)
@@ -1531,7 +1540,7 @@ _mesa_UseProgram(GLhandleARB program)
       }
 
       /* debug code */
-      if (ctx->Shader.Flags & GLSL_USE_PROG) {
+      if (ctx->_Shader->Flags & GLSL_USE_PROG) {
          print_shader_info(shProg);
       }
    }
@@ -1539,7 +1548,31 @@ _mesa_UseProgram(GLhandleARB program)
       shProg = NULL;
    }
 
-   _mesa_use_program(ctx, shProg);
+   /* The "Dependencies on EXT_separate_shader_objects" section of the
+    * ARB_separate_shader_object spec says:
+    *
+    *     "The executable code for an individual shader stage is taken from
+    *     the current program for that stage.  If there is a current program
+    *     object for any shader stage or for uniform updates established by
+    *     UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current
+    *     program for that stage (if any) is considered current.  Otherwise,
+    *     if there is a bound program pipeline object ..."
+    */
+   if (program) {
+      /* Attach shader state to the binding point */
+      _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
+      /* Update the program */
+      _mesa_use_program(ctx, shProg);
+   } else {
+      /* Must be done first: detach the progam */
+      _mesa_use_program(ctx, shProg);
+      /* Unattach shader_state binding point */
+      _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);
+      }
+   }
 }
 
 
@@ -1771,9 +1804,10 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
 
 void
 _mesa_use_shader_program(struct gl_context *ctx, GLenum type,
-                        struct gl_shader_program *shProg)
+                         struct gl_shader_program *shProg,
+                         struct gl_pipeline_object *shTarget)
 {
-   use_shader_program(ctx, type, shProg);
+   use_shader_program(ctx, type, shProg, shTarget);
 
    if (ctx->Driver.UseProgram)
       ctx->Driver.UseProgram(ctx, shProg);
@@ -1813,7 +1847,41 @@ _mesa_UseShaderProgramEXT(GLenum type, GLuint program)
       }
    }
 
-   _mesa_use_shader_program(ctx, type, shProg);
+   /* The "Dependencies on EXT_separate_shader_objects" section of the
+    * ARB_separate_shader_object spec says:
+    *
+    *     "The executable code for an individual shader stage is taken from
+    *     the current program for that stage.  If there is a current program
+    *     object for any shader stage or for uniform updates established by
+    *     UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current
+    *     program for that stage (if any) is considered current.  Otherwise,
+    *     if there is a bound program pipeline object ..."
+    */
+   if (program) {
+      /* Attach shader state to the binding point */
+      _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
+      /* Update the program */
+      _mesa_use_shader_program(ctx, type, shProg, ctx->_Shader);
+   } else {
+      /* Must be done first: detach the progam */
+      _mesa_use_shader_program(ctx, type, shProg, ctx->_Shader);
+
+      /* Nothing remains current */
+      if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] &&
+          !ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY] &&
+          !ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT] &&
+          !ctx->Shader.ActiveProgram) {
+
+         /* Unattach shader_state binding point */
+         _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);
+         }
+      }
+   }
 }
 
 
@@ -1828,7 +1896,39 @@ _mesa_ActiveProgramEXT(GLuint program)
       ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
       : NULL;
 
-   _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+   /* The "Dependencies on EXT_separate_shader_objects" section of the
+    * ARB_separate_shader_object spec says:
+    *
+    *     "The executable code for an individual shader stage is taken from
+    *     the current program for that stage.  If there is a current program
+    *     object for any shader stage or for uniform updates established by
+    *     UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current
+    *     program for that stage (if any) is considered current.  Otherwise,
+    *     if there is a bound program pipeline object ..."
+    */
+   if (shProg != NULL) {
+      /* Attach shader state to the binding point */
+      _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
+      _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+   } else {
+      /* Must be done first: unset the current active progam */
+      _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+
+      /* Nothing remains current */
+      if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] &&
+          !ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY] &&
+          !ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT] &&
+          !ctx->Shader.ActiveProgram) {
+
+         /* Unattach shader_state binding point */
+         _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);
+         }
+      }
+   }
+
    return;
 }
 
@@ -1930,10 +2030,15 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
 
 /**
  * ARB_separate_shader_objects: Compile & Link Program
+ *
+ * Basically the same as _mesa_CreateShaderProgramEXT but with support of
+ * multiple strings and sets the SeparateShader flag to true.
  */
 GLuint GLAPIENTRY
 _mesa_CreateShaderProgramv(GLenum type, GLsizei count,
                            const GLchar* const *strings)
 {
-   return 0;
+   GET_CURRENT_CONTEXT(ctx);
+
+   return _mesa_create_shader_program(ctx, GL_TRUE, type, count, strings);
 }