mesa: make _mesa_lookup_list() non-static
[mesa.git] / src / mesa / main / shaderapi.c
index 7f5fce796e5654da9c6aed609cf7c4a0809e5f64..4fe9d9ca252e12c53b1376f3ea57d4bbecf1e495 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
- * BRIAN PAUL 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/dispatch.h"
 #include "main/enums.h"
 #include "main/hash.h"
-#include "main/mfeatures.h"
 #include "main/mtypes.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
 #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
@@ -68,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;
@@ -174,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;
    }
@@ -207,6 +212,8 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
    struct gl_shader *sh;
    GLuint i, n;
 
+   const bool same_type_disallowed = _mesa_is_gles(ctx);
+
    shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
    if (!shProg)
       return;
@@ -227,6 +234,18 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
           */
          _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
          return;
+      } else if (same_type_disallowed &&
+                 shProg->Shaders[i]->Type == sh->Type) {
+        /* Shader with the same type is already attached to this program,
+         * OpenGL ES 2.0 and 3.0 specs say:
+         *
+         *      "Multiple shader objects of the same type may not be attached
+         *      to a single program object. [...] The error INVALID_OPERATION
+         *      is generated if [...] another shader object of the same type
+         *      as shader is already attached to program."
+         */
+         _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
+         return;
       }
    }
 
@@ -459,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?
     */
@@ -504,9 +522,11 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
       GLint max_len = 0;
 
       for (i = 0; i < shProg->NumUserUniformStorage; i++) {
-        /* Add one for the terminating NUL character.
+        /* Add one for the terminating NUL character for a non-array, and
+         * 4 for the "[0]" and the NUL for an array.
          */
-        const GLint len = strlen(shProg->UniformStorage[i].name) + 1;
+        const GLint len = strlen(shProg->UniformStorage[i].name) + 1 +
+            ((shProg->UniformStorage[i].array_elements != 0) ? 3 : 0);
 
         if (len > max_len)
            max_len = len;
@@ -722,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);
+      }
+
+      /* 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 == GL_FALSE && 
-       (ctx->Shader.Flags & GLSL_REPORT_ERRORS)) {
-      _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
-                  sh->Name, 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);
+      }
    }
 }
 
@@ -800,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);
    }
@@ -1400,8 +1452,6 @@ _mesa_UseProgram(GLhandleARB program)
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg;
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
    if (_mesa_is_xfb_active_and_unpaused(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glUseProgram(transform feedback active)");
@@ -1439,8 +1489,10 @@ _mesa_ValidateProgram(GLhandleARB program)
    validate_program(ctx, program);
 }
 
-#ifdef FEATURE_ES2
 
+/**
+ * For OpenGL ES 2.0, GL_ARB_ES2_compatibility
+ */
 void GLAPIENTRY
 _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
                                GLint* range, GLint* precision)
@@ -1493,6 +1545,9 @@ _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
 }
 
 
+/**
+ * For OpenGL ES 2.0, GL_ARB_ES2_compatibility
+ */
 void GLAPIENTRY
 _mesa_ReleaseShaderCompiler(void)
 {
@@ -1500,6 +1555,9 @@ _mesa_ReleaseShaderCompiler(void)
 }
 
 
+/**
+ * For OpenGL ES 2.0, GL_ARB_ES2_compatibility
+ */
 void GLAPIENTRY
 _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
                    const void* binary, GLint length)
@@ -1513,7 +1571,6 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
    _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
 }
 
-#endif /* FEATURE_ES2 */
 
 void GLAPIENTRY
 _mesa_GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length,
@@ -1522,8 +1579,6 @@ _mesa_GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length,
    struct gl_shader_program *shProg;
    GET_CURRENT_CONTEXT(ctx);
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
    shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetProgramBinary");
    if (!shProg)
       return;
@@ -1558,8 +1613,6 @@ _mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
    struct gl_shader_program *shProg;
    GET_CURRENT_CONTEXT(ctx);
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
    shProg = _mesa_lookup_shader_program_err(ctx, program, "glProgramBinary");
    if (!shProg)
       return;
@@ -1577,8 +1630,6 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
    struct gl_shader_program *shProg;
    GET_CURRENT_CONTEXT(ctx);
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
    shProg = _mesa_lookup_shader_program_err(ctx, program,
                                             "glProgramParameteri");
    if (!shProg)
@@ -1589,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;
       }
@@ -1612,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;
       }
@@ -1629,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;
       }
@@ -1707,8 +1758,6 @@ _mesa_UseShaderProgramEXT(GLenum type, GLuint program)
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg = NULL;
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
    if (!validate_shader_target(ctx, type)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
       return;
@@ -1800,83 +1849,32 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
    return program;
 }
 
+
 /**
- * Plug in shader-related functions into API dispatch table.
+ * Copy program-specific data generated by linking from the gl_shader_program
+ * object to a specific gl_program object.
  */
 void
-_mesa_init_shader_dispatch(const struct gl_context *ctx,
-                           struct _glapi_table *exec)
-{
-#if FEATURE_GL
-   /* GL_ARB_vertex/fragment_shader */
-   if (_mesa_is_desktop_gl(ctx)) {
-      SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB);
-      SET_GetHandleARB(exec, _mesa_GetHandleARB);
-      SET_DetachObjectARB(exec, _mesa_DetachObjectARB);
-      SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB);
-      SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB);
-      SET_AttachObjectARB(exec, _mesa_AttachObjectARB);
-      SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB);
-      SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB);
-      SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB);
-      SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB);
-   }
-
-   if (ctx->API != API_OPENGLES) {
-      SET_ShaderSource(exec, _mesa_ShaderSource);
-      SET_CompileShader(exec, _mesa_CompileShader);
-      SET_LinkProgram(exec, _mesa_LinkProgram);
-      SET_UseProgram(exec, _mesa_UseProgram);
-      SET_ValidateProgram(exec, _mesa_ValidateProgram);
-      SET_GetShaderSource(exec, _mesa_GetShaderSource);
-
-      /* OpenGL 2.0 */
-      SET_AttachShader(exec, _mesa_AttachShader);
-      SET_CreateProgram(exec, _mesa_CreateProgram);
-      SET_CreateShader(exec, _mesa_CreateShader);
-      SET_DeleteProgram(exec, _mesa_DeleteProgram);
-      SET_DeleteShader(exec, _mesa_DeleteShader);
-      SET_DetachShader(exec, _mesa_DetachShader);
-      SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders);
-      SET_GetProgramiv(exec, _mesa_GetProgramiv);
-      SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog);
-      SET_GetShaderiv(exec, _mesa_GetShaderiv);
-      SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog);
-      SET_IsProgram(exec, _mesa_IsProgram);
-      SET_IsShader(exec, _mesa_IsShader);
-
-      /* GL_ARB_vertex_shader */
-      SET_BindAttribLocation(exec, _mesa_BindAttribLocation);
-      SET_GetActiveAttrib(exec, _mesa_GetActiveAttrib);
-      SET_GetAttribLocation(exec, _mesa_GetAttribLocation);
-   }
-
-   if (ctx->API == API_OPENGL_COMPAT) {
-      SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
-      SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
-      SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
-   }
-
-   /* GL_EXT_gpu_shader4 / GL 3.0 */
-   if (_mesa_is_desktop_gl(ctx)) {
-      SET_BindFragDataLocation(exec, _mesa_BindFragDataLocation);
-   }
-   if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
-      SET_GetFragDataLocation(exec, _mesa_GetFragDataLocation);
-   }
-
-   /* GL_ARB_ES2_compatibility */
-   if (ctx->API != API_OPENGLES) {
-      SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
-      SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
-      SET_ShaderBinary(exec, _mesa_ShaderBinary);
-   }
-
-   /* GL_ARB_blend_func_extended */
-   if (_mesa_is_desktop_gl(ctx)) {
-      SET_BindFragDataLocationIndexed(exec, _mesa_BindFragDataLocationIndexed);
-      SET_GetFragDataIndex(exec, _mesa_GetFragDataIndex);
-   }
-#endif /* FEATURE_GL */
+_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;
+   }
+      break;
+   default:
+      break;
+   }
 }
-