mesa: add support for memory object creation/import/delete
[mesa.git] / src / mesa / main / shaderapi.c
index 84189f0719fd47db1a620b86ecfc2b033db3f152..6dd617be7e5e727a1506a88f09aad7a642b8774f 100644 (file)
@@ -423,16 +423,21 @@ delete_shader(struct gl_context *ctx, GLuint shader)
 }
 
 
-static void
-detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
+static ALWAYS_INLINE void
+detach_shader(struct gl_context *ctx, GLuint program, GLuint shader,
+              bool no_error)
 {
    struct gl_shader_program *shProg;
    GLuint n;
    GLuint i, j;
 
-   shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
-   if (!shProg)
-      return;
+   if (!no_error) {
+      shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
+      if (!shProg)
+         return;
+   } else {
+      shProg = _mesa_lookup_shader_program(ctx, program);
+   }
 
    n = shProg->NumShaders;
 
@@ -480,7 +485,7 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
    }
 
    /* not found */
-   {
+   if (!no_error) {
       GLenum err;
       if (is_shader(ctx, shader) || is_program(ctx, shader))
          err = GL_INVALID_OPERATION;
@@ -492,6 +497,20 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
 }
 
 
+static void
+detach_shader_error(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+   detach_shader(ctx, program, shader, false);
+}
+
+
+static void
+detach_shader_no_error(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+   detach_shader(ctx, program, shader, true);
+}
+
+
 /**
  * Return list of shaders attached to shader program.
  */
@@ -1020,7 +1039,7 @@ get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
  * glShaderSource[ARB].
  */
 static void
-shader_source(struct gl_shader *sh, const GLchar *source)
+set_shader_source(struct gl_shader *sh, const GLchar *source)
 {
    assert(sh);
 
@@ -1111,21 +1130,24 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh)
 /**
  * Link a program's shaders.
  */
-void
-_mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg)
+static ALWAYS_INLINE void
+link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
+             bool no_error)
 {
    if (!shProg)
       return;
 
-   /* From the ARB_transform_feedback2 specification:
-    * "The error INVALID_OPERATION is generated by LinkProgram if <program> is
-    *  the name of a program being used by one or more transform feedback
-    *  objects, even if the objects are not currently bound or are paused."
-    */
-   if (_mesa_transform_feedback_is_using_program(ctx, shProg)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glLinkProgram(transform feedback is using the program)");
-      return;
+   if (!no_error) {
+      /* From the ARB_transform_feedback2 specification:
+       * "The error INVALID_OPERATION is generated by LinkProgram if <program>
+       * is the name of a program being used by one or more transform feedback
+       * objects, even if the objects are not currently bound or are paused."
+       */
+      if (_mesa_transform_feedback_is_using_program(ctx, shProg)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glLinkProgram(transform feedback is using the program)");
+         return;
+      }
    }
 
    unsigned programs_in_use = 0;
@@ -1213,6 +1235,27 @@ _mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg)
 }
 
 
+static void
+link_program_error(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+   link_program(ctx, shProg, false);
+}
+
+
+static void
+link_program_no_error(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+   link_program(ctx, shProg, true);
+}
+
+
+void
+_mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+   link_program_error(ctx, shProg);
+}
+
+
 /**
  * Print basic shader info (for debug).
  */
@@ -1495,11 +1538,27 @@ _mesa_DeleteShader(GLuint name)
 }
 
 
+void GLAPIENTRY
+_mesa_DetachObjectARB_no_error(GLhandleARB program, GLhandleARB shader)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   detach_shader_no_error(ctx, program, shader);
+}
+
+
 void GLAPIENTRY
 _mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader)
 {
    GET_CURRENT_CONTEXT(ctx);
-   detach_shader(ctx, program, shader);
+   detach_shader_error(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_DetachShader_no_error(GLuint program, GLuint shader)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   detach_shader_no_error(ctx, program, shader);
 }
 
 
@@ -1507,7 +1566,7 @@ void GLAPIENTRY
 _mesa_DetachShader(GLuint program, GLuint shader)
 {
    GET_CURRENT_CONTEXT(ctx);
-   detach_shader(ctx, program, shader);
+   detach_shader_error(ctx, program, shader);
 }
 
 
@@ -1650,14 +1709,28 @@ _mesa_IsShader(GLuint name)
 }
 
 
+void GLAPIENTRY
+_mesa_LinkProgram_no_error(GLuint programObj)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_shader_program *shProg =
+      _mesa_lookup_shader_program(ctx, programObj);
+   link_program_no_error(ctx, shProg);
+}
+
+
 void GLAPIENTRY
 _mesa_LinkProgram(GLuint programObj)
 {
    GET_CURRENT_CONTEXT(ctx);
+
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glLinkProgram %u\n", programObj);
-   _mesa_link_program(ctx, _mesa_lookup_shader_program_err(ctx, programObj,
-                                                           "glLinkProgram"));
+
+   struct gl_shader_program *shProg =
+      _mesa_lookup_shader_program_err(ctx, programObj, "glLinkProgram");
+   link_program_error(ctx, shProg);
 }
 
 #ifdef ENABLE_SHADER_CACHE
