mesa: call FLUSH_VERTICES() before deleting shaders, buffers, query objects
[mesa.git] / src / mesa / main / shaderapi.c
index 9b48610d166146cc80a02aacd6aa245849c0136b..6650613d28d76ea3cca3dec505b71568a807aa94 100644 (file)
 #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 "program/program.h"
 #include "program/prog_parameter.h"
 #include "program/prog_uniform.h"
-#include "talloc.h"
+#include "ralloc.h"
 #include <stdbool.h>
+#include "../glsl/glsl_parser_extras.h"
 
 /** Define this to enable shader substitution (see below) */
 #define SHADER_SUBST 0
@@ -95,7 +98,7 @@ _mesa_init_shader_state(struct gl_context *ctx)
     * are generated by the GLSL compiler.
     */
    struct gl_shader_compiler_options options;
-   GLuint i;
+   gl_shader_type sh;
 
    memset(&options, 0, sizeof(options));
    options.MaxUnrollIterations = 32;
@@ -103,8 +106,8 @@ _mesa_init_shader_state(struct gl_context *ctx)
    /* Default pragma settings */
    options.DefaultPragmas.Optimize = GL_TRUE;
 
-   for(i = 0; i < MESA_SHADER_TYPES; ++i)
-      memcpy(&ctx->ShaderCompilerOptions[i], &options, sizeof(options));
+   for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+      memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
 
    ctx->Shader.Flags = get_shader_flags();
 }
@@ -116,7 +119,12 @@ _mesa_init_shader_state(struct gl_context *ctx)
 void
 _mesa_free_shader_state(struct gl_context *ctx)
 {
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
+   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
+   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
+                                 NULL);
+   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
+                                 NULL);
+   _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
 }
 
 
@@ -399,6 +407,14 @@ bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index,
 }
 
 
+static void
+bind_frag_data_location(struct gl_context *ctx, GLuint program,
+                        GLuint colorNumber, const GLchar *name)
+{
+   _mesa_problem(ctx, "bind_frag_data_location() not implemented yet");
+}
+
+
 static GLuint
 create_shader(struct gl_context *ctx, GLenum type)
 {
@@ -600,6 +616,16 @@ get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
 }
 
 
+static GLint
+get_frag_data_location(struct gl_context *ctx, GLuint program,
+                       const GLchar *name)
+{
+   _mesa_problem(ctx, "get_frag_data_location() not implemented yet");
+   return -1;
+}
+
+
+
 /**
  * glGetHandleARB() - return ID/name of currently bound shader program.
  */
@@ -607,8 +633,8 @@ static GLuint
 get_handle(struct gl_context *ctx, GLenum pname)
 {
    if (pname == GL_PROGRAM_OBJECT_ARB) {
-      if (ctx->Shader.CurrentProgram)
-         return ctx->Shader.CurrentProgram->Name;
+      if (ctx->Shader.ActiveProgram)
+         return ctx->Shader.ActiveProgram->Name;
       else
          return 0;
    }
@@ -845,7 +871,10 @@ link_program(struct gl_context *ctx, GLuint program)
    if (!shProg)
       return;
 
-   if (obj->Active && shProg == ctx->Shader.CurrentProgram) {
+   if (obj->Active
+       && (shProg == ctx->Shader.CurrentVertexProgram
+          || shProg == ctx->Shader.CurrentGeometryProgram
+          || shProg == ctx->Shader.CurrentFragmentProgram)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glLinkProgram(transform feedback active");
       return;
@@ -908,52 +937,83 @@ print_shader_info(const struct gl_shader_program *shProg)
 
 
 /**
- * Use the named shader program for subsequent rendering.
+ * Use the named shader program for subsequent glUniform calls
  */
 void
-_mesa_use_program(struct gl_context *ctx, GLuint program)
+_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
+                    const char *caller)
 {
-   struct gl_shader_program *shProg;
-   struct gl_transform_feedback_object *obj =
-      ctx->TransformFeedback.CurrentObject;
-
-   if (obj->Active) {
+   if ((shProg != NULL) && !shProg->LinkStatus) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glUseProgram(transform feedback active)");
+                 "%s(program %u not linked)", caller, shProg->Name);
       return;
    }
 
-   if (ctx->Shader.CurrentProgram &&
-       ctx->Shader.CurrentProgram->Name == program) {
-      /* no-op */
-      return;
+   if (ctx->Shader.ActiveProgram != shProg) {
+      _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
    }
+}
 
-   if (program) {
-      shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
-      if (!shProg) {
-         return;
+/**
+ */
+static bool
+use_shader_program(struct gl_context *ctx, GLenum type,
+                  struct gl_shader_program *shProg)
+{
+   struct gl_shader_program **target;
+
+   switch (type) {
+#if FEATURE_ARB_vertex_shader
+   case GL_VERTEX_SHADER:
+      target = &ctx->Shader.CurrentVertexProgram;
+      if ((shProg == NULL)
+         || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
+        shProg = NULL;
       }
-      if (!shProg->LinkStatus) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glUseProgram(program %u not linked)", program);
-         return;
+      break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+   case GL_GEOMETRY_SHADER_ARB:
+      target = &ctx->Shader.CurrentGeometryProgram;
+      if ((shProg == NULL)
+         || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
+        shProg = NULL;
       }
-
-      /* debug code */
-      if (ctx->Shader.Flags & GLSL_USE_PROG) {
-         print_shader_info(shProg);
+      break;
+#endif
+#if FEATURE_ARB_fragment_shader
+   case GL_FRAGMENT_SHADER:
+      target = &ctx->Shader.CurrentFragmentProgram;
+      if ((shProg == NULL)
+         || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
+        shProg = NULL;
       }
-   }
-   else {
-      shProg = NULL;
+      break;
+#endif
+   default:
+      return false;
    }
 
-   if (ctx->Shader.CurrentProgram != shProg) {
+   if (*target != shProg) {
       FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
-      _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
+      _mesa_reference_shader_program(ctx, target, shProg);
+      return true;
    }
 
+   return false;
+}
+
+/**
+ * Use the named shader program for subsequent rendering.
+ */
+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);
+   _mesa_active_program(ctx, shProg, "glUseProgram");
+
    if (ctx->Driver.UseProgram)
       ctx->Driver.UseProgram(ctx, shProg);
 }
@@ -966,7 +1026,7 @@ _mesa_use_program(struct gl_context *ctx, GLuint program)
  * \return GL_TRUE if valid, GL_FALSE if invalid
  */
 static GLboolean
-validate_samplers(struct gl_context *ctx, const struct gl_program *prog, char *errMsg)
+validate_samplers(const struct gl_program *prog, char *errMsg)
 {
    static const char *targetName[] = {
       "TEXTURE_2D_ARRAY",
@@ -1018,8 +1078,7 @@ validate_samplers(struct gl_context *ctx, const struct gl_program *prog, char *e
  * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
  */
 static GLboolean
-validate_shader_program(struct gl_context *ctx,
-                        const struct gl_shader_program *shProg,
+validate_shader_program(const struct gl_shader_program *shProg,
                         char *errMsg)
 {
    const struct gl_vertex_program *vp = shProg->VertexProgram;
@@ -1049,10 +1108,10 @@ validate_shader_program(struct gl_context *ctx,
     * Check: any two active samplers in the current program object are of
     * different types, but refer to the same texture image unit,
     */
-   if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
+   if (vp && !validate_samplers(&vp->Base, errMsg)) {
       return GL_FALSE;
    }
-   if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
+   if (fp && !validate_samplers(&fp->Base, errMsg)) {
       return GL_FALSE;
    }
 
@@ -1074,13 +1133,13 @@ validate_program(struct gl_context *ctx, GLuint program)
       return;
    }
 
-   shProg->Validated = validate_shader_program(ctx, shProg, errMsg);
+   shProg->Validated = validate_shader_program(shProg, errMsg);
    if (!shProg->Validated) {
       /* update info log */
       if (shProg->InfoLog) {
-         talloc_free(shProg->InfoLog);
+         ralloc_free(shProg->InfoLog);
       }
-      shProg->InfoLog = talloc_strdup(shProg, errMsg);
+      shProg->InfoLog = ralloc_strdup(shProg, errMsg);
    }
 }
 
@@ -1111,10 +1170,22 @@ _mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
 }
 
 
+/* GL_EXT_gpu_shader4, GL3 */
+void GLAPIENTRY
+_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
+                           const GLchar *name)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   bind_frag_data_location(ctx, program, colorNumber, name);
+}
+
+
 void GLAPIENTRY
 _mesa_CompileShaderARB(GLhandleARB shaderObj)
 {
    GET_CURRENT_CONTEXT(ctx);
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glCompileShader %u\n", shaderObj);
    compile_shader(ctx, shaderObj);
 }
 
@@ -1123,6 +1194,8 @@ GLuint GLAPIENTRY
 _mesa_CreateShader(GLenum type)
 {
    GET_CURRENT_CONTEXT(ctx);
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type));
    return create_shader(ctx, type);
 }
 
@@ -1139,6 +1212,8 @@ GLuint GLAPIENTRY
 _mesa_CreateProgram(void)
 {
    GET_CURRENT_CONTEXT(ctx);
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glCreateProgram\n");
    return create_shader_program(ctx);
 }
 
@@ -1154,8 +1229,14 @@ _mesa_CreateProgramObjectARB(void)
 void GLAPIENTRY
 _mesa_DeleteObjectARB(GLhandleARB obj)
 {
+   if (MESA_VERBOSE & VERBOSE_API) {
+      GET_CURRENT_CONTEXT(ctx);
+      _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj);
+   }
+
    if (obj) {
       GET_CURRENT_CONTEXT(ctx);
+      FLUSH_VERTICES(ctx, 0);
       if (is_program(ctx, obj)) {
          delete_shader_program(ctx, obj);
       }
@@ -1174,6 +1255,7 @@ _mesa_DeleteProgram(GLuint name)
 {
    if (name) {
       GET_CURRENT_CONTEXT(ctx);
+      FLUSH_VERTICES(ctx, 0);
       delete_shader_program(ctx, name);
    }
 }
@@ -1184,6 +1266,7 @@ _mesa_DeleteShader(GLuint name)
 {
    if (name) {
       GET_CURRENT_CONTEXT(ctx);
+      FLUSH_VERTICES(ctx, 0);
       delete_shader(ctx, name);
    }
 }
@@ -1241,6 +1324,16 @@ _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
 }
 
 
+/* GL_EXT_gpu_shader4, GL3 */
+GLint GLAPIENTRY
+_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   return get_frag_data_location(ctx, program, name);
+}
+
+
+
 void GLAPIENTRY
 _mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
                     GLcharARB * infoLog)
@@ -1502,8 +1595,37 @@ void GLAPIENTRY
 _mesa_UseProgramObjectARB(GLhandleARB program)
 {
    GET_CURRENT_CONTEXT(ctx);
-   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
-   _mesa_use_program(ctx, program);
+   struct gl_shader_program *shProg;
+   struct gl_transform_feedback_object *obj =
+      ctx->TransformFeedback.CurrentObject;
+
+   if (obj->Active) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glUseProgram(transform feedback active)");
+      return;
+   }
+
+   if (program) {
+      shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
+      if (!shProg) {
+         return;
+      }
+      if (!shProg->LinkStatus) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glUseProgram(program %u not linked)", program);
+         return;
+      }
+
+      /* debug code */
+      if (ctx->Shader.Flags & GLSL_USE_PROG) {
+         print_shader_info(shProg);
+      }
+   }
+   else {
+      shProg = NULL;
+   }
+
+   _mesa_use_program(ctx, shProg);
 }
 
 
@@ -1520,16 +1642,58 @@ void GLAPIENTRY
 _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
                                GLint* range, GLint* precision)
 {
+   const struct gl_program_constants *limits;
+   const struct gl_precision *p;
    GET_CURRENT_CONTEXT(ctx);
-   _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+
+   switch (shadertype) {
+   case GL_VERTEX_SHADER:
+      limits = &ctx->Const.VertexProgram;
+      break;
+   case GL_FRAGMENT_SHADER:
+      limits = &ctx->Const.FragmentProgram;
+      break;
+   default:
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glGetShaderPrecisionFormat(shadertype)");
+      return;
+   }
+
+   switch (precisiontype) {
+   case GL_LOW_FLOAT:
+      p = &limits->LowFloat;
+      break;
+   case GL_MEDIUM_FLOAT:
+      p = &limits->MediumFloat;
+      break;
+   case GL_HIGH_FLOAT:
+      p = &limits->HighFloat;
+      break;
+   case GL_LOW_INT:
+      p = &limits->LowInt;
+      break;
+   case GL_MEDIUM_INT:
+      p = &limits->MediumInt;
+      break;
+   case GL_HIGH_INT:
+      p = &limits->HighInt;
+      break;
+   default:
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glGetShaderPrecisionFormat(precisiontype)");
+      return;
+   }
+
+   range[0] = p->RangeMin;
+   range[1] = p->RangeMax;
+   precision[0] = p->Precision;
 }
 
 
 void GLAPIENTRY
 _mesa_ReleaseShaderCompiler(void)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+   _mesa_destroy_shader_compiler_caches();
 }
 
 
@@ -1538,6 +1702,11 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
                    const void* binary, GLint length)
 {
    GET_CURRENT_CONTEXT(ctx);
+   (void) n;
+   (void) shaders;
+   (void) binaryformat;
+   (void) binary;
+   (void) length;
    _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
 }
 
@@ -1610,6 +1779,104 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname,
 
 #endif
 
+void
+_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
+                        struct gl_shader_program *shProg)
+{
+   use_shader_program(ctx, type, shProg);
+
+   if (ctx->Driver.UseProgram)
+      ctx->Driver.UseProgram(ctx, shProg);
+}
+
+void GLAPIENTRY
+_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_shader_program *shProg = NULL;
+
+   if (!validate_shader_target(ctx, type)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
+      return;
+   }
+
+   if (ctx->TransformFeedback.CurrentObject->Active) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glUseShaderProgramEXT(transform feedback is active)");
+      return;
+   }
+
+   if (program) {
+      shProg = _mesa_lookup_shader_program_err(ctx, program,
+                                              "glUseShaderProgramEXT");
+      if (shProg == NULL)
+        return;
+
+      if (!shProg->LinkStatus) {
+        _mesa_error(ctx, GL_INVALID_OPERATION,
+                    "glUseShaderProgramEXT(program not linked)");
+        return;
+      }
+   }
+
+   _mesa_use_shader_program(ctx, type, shProg);
+}
+
+void GLAPIENTRY
+_mesa_ActiveProgramEXT(GLuint program)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_shader_program *shProg = (program != 0)
+      ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
+      : NULL;
+
+   _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+   return;
+}
+
+GLuint GLAPIENTRY
+_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   const GLuint shader = create_shader(ctx, type);
+   GLuint program = 0;
+
+   if (shader) {
+      shader_source(ctx, shader, _mesa_strdup(string));
+      compile_shader(ctx, shader);
+
+      program = create_shader_program(ctx);
+      if (program) {
+        struct gl_shader_program *shProg;
+        struct gl_shader *sh;
+        GLint compiled = GL_FALSE;
+
+        shProg = _mesa_lookup_shader_program(ctx, program);
+        sh = _mesa_lookup_shader(ctx, shader);
+
+        get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
+        if (compiled) {
+           attach_shader(ctx, program, shader);
+           link_program(ctx, program);
+           detach_shader(ctx, program, shader);
+
+#if 0
+           /* Possibly... */
+           if (active-user-defined-varyings-in-linked-program) {
+              append-error-to-info-log;
+              shProg->LinkStatus = GL_FALSE;
+           }
+#endif
+        }
+
+        ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
+      }
+
+      delete_shader(ctx, shader);
+   }
+
+   return program;
+}
 
 /**
  * Plug in shader-related functions into API dispatch table.
@@ -1660,6 +1927,19 @@ _mesa_init_shader_dispatch(struct _glapi_table *exec)
 #if FEATURE_ARB_geometry_shader4
    SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB);
 #endif
+
+   SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
+   SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
+   SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
+
+   /* GL_EXT_gpu_shader4 / GL 3.0 */
+   SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
+   SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation);
+
+   /* GL_ARB_ES2_compatibility */
+   SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
+   SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
+
 #endif /* FEATURE_GL */
 }