svga: always link with C++
[mesa.git] / src / mesa / main / shaderapi.c
index 4411e8acca7ef2bdf92c0e5f5e6ea2b9d2cf8923..be69467986d417693819ed1d7df33f3e6ad33f78 100644 (file)
@@ -45,6 +45,7 @@
 #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_parameter.h"
@@ -180,25 +181,6 @@ validate_shader_target(const struct gl_context *ctx, GLenum type)
 }
 
 
-/**
- * Find the length of the longest transform feedback varying name
- * which was specified with glTransformFeedbackVaryings().
- */
-static GLint
-longest_feedback_varying_name(const struct gl_shader_program *shProg)
-{
-   GLuint i;
-   GLint max = 0;
-   for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
-      GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]);
-      if (len > max)
-         max = len;
-   }
-   return max;
-}
-
-
-
 static GLboolean
 is_program(struct gl_context *ctx, GLuint name)
 {
@@ -225,6 +207,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;
@@ -245,6 +229,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;
       }
    }
 
@@ -471,7 +467,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
    /* Is transform feedback available in this context?
     */
    const bool has_xfb =
-      (ctx->API == API_OPENGL && ctx->Extensions.EXT_transform_feedback)
+      (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_transform_feedback)
       || ctx->API == API_OPENGL_CORE
       || _mesa_is_gles3(ctx);
 
@@ -483,7 +479,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
    /* Are uniform buffer objects available in this context?
     */
    const bool has_ubo =
-      (ctx->API == API_OPENGL && ctx->Extensions.ARB_uniform_buffer_object)
+      (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_uniform_buffer_object)
       || ctx->API == API_OPENGL_CORE
       || _mesa_is_gles3(ctx);
 
@@ -538,11 +534,24 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
          break;
       *params = shProg->TransformFeedback.NumVarying;
       return;
-   case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+   case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: {
+      unsigned i;
+      GLint max_len = 0;
       if (!has_xfb)
          break;
-      *params = longest_feedback_varying_name(shProg) + 1;
+
+      for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
+         /* Add one for the terminating NUL character.
+          */
+         const GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]) + 1;
+
+         if (len > max_len)
+            max_len = len;
+      }
+
+      *params = max_len;
       return;
+   }
    case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
       if (!has_xfb)
          break;
@@ -588,6 +597,21 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
 
       *params = shProg->NumUniformBlocks;
       return;
+   case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+      /* This enum isn't part of the OES extension for OpenGL ES 2.0.  It is
+       * only available with desktop OpenGL 3.0+ with the
+       * GL_ARB_get_program_binary extension or OpenGL ES 3.0.
+       *
+       * On desktop, we ignore the 3.0+ requirement because it is silly.
+       */
+      if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
+         break;
+
+      *params = shProg->BinaryRetreivableHint;
+      return;
+   case GL_PROGRAM_BINARY_LENGTH:
+      *params = 0;
+      return;
    default:
       break;
    }
@@ -1001,7 +1025,7 @@ _mesa_AttachShader(GLuint program, GLuint shader)
 
 
 void GLAPIENTRY
-_mesa_CompileShaderARB(GLhandleARB shaderObj)
+_mesa_CompileShader(GLhandleARB shaderObj)
 {
    GET_CURRENT_CONTEXT(ctx);
    if (MESA_VERBOSE & VERBOSE_API)
@@ -1215,7 +1239,7 @@ _mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
 
 
 void GLAPIENTRY
-_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength,
+_mesa_GetShaderSource(GLhandleARB shader, GLsizei maxLength,
                          GLsizei *length, GLcharARB *sourceOut)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -1248,7 +1272,7 @@ _mesa_IsShader(GLuint name)
 
 
 void GLAPIENTRY
-_mesa_LinkProgramARB(GLhandleARB programObj)
+_mesa_LinkProgram(GLhandleARB programObj)
 {
    GET_CURRENT_CONTEXT(ctx);
    link_program(ctx, programObj);
@@ -1291,8 +1315,8 @@ read_shader(const char *fname)
  * and pass it to _mesa_shader_source().
  */
 void GLAPIENTRY
-_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
-                      const GLcharARB ** string, const GLint * length)
+_mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
+                      const GLcharARB * const * string, const GLint * length)
 {
    GET_CURRENT_CONTEXT(ctx);
    GLint *offsets;
@@ -1385,16 +1409,12 @@ _mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
 
 
 void GLAPIENTRY
-_mesa_UseProgramObjectARB(GLhandleARB program)
+_mesa_UseProgram(GLhandleARB program)
 {
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg;
-   struct gl_transform_feedback_object *obj =
-      ctx->TransformFeedback.CurrentObject;
-
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
 
-   if (obj->Active && !obj->Paused) {
+   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glUseProgram(transform feedback active)");
       return;
@@ -1425,7 +1445,7 @@ _mesa_UseProgramObjectARB(GLhandleARB program)
 
 
 void GLAPIENTRY
-_mesa_ValidateProgramARB(GLhandleARB program)
+_mesa_ValidateProgram(GLhandleARB program)
 {
    GET_CURRENT_CONTEXT(ctx);
    validate_program(ctx, program);
@@ -1507,14 +1527,63 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
 
 #endif /* FEATURE_ES2 */
 
+void GLAPIENTRY
+_mesa_GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length,
+                       GLenum *binaryFormat, GLvoid *binary)
+{
+   struct gl_shader_program *shProg;
+   GET_CURRENT_CONTEXT(ctx);
+
+   shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetProgramBinary");
+   if (!shProg)
+      return;
+
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetProgramBinary(program %u not linked)",
+                  shProg->Name);
+      return;
+   }
+
+   if (bufSize < 0){
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramBinary(bufSize < 0)");
+      return;
+   }
+
+   /* The ARB_get_program_binary spec says:
+    *
+    *     "If <length> is NULL, then no length is returned."
+    */
+   if (length != NULL)
+      *length = 0;
+
+   (void) binaryFormat;
+   (void) binary;
+}
 
 void GLAPIENTRY
-_mesa_ProgramParameteriARB(GLuint program, GLenum pname, GLint value)
+_mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
+                    const GLvoid *binary, GLsizei length)
 {
    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;
+
+   (void) binaryFormat;
+   (void) binary;
+   (void) length;
+   _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
+{
+   struct gl_shader_program *shProg;
+   GET_CURRENT_CONTEXT(ctx);
 
    shProg = _mesa_lookup_shader_program_err(ctx, program,
                                             "glProgramParameteri");
@@ -1523,6 +1592,9 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname, GLint value)
 
    switch (pname) {
    case GL_GEOMETRY_VERTICES_OUT_ARB:
+      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
+         break;
+
       if (value < 1 ||
           (unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
          _mesa_error(ctx, GL_INVALID_VALUE,
@@ -1531,8 +1603,11 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname, GLint value)
          return;
       }
       shProg->Geom.VerticesOut = value;
-      break;
+      return;
    case GL_GEOMETRY_INPUT_TYPE_ARB:
+      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
+         break;
+
       switch (value) {
       case GL_POINTS:
       case GL_LINES:
@@ -1547,8 +1622,11 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname, GLint value)
                      _mesa_lookup_enum_by_nr(value));
          return;
       }
-      break;
+      return;
    case GL_GEOMETRY_OUTPUT_TYPE_ARB:
+      if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
+         break;
+
       switch (value) {
       case GL_POINTS:
       case GL_LINE_STRIP:
@@ -1561,12 +1639,58 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname, GLint value)
                      _mesa_lookup_enum_by_nr(value));
          return;
       }
-      break;
+      return;
+   case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+      /* This enum isn't part of the OES extension for OpenGL ES 2.0, but it
+       * is part of OpenGL ES 3.0.  For the ES2 case, this function shouldn't
+       * even be in the dispatch table, so we shouldn't need to expclicitly
+       * check here.
+       *
+       * On desktop, we ignore the 3.0+ requirement because it is silly.
+       */
+
+      /* The ARB_get_program_binary extension spec says:
+       *
+       *     "An INVALID_VALUE error is generated if the <value> argument to
+       *     ProgramParameteri is not TRUE or FALSE."
+       */
+      if (value != GL_TRUE && value != GL_FALSE) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glProgramParameteri(pname=%s, value=%d): "
+                     "value must be 0 or 1.",
+                     _mesa_lookup_enum_by_nr(pname),
+                     value);
+         return;
+      }
+
+      /* No need to notify the driver.  Any changes will actually take effect
+       * the next time the shader is linked.
+       *
+       * The ARB_get_program_binary extension spec says:
+       *
+       *     "To indicate that a program binary is likely to be retrieved,
+       *     ProgramParameteri should be called with <pname>
+       *     PROGRAM_BINARY_RETRIEVABLE_HINT and <value> TRUE. This setting
+       *     will not be in effect until the next time LinkProgram or
+       *     ProgramBinary has been called successfully."
+       *
+       * The resloution of issue 9 in the extension spec also says:
+       *
+       *     "The application may use the PROGRAM_BINARY_RETRIEVABLE_HINT hint
+       *     to indicate to the GL implementation that this program will
+       *     likely be saved with GetProgramBinary at some point. This will
+       *     give the GL implementation the opportunity to track any state
+       *     changes made to the program before being saved such that when it
+       *     is loaded again a recompile can be avoided."
+       */
+      shProg->BinaryRetreivableHint = value;
+      return;
    default:
-      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)",
-                  _mesa_lookup_enum_by_nr(pname));
       break;
    }
+
+   _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteri(pname=%s)",
+               _mesa_lookup_enum_by_nr(pname));
 }
 
 void
@@ -1589,15 +1713,12 @@ _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;
    }
 
-   if (ctx->TransformFeedback.CurrentObject->Active &&
-       !ctx->TransformFeedback.CurrentObject->Paused) {
+   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glUseShaderProgramEXT(transform feedback is active)");
       return;
@@ -1682,88 +1803,3 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
 
    return program;
 }
-
-/**
- * Plug in shader-related functions into API dispatch table.
- */
-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_ShaderSourceARB(exec, _mesa_ShaderSourceARB);
-      SET_CompileShaderARB(exec, _mesa_CompileShaderARB);
-      SET_LinkProgramARB(exec, _mesa_LinkProgramARB);
-      SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB);
-      SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB);
-      SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB);
-
-      /* 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_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB);
-      SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB);
-      SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB);
-   }
-
-   if (_mesa_is_desktop_gl(ctx)) {
-      SET_ProgramParameteri(exec, _mesa_ProgramParameteriARB);
-   }
-
-   if (ctx->API == API_OPENGL) {
-      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_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
-   }
-   if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
-      SET_GetFragDataLocationEXT(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 */
-}
-