@@ -1779,23 +1852,26 @@ read_shader(const gl_shader_stage stage, const char *source)
  * Basically, concatenate the source code strings into one long string
  * and pass it to _mesa_shader_source().
  */
-void GLAPIENTRY
-_mesa_ShaderSource(GLuint shaderObj, GLsizei count,
-                   const GLchar * const * string, const GLint * length)
+static ALWAYS_INLINE void
+shader_source(struct gl_context *ctx, GLuint shaderObj, GLsizei count,
+              const GLchar *const *string, const GLint *length, bool no_error)
 {
-   GET_CURRENT_CONTEXT(ctx);
    GLint *offsets;
    GLsizei i, totalLength;
    GLcharARB *source;
    struct gl_shader *sh;
 
-   sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB");
-   if (!sh)
-      return;
+   if (!no_error) {
+      sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB");
+      if (!sh)
+         return;
 
-   if (string == NULL) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
-      return;
+      if (string == NULL) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
+         return;
+      }
+   } else {
+      sh = _mesa_lookup_shader(ctx, shaderObj);
    }
 
    /*
@@ -1809,7 +1885,7 @@ _mesa_ShaderSource(GLuint shaderObj, GLsizei count,
    }
 
    for (i = 0; i < count; i++) {
-      if (string[i] == NULL) {
+      if (!no_error && string[i] == NULL) {
          free((GLvoid *) offsets);
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glShaderSourceARB(null string)");
@@ -1859,12 +1935,30 @@ _mesa_ShaderSource(GLuint shaderObj, GLsizei count,
    }
 #endif /* ENABLE_SHADER_CACHE */
 
-   shader_source(sh, source);
+   set_shader_source(sh, source);
 
    free(offsets);
 }
 
 
+void GLAPIENTRY
+_mesa_ShaderSource_no_error(GLuint shaderObj, GLsizei count,
+                            const GLchar *const *string, const GLint *length)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   shader_source(ctx, shaderObj, count, string, length, true);
+}
+
+
+void GLAPIENTRY
+_mesa_ShaderSource(GLuint shaderObj, GLsizei count,
+                   const GLchar *const *string, const GLint *length)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   shader_source(ctx, shaderObj, count, string, length, false);
+}
+
+
 static ALWAYS_INLINE void
 use_program(GLuint program, bool no_error)
 {
@@ -2141,17 +2235,10 @@ _mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
 }
 
 
-void GLAPIENTRY
-_mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
+static ALWAYS_INLINE void
+program_parameteri(struct gl_context *ctx, struct gl_shader_program *shProg,
+                   GLuint pname, GLint value, bool no_error)
 {
-   struct gl_shader_program *shProg;
-   GET_CURRENT_CONTEXT(ctx);
-
-   shProg = _mesa_lookup_shader_program_err(ctx, program,
-                                            "glProgramParameteri");
-   if (!shProg)
-      return;
-
    switch (pname) {
    case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
       /* This enum isn't part of the OES extension for OpenGL ES 2.0, but it
@@ -2167,7 +2254,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
        *     "An INVALID_VALUE error is generated if the <value> argument to
        *     ProgramParameteri is not TRUE or FALSE."
        */
-      if (value != GL_TRUE && value != GL_FALSE) {
+      if (!no_error && value != GL_TRUE && value != GL_FALSE) {
          goto invalid_value;
       }
 
@@ -2198,15 +2285,17 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
       /* Spec imply that the behavior is the same as ARB_get_program_binary
        * Chapter 7.3 Program Objects
        */
-      if (value != GL_TRUE && value != GL_FALSE) {
+      if (!no_error && value != GL_TRUE && value != GL_FALSE) {
          goto invalid_value;
       }
       shProg->SeparateShader = value;
       return;
 
    default:
-      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteri(pname=%s)",
-                  _mesa_enum_to_string(pname));
+      if (!no_error) {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteri(pname=%s)",
+                     _mesa_enum_to_string(pname));
+      }
       return;
    }
 
@@ -2219,6 +2308,31 @@ invalid_value:
 }
 
 
+void GLAPIENTRY
+_mesa_ProgramParameteri_no_error(GLuint program, GLenum pname, GLint value)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program);
+   program_parameteri(ctx, shProg, pname, value, true);
+}
+
+
+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");
+   if (!shProg)
+      return;
+
+   program_parameteri(ctx, shProg, pname, value, false);
+}
+
+
 void
 _mesa_use_program(struct gl_context *ctx, gl_shader_stage stage,
                   struct gl_shader_program *shProg, struct gl_program *prog,
@@ -2324,7 +2438,7 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count,
         if (compiled) {
            attach_shader_err(ctx, program, shader, "glCreateShaderProgramv");
            _mesa_link_program(ctx, shProg);
-           detach_shader(ctx, program, shader);
+           detach_shader_error(ctx, program, shader);
 
 #if 0
            /* Possibly... */
@@ -2348,6 +2462,14 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count,
 /**
  * For GL_ARB_tessellation_shader
  */
+void GLAPIENTRY
+_mesa_PatchParameteri_no_error(GLenum pname, GLint value)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ctx->TessCtrlProgram.patch_vertices = value;
+}
+
+
 extern void GLAPIENTRY
 _mesa_PatchParameteri(GLenum pname, GLint value)
 {