mesa/get: fix enum16 big-endian getting.
[mesa.git] / src / mesa / main / shaderapi.c
index 13faf787a2d68af0233ecc94e6a410bd455cc06c..19d7a3ab44003261b2bc601481fec61f093cbded 100644 (file)
@@ -63,6 +63,7 @@
 #include "util/crc32.h"
 #include "util/os_file.h"
 #include "util/simple_list.h"
+#include "util/u_string.h"
 
 /**
  * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
@@ -1249,6 +1250,29 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh)
 }
 
 
+struct update_programs_in_pipeline_params
+{
+   struct gl_context *ctx;
+   struct gl_shader_program *shProg;
+};
+
+static void
+update_programs_in_pipeline(GLuint key, void *data, void *userData)
+{
+   struct update_programs_in_pipeline_params *params =
+      (struct update_programs_in_pipeline_params *) userData;
+   struct gl_pipeline_object *obj = (struct gl_pipeline_object *) data;
+
+   for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+      if (obj->CurrentProgram[stage] &&
+          obj->CurrentProgram[stage]->Id == params->shProg->Name) {
+         struct gl_program *prog = params->shProg->_LinkedShaders[stage]->Program;
+         _mesa_use_program(params->ctx, stage, params->shProg, prog, obj);
+      }
+   }
+}
+
+
 /**
  * Link a program's shaders.
  */
@@ -1279,7 +1303,7 @@ link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
              ctx->_Shader->CurrentProgram[stage]->Id == shProg->Name) {
             programs_in_use |= 1 << stage;
          }
-   }
+      }
 
    ensure_builtin_types(ctx);
 
@@ -1296,7 +1320,7 @@ link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
     *     the state of any program pipeline for all stages where the program
     *     is attached."
     */
-   if (shProg->data->LinkStatus && programs_in_use) {
+   if (shProg->data->LinkStatus) {
       while (programs_in_use) {
          const int stage = u_bit_scan(&programs_in_use);
 
@@ -1306,6 +1330,15 @@ link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
 
          _mesa_use_program(ctx, stage, shProg, prog, ctx->_Shader);
       }
+
+      if (ctx->Pipeline.Objects) {
+         struct update_programs_in_pipeline_params params = {
+            .ctx = ctx,
+            .shProg = shProg
+         };
+         _mesa_HashWalk(ctx->Pipeline.Objects, update_programs_in_pipeline,
+                        &params);
+      }
    }
 
    /* Capture .shader_test files. */
@@ -2547,6 +2580,7 @@ _mesa_use_program(struct gl_context *ctx, gl_shader_stage stage,
                                      &shTarget->ReferencedPrograms[stage],
                                      shProg);
       _mesa_reference_program(ctx, target, prog);
+      _mesa_update_allow_draw_out_of_order(ctx);
       if (stage == MESA_SHADER_VERTEX)
          _mesa_update_vertex_processing_mode(ctx);
       return;
@@ -2660,6 +2694,7 @@ void GLAPIENTRY
 _mesa_PatchParameteri_no_error(GLenum pname, GLint value)
 {
    GET_CURRENT_CONTEXT(ctx);
+   FLUSH_VERTICES(ctx, 0);
    ctx->TessCtrlProgram.patch_vertices = value;
 }
 
@@ -2684,6 +2719,7 @@ _mesa_PatchParameteri(GLenum pname, GLint value)
       return;
    }
 
+   FLUSH_VERTICES(ctx, 0);
    ctx->TessCtrlProgram.patch_vertices = value;
 }
 
@@ -3162,6 +3198,7 @@ struct shader_includes {
    /* Array to hold include paths given to glCompileShaderIncludeARB() */
    struct sh_incl_path_entry **include_paths;
    size_t num_include_paths;
+   size_t relative_path_cursor;
 
    /* Root hash table holding the shader include tree */
    struct hash_table *shader_include_tree;
@@ -3176,6 +3213,18 @@ _mesa_init_shader_includes(struct gl_shared_state *shared)
                               _mesa_key_string_equal);
 }
 
+size_t
+_mesa_get_shader_include_cursor(struct gl_shared_state *shared)
+{
+   return shared->ShaderIncludes->relative_path_cursor;
+}
+
+void
+_mesa_set_shader_include_cursor(struct gl_shared_state *shared, size_t cursor)
+{
+   shared->ShaderIncludes->relative_path_cursor = cursor;
+}
+
 static void
 destroy_shader_include(struct hash_entry *entry)
 {
@@ -3196,11 +3245,11 @@ _mesa_destroy_shader_includes(struct gl_shared_state *shared)
 }
 
 static bool
-valid_path_format(const char *str)
+valid_path_format(const char *str, bool relative_path)
 {
    int i = 0;
 
-   if (!str[i] || str[i] != '/')
+   if (!str[i] || (!relative_path && str[i] != '/'))
       return false;
 
    i++;
@@ -3236,7 +3285,9 @@ validate_and_tokenise_sh_incl(struct gl_context *ctx,
                               struct sh_incl_path_entry **path_list,
                               char *full_path, bool error_check)
 {
-   if (!valid_path_format(full_path)) {
+   bool relative_path = ctx->Shared->ShaderIncludes->num_include_paths;
+
+   if (!valid_path_format(full_path, relative_path)) {
       if (error_check) {
          _mesa_error(ctx, GL_INVALID_VALUE,
                      "glNamedStringARB(invalid name %s)", full_path);
@@ -3280,9 +3331,9 @@ validate_and_tokenise_sh_incl(struct gl_context *ctx,
    return true;
 }
 
-const char *
-_mesa_lookup_shader_include(struct gl_context *ctx, char *path,
-                            bool error_check)
+static struct sh_incl_path_ht_entry *
+lookup_shader_include(struct gl_context *ctx, char *path,
+                      bool error_check)
 {
    void *mem_ctx = ralloc_context(NULL);
    struct sh_incl_path_entry *path_list;
@@ -3297,23 +3348,98 @@ _mesa_lookup_shader_include(struct gl_context *ctx, char *path,
    struct hash_table *path_ht =
       ctx->Shared->ShaderIncludes->shader_include_tree;
 
-   struct sh_incl_path_entry *entry;
-   foreach(entry, path_list) {
-      struct hash_entry *ht_entry =
-         _mesa_hash_table_search(path_ht, entry->path);
+   size_t count = ctx->Shared->ShaderIncludes->num_include_paths;
+   bool relative_path = path[0] != '/';
 
-      if (!ht_entry) {
-         return NULL;
-      } else {
-         sh_incl_ht_entry = (struct sh_incl_path_ht_entry *) ht_entry->data;
+   size_t i = ctx->Shared->ShaderIncludes->relative_path_cursor;
+   bool use_cursor = ctx->Shared->ShaderIncludes->relative_path_cursor;
+
+   do {
+      struct sh_incl_path_entry *entry;
+
+      if (relative_path) {
+next_relative_path:
+         {
+            struct sh_incl_path_entry *rel_path_list =
+               ctx->Shared->ShaderIncludes->include_paths[i];
+            foreach(entry, rel_path_list) {
+               struct hash_entry *ht_entry =
+                  _mesa_hash_table_search(path_ht, entry->path);
+
+               if (!ht_entry) {
+                  /* Reset search path and skip to the next include path */
+                  path_ht = ctx->Shared->ShaderIncludes->shader_include_tree;
+                  sh_incl_ht_entry = NULL;
+                  if (use_cursor) {
+                     i = 0;
+                     use_cursor = false;
+
+                     goto next_relative_path;
+                  }
+                  i++;
+                  if (i < count)
+                     goto next_relative_path;
+                  else
+                     break;
+               } else {
+                  sh_incl_ht_entry =
+                    (struct sh_incl_path_ht_entry *) ht_entry->data;
+               }
+
+               path_ht = sh_incl_ht_entry->path;
+            }
+         }
       }
 
-      path_ht = sh_incl_ht_entry->path;
-   }
+      foreach(entry, path_list) {
+         struct hash_entry *ht_entry =
+            _mesa_hash_table_search(path_ht, entry->path);
+
+         if (!ht_entry) {
+            /* Reset search path and skip to the next include path */
+            path_ht = ctx->Shared->ShaderIncludes->shader_include_tree;
+            sh_incl_ht_entry = NULL;
+            if (use_cursor) {
+               i = 0;
+               use_cursor = false;
+
+               break;
+            }
+            i++;
+            break;
+         } else {
+
+            sh_incl_ht_entry =
+               (struct sh_incl_path_ht_entry *) ht_entry->data;
+         }
+
+         path_ht = sh_incl_ht_entry->path;
+      }
+
+      if (i < count &&
+          (sh_incl_ht_entry == NULL || !sh_incl_ht_entry->shader_source))
+         continue;
+
+      /* If we get here then we have found a matching path or exahusted our
+       * relative search paths.
+       */
+      ctx->Shared->ShaderIncludes->relative_path_cursor = i;
+      break;
+   } while (i < count);
 
    ralloc_free(mem_ctx);
 
-   return sh_incl_ht_entry ? sh_incl_ht_entry->shader_source : NULL;
+   return sh_incl_ht_entry;
+}
+
+const char *
+_mesa_lookup_shader_include(struct gl_context *ctx, char *path,
+                            bool error_check)
+{
+   struct sh_incl_path_ht_entry *shader_include =
+      lookup_shader_include(ctx, path, error_check);
+
+   return shader_include ? shader_include->shader_source : NULL;
 }
 
 static char *
@@ -3405,18 +3531,114 @@ _mesa_NamedStringARB(GLenum type, GLint namelen, const GLchar *name,
 GLvoid GLAPIENTRY
 _mesa_DeleteNamedStringARB(GLint namelen, const GLchar *name)
 {
+   GET_CURRENT_CONTEXT(ctx);
+   const char *caller = "glDeleteNamedStringARB";
+
+   char *name_cp = copy_string(ctx, name, namelen, caller);
+   if (!name_cp)
+      return;
+
+   struct sh_incl_path_ht_entry *shader_include =
+      lookup_shader_include(ctx, name_cp, true);
+
+   if (!shader_include) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(no string associated with path %s)", caller, name_cp);
+      free(name_cp);
+      return;
+   }
+
+   mtx_lock(&ctx->Shared->ShaderIncludeMutex);
+
+   free(shader_include->shader_source);
+   shader_include->shader_source = NULL;
+
+   mtx_unlock(&ctx->Shared->ShaderIncludeMutex);
+
+   free(name_cp);
 }
 
 GLvoid GLAPIENTRY
 _mesa_CompileShaderIncludeARB(GLuint shader, GLsizei count,
                               const GLchar* const *path, const GLint *length)
 {
+   GET_CURRENT_CONTEXT(ctx);
+   const char *caller = "glCompileShaderIncludeARB";
+
+   if (count > 0 && path == NULL) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(count > 0 && path == NULL)",
+                  caller);
+      return;
+   }
+
+   void *mem_ctx = ralloc_context(NULL);
+
+   mtx_lock(&ctx->Shared->ShaderIncludeMutex);
+
+   ctx->Shared->ShaderIncludes->include_paths =
+      ralloc_array_size(mem_ctx, sizeof(struct sh_incl_path_entry *), count);
+
+   for (size_t i = 0; i < count; i++) {
+      char *path_cp = copy_string(ctx, path[i], length ? length[i] : -1,
+                                  caller);
+      if (!path_cp) {
+         goto exit;
+      }
+
+      struct sh_incl_path_entry *path_list;
+
+      if (!validate_and_tokenise_sh_incl(ctx, mem_ctx, &path_list, path_cp,
+                                         true)) {
+         free(path_cp);
+         goto exit;
+      }
+
+      ctx->Shared->ShaderIncludes->include_paths[i] = path_list;
+
+      free(path_cp);
+   }
+
+   /* We must set this *after* all calls to validate_and_tokenise_sh_incl()
+    * are done as we use this to decide if we need to check the start of the
+    * path for a '/'
+    */
+   ctx->Shared->ShaderIncludes->num_include_paths = count;
+
+   struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
+   if (!sh) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(shader)", caller);
+      goto exit;
+   }
+
+   _mesa_compile_shader(ctx, sh);
+
+exit:
+   ctx->Shared->ShaderIncludes->num_include_paths = 0;
+   ctx->Shared->ShaderIncludes->relative_path_cursor = 0;
+   ctx->Shared->ShaderIncludes->include_paths = NULL;
+
+   mtx_unlock(&ctx->Shared->ShaderIncludeMutex);
+
+   ralloc_free(mem_ctx);
 }
 
 GLboolean GLAPIENTRY
 _mesa_IsNamedStringARB(GLint namelen, const GLchar *name)
 {
-   return false;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!name)
+      return false;
+
+   char *name_cp = copy_string(ctx, name, namelen, "");
+
+   const char *source = _mesa_lookup_shader_include(ctx, name_cp, false);
+   free(name_cp);
+
+   if (!source)
+      return false;
+
+   return true;
 }
 
 GLvoid GLAPIENTRY
@@ -3451,6 +3673,34 @@ GLvoid GLAPIENTRY
 _mesa_GetNamedStringivARB(GLint namelen, const GLchar *name,
                           GLenum pname, GLint *params)
 {
+   GET_CURRENT_CONTEXT(ctx);
+   const char *caller = "glGetNamedStringivARB";
+
+   char *name_cp = copy_string(ctx, name, namelen, caller);
+   if (!name_cp)
+      return;
+
+   const char *source = _mesa_lookup_shader_include(ctx, name_cp, true);
+   if (!source) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(no string associated with path %s)", caller, name_cp);
+      free(name_cp);
+      return;
+   }
+
+   switch (pname) {
+   case GL_NAMED_STRING_LENGTH_ARB:
+      *params = strlen(source) + 1;
+      break;
+   case GL_NAMED_STRING_TYPE_ARB:
+      *params = GL_SHADER_INCLUDE_ARB;
+      break;
+   default:
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname)", caller);
+      break;
+   }
+
+   free(name_cp);
 }
 
 static int