mesa: Reject ResumeTransformFeedback if the wrong program is bound.
[mesa.git] / src / mesa / main / shaderapi.c
index a2a4875bbfa40804076989b91140d12c57a40e1f..a2386fb133e105102fc70da5109f766a9fee4e37 100644 (file)
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /**
 #include "main/transformfeedback.h"
 #include "main/uniforms.h"
 #include "program/program.h"
+#include "program/prog_print.h"
 #include "program/prog_parameter.h"
 #include "ralloc.h"
 #include <stdbool.h>
 #include "../glsl/glsl_parser_extras.h"
+#include "../glsl/ir.h"
 #include "../glsl/ir_uniform.h"
+#include "../glsl/program.h"
 
 /** Define this to enable shader substitution (see below) */
 #define SHADER_SUBST 0
@@ -67,7 +71,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;
@@ -173,7 +179,7 @@ validate_shader_target(const struct gl_context *ctx, GLenum type)
    case GL_VERTEX_SHADER:
       return ctx->Extensions.ARB_vertex_shader;
    case GL_GEOMETRY_SHADER_ARB:
-      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+      return _mesa_has_geometry_shaders(ctx);
    default:
       return false;
    }
@@ -472,8 +478,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
 
    /* Are geometry shaders available in this context?
     */
-   const bool has_gs =
-      _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+   const bool has_gs = _mesa_has_geometry_shaders(ctx);
 
    /* Are uniform buffer objects available in this context?
     */
@@ -737,20 +742,65 @@ 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)];
 
    /* set default pragma state for shader */
    sh->Pragmas = options->DefaultPragmas;
 
-   /* this call will set the sh->CompileStatus field to indicate if
-    * compilation was successful.
-    */
-   _mesa_glsl_compile_shader(ctx, sh);
+   if (!sh->Source) {
+      /* If the user called glCompileShader without first calling
+       * glShaderSource, we should fail to compile, but not raise a GL_ERROR.
+       */
+      sh->CompileStatus = GL_FALSE;
+   } else {
+      if (ctx->Shader.Flags & GLSL_DUMP) {
+         printf("GLSL source for %s shader %d:\n",
+                _mesa_glsl_shader_target_name(sh->Type), sh->Name);
+         printf("%s\n", sh->Source);
+      }
 
-   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);
+      /* this call will set the shader->CompileStatus field to indicate if
+       * compilation was successful.
+       */
+      _mesa_glsl_compile_shader(ctx, sh, false, false);
+
+      if (ctx->Shader.Flags & GLSL_LOG) {
+         _mesa_write_shader_to_file(sh);
+      }
+
+      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");
+         } else {
+            printf("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);
+         }
+      }
+
+   }
+
+   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);
+         fprintf(stderr, "%s\n", sh->Source);
+      }
+
+      if (ctx->Shader.Flags & GLSL_REPORT_ERRORS) {
+         _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
+                     sh->Name, sh->InfoLog);
+      }
    }
 }
 
@@ -815,21 +865,8 @@ print_shader_info(const struct gl_shader_program *shProg)
 
    printf("Mesa: glUseProgram(%u)\n", shProg->Name);
    for (i = 0; i < shProg->NumShaders; i++) {
-      const char *s;
-      switch (shProg->Shaders[i]->Type) {
-      case GL_VERTEX_SHADER:
-         s = "vertex";
-         break;
-      case GL_FRAGMENT_SHADER:
-         s = "fragment";
-         break;
-      case GL_GEOMETRY_SHADER:
-         s = "geometry";
-         break;
-      default:
-         s = "";
-      }
-      printf("  %s shader %u, checksum %u\n", s, 
+      printf("  %s shader %u, checksum %u\n",
+             _mesa_glsl_shader_target_name(shProg->Shaders[i]->Type),
             shProg->Shaders[i]->Name,
             shProg->Shaders[i]->SourceChecksum);
    }
@@ -1603,10 +1640,10 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
       if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
          break;
 
-      if (value < 1 ||
+      if (value < 0 ||
           (unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
+                     "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d)",
                      value);
          return;
       }
@@ -1626,7 +1663,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
          break;
       default:
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glProgramParameteri(geometry input type = %s",
+                     "glProgramParameteri(geometry input type = %s)",
                      _mesa_lookup_enum_by_nr(value));
          return;
       }
@@ -1643,7 +1680,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
          break;
       default:
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glProgramParameteri(geometry output type = %s",
+                     "glProgramParameteri(geometry output type = %s)",
                      _mesa_lookup_enum_by_nr(value));
          return;
       }
@@ -1811,3 +1848,34 @@ _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_type 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;
+   }
+      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_gp->UsesClipDistance = src->Geom.UsesClipDistance;
+      dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
+   }
+      break;
+   default:
+      break;
+   }
+}