[Mesa-dev] [PATCHv2 08/13] mesa: add infrastructure for threaded shader compilation

Ian Romanick idr at freedesktop.org
Wed Aug 13 13:35:30 PDT 2014


On 07/09/2014 12:47 AM, Chia-I Wu wrote:
> Add _mesa_enable_glsl_threadpool to enable the thread pool for a context, and
> add ctx->Const.DeferCompileShader and ctx->Const.DeferLinkProgram to
> fine-control what gets threaded.
> 
> Setting DeferCompileShader to true will make _mesa_glsl_compile_shader be
> executed in a worker thread.  The function is thread-safe so there is no
> restriction on DeferCompileShader.
> 
> Setting DeferLinkProgram to true will make _mesa_glsl_link_shader be executed
> in a worker thread.  The function is thread-safe only when certain driver
> functions (as documented in struct gl_constants) are thread-safe.  It is
> drivers' responsibility to fix those driver functions before setting
> DeferLinkProgram.
> 
> When DeferLinkProgram is set, drivers are not supposed to inspect the context
> in their LinkShader callbacks.  Instead, NotifyLinkShader is added.  Drivers
> should inspect the context in NotifyLinkShader and save what they need for
> LinkShader in gl_shader_program.
> 
> As a final note, most applications will not benefit from threaded shader
> compilation because they check GL_COMPILE_STATUS/GL_LINK_STATUS immediately,
> giving the worker threads no time to do their jobs.  A possible improvement is
> to split LinkShader into two parts: the first part links and error checks
> while the second part optimizes and generates the machine code.  With the
> split, we can always defer the second part to the thread pool.
> 
> Signed-off-by: Chia-I Wu <olv at lunarg.com>
> ---
>  src/mesa/main/context.c     |  29 +++++++++++
>  src/mesa/main/context.h     |   3 ++
>  src/mesa/main/dd.h          |   8 +++
>  src/mesa/main/mtypes.h      |  34 ++++++++++++
>  src/mesa/main/pipelineobj.c |  18 +++++++
>  src/mesa/main/shaderapi.c   | 122 +++++++++++++++++++++++++++++++++++++++-----
>  src/mesa/main/shaderobj.c   |  74 +++++++++++++++++++++++++--
>  src/mesa/main/shaderobj.h   |  55 ++++++++++++++++++--
>  8 files changed, 322 insertions(+), 21 deletions(-)
> 
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index b082159..e27450c 100644
> --- a/src/mesa/main/context.c
> +++ b/src/mesa/main/context.c
> @@ -112,6 +112,7 @@
>  #include "points.h"
>  #include "polygon.h"
>  #include "queryobj.h"
> +#include "shaderapi.h"
>  #include "syncobj.h"
>  #include "rastpos.h"
>  #include "remap.h"
> @@ -139,6 +140,7 @@
>  #endif
>  
>  #include "glsl_parser_extras.h"
> +#include "threadpool.h"
>  #include <stdbool.h>
>  
>  
> @@ -1187,6 +1189,27 @@ _mesa_create_context(gl_api api,
>     }
>  }
>  
> +void
> +_mesa_enable_glsl_threadpool(struct gl_context *ctx, int max_threads)
> +{
> +   if (!ctx->ThreadPool)
> +      ctx->ThreadPool = _mesa_glsl_get_threadpool(max_threads);
> +}
> +
> +static void
> +wait_shader_object_cb(GLuint id, void *data, void *userData)
> +{
> +   struct gl_context *ctx = (struct gl_context *) userData;
> +   struct gl_shader *sh = (struct gl_shader *) data;
> +
> +   if (_mesa_validate_shader_target(ctx, sh->Type)) {
> +      _mesa_wait_shaders(ctx, &sh, 1);
> +   }
> +   else {
> +      struct gl_shader_program *shProg = (struct gl_shader_program *) data;
> +      _mesa_wait_shader_program(ctx, shProg);
> +   }
> +}
>  
>  /**
>   * Free the data associated with the given context.
> @@ -1205,6 +1228,12 @@ _mesa_free_context_data( struct gl_context *ctx )
>        _mesa_make_current(ctx, NULL, NULL);
>     }
>  
> +   if (ctx->ThreadPool) {
> +      _mesa_HashWalk(ctx->Shared->ShaderObjects, wait_shader_object_cb, ctx);
> +      _mesa_threadpool_unref(ctx->ThreadPool);
> +      ctx->ThreadPool = NULL;
> +   }
> +
>     /* unreference WinSysDraw/Read buffers */
>     _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
>     _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
> diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h
> index 792ab4c..b23f9fa 100644
> --- a/src/mesa/main/context.h
> +++ b/src/mesa/main/context.h
> @@ -118,6 +118,9 @@ _mesa_create_context(gl_api api,
>                       const struct dd_function_table *driverFunctions);
>  
>  extern void
> +_mesa_enable_glsl_threadpool(struct gl_context *ctx, int max_threads);
> +
> +extern void
>  _mesa_free_context_data( struct gl_context *ctx );
>  
>  extern void
> diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
> index 633ea2c..38f8c68 100644
> --- a/src/mesa/main/dd.h
> +++ b/src/mesa/main/dd.h
> @@ -447,6 +447,14 @@ struct dd_function_table {
>      */
>     /*@{*/
>     /**
> +    * Called when a shader program is to be linked.
> +    *
> +    * This is optional and gives drivers an opportunity to inspect the context
> +    * and prepare for LinkShader, which may be deferred to another thread.
> +    */
> +   void (*NotifyLinkShader)(struct gl_context *ctx,
> +                            struct gl_shader_program *shader);
> +   /**
>      * Called when a shader program is linked.
>      *
>      * This gives drivers an opportunity to clone the IR and make their
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index 5964576..316da23 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -71,6 +71,8 @@ typedef GLuint64 GLbitfield64;
>   */
>  /*@{*/
>  struct _mesa_HashTable;
> +struct _mesa_threadpool;
> +struct _mesa_threadpool_task;
>  struct gl_attrib_node;
>  struct gl_list_extensions;
>  struct gl_meta_state;
> @@ -2510,6 +2512,14 @@ struct gl_shader
>         */
>        unsigned LocalSize[3];
>     } Comp;
> +
> +   /**
> +    * Deferred task of glCompileShader.  We should extend the mutex, not only
> +    * to protect the deferred task, but to protect the entire gl_shader.
> +    */
> +   mtx_t Mutex;
> +   struct _mesa_threadpool_task *Task;
> +   void *TaskData;
>  };
>  
>  
> @@ -2770,6 +2780,15 @@ struct gl_shader_program
>      * #extension ARB_fragment_coord_conventions: enable
>      */
>     GLboolean ARB_fragment_coord_conventions_enable;
> +
> +   /**
> +    * Deferred task of glLinkProgram.  We should extend the mutex, not only
> +    * to protect the deferred task, but to protect the entire
> +    * gl_shader_program.
> +    */
> +   mtx_t Mutex;
> +   struct _mesa_threadpool_task *Task;
> +   void *TaskData;
>  };   
>  
>  
> @@ -3489,6 +3508,18 @@ struct gl_constants
>     GLfloat MaxFragmentInterpolationOffset;
>  
>     GLboolean FakeSWMSAA;
> +
> +   /*
> +    * Defer certain operations to a thread pool.
> +    *
> +    * When DeferLinkProgram is set, these functions must be thread-safe
> +    *
> +    *   ctx->Driver.NewShader
> +    *   ctx->Driver.DeleteShader
> +    *   ctx->Driver.LinkShader
> +    */
> +   GLboolean DeferCompileShader;
> +   GLboolean DeferLinkProgram;
>  };
>  
>  
> @@ -4262,6 +4293,9 @@ struct gl_context
>      * Once this field becomes true, it is never reset to false.
>      */
>     GLboolean ShareGroupReset;
> +
> +   /* A thread pool for threaded shader compilation */
> +   struct _mesa_threadpool *ThreadPool;
>  };
>  
>  
> diff --git a/src/mesa/main/pipelineobj.c b/src/mesa/main/pipelineobj.c
> index 90c1d00..ae4f80a 100644
> --- a/src/mesa/main/pipelineobj.c
> +++ b/src/mesa/main/pipelineobj.c
> @@ -211,6 +211,24 @@ _mesa_reference_pipeline_object_(struct gl_context *ctx,
>        }
>        else {
>           obj->RefCount++;
> +
> +         /*
> +          * The current pipeline object (as set by glUseProgram or
> +          * glBindProgramPipeline) cannot have unfinished tasks.
> +          */
> +         if (ptr == &ctx->_Shader) {
> +            if (obj->ActiveProgram)
> +               _mesa_wait_shader_program(ctx, obj->ActiveProgram);
> +            if (obj->Name) {
> +               int i;
> +
> +               for (i = 0; i < MESA_SHADER_STAGES; i++) {
> +                  if (obj->CurrentProgram[i])
> +                     _mesa_wait_shader_program(ctx, obj->CurrentProgram[i]);
> +               }
> +            }
> +         }
> +
>           *ptr = obj;
>        }
>        mtx_unlock(&obj->Mutex);
> diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
> index 2bbef35..339d7a2 100644
> --- a/src/mesa/main/shaderapi.c
> +++ b/src/mesa/main/shaderapi.c
> @@ -53,6 +53,7 @@
>  #include "program/prog_print.h"
>  #include "program/prog_parameter.h"
>  #include "ralloc.h"
> +#include "threadpool.h"
>  #include <stdbool.h>
>  #include "../glsl/glsl_parser_extras.h"
>  #include "../glsl/ir.h"
> @@ -210,7 +211,8 @@ _mesa_validate_shader_target(const struct gl_context *ctx, GLenum type)
>  static GLboolean
>  is_program(struct gl_context *ctx, GLuint name)
>  {
> -   struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
> +   struct gl_shader_program *shProg =
> +      _mesa_lookup_shader_program_no_wait(ctx, name);
>     return shProg ? GL_TRUE : GL_FALSE;
>  }
>  
> @@ -218,7 +220,7 @@ is_program(struct gl_context *ctx, GLuint name)
>  static GLboolean
>  is_shader(struct gl_context *ctx, GLuint name)
>  {
> -   struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
> +   struct gl_shader *shader = _mesa_lookup_shader_no_wait(ctx, name);
>     return shader ? GL_TRUE : GL_FALSE;
>  }
>  
> @@ -239,7 +241,7 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
>     if (!shProg)
>        return;
>  
> -   sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
> +   sh = _mesa_lookup_shader_err_no_wait(ctx, shader, "glAttachShader");
>     if (!sh) {
>        return;
>     }
> @@ -341,7 +343,9 @@ delete_shader_program(struct gl_context *ctx, GLuint name)
>      */
>     struct gl_shader_program *shProg;
>  
> -   shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
> +   /* no waiting until _mesa_delete_shader_program() */
> +   shProg = _mesa_lookup_shader_program_err_no_wait(ctx, name,
> +                                                    "glDeleteProgram");
>     if (!shProg)
>        return;
>  
> @@ -359,7 +363,8 @@ delete_shader(struct gl_context *ctx, GLuint shader)
>  {
>     struct gl_shader *sh;
>  
> -   sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
> +   /* no waiting until _mesa_delete_shader() */
> +   sh = _mesa_lookup_shader_err_no_wait(ctx, shader, "glDeleteShader");
>     if (!sh)
>        return;
>  
> @@ -812,6 +817,48 @@ shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
>  #endif
>  }
>  
> +static bool
> +can_queue_task(struct gl_context *ctx)
> +{
> +   if (!ctx->ThreadPool)
> +      return false;
> +
> +   /* MESA_GLSL is set */
> +   if (ctx->_Shader->Flags)
> +      return false;
> +
> +   /* context requires synchronized compiler warnings and errors */
> +   if (_mesa_get_debug_state_int(ctx, GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB))
> +      return false;
> +
> +   return true;
> +}
> +
> +static void
> +deferred_compile_shader(void *data)
> +{
> +   struct gl_shader *sh = (struct gl_shader *) data;
> +   struct gl_context *ctx = (struct gl_context *) sh->TaskData;
> +
> +   _mesa_glsl_compile_shader(ctx, sh, false, false);
> +}
> +
> +static bool
> +queue_compile_shader(struct gl_context *ctx, struct gl_shader *sh)
> +{
> +   if (!can_queue_task(ctx))
> +      return false;
> +   if (!ctx->Const.DeferCompileShader)
> +      return false;
> +
> +   sh->TaskData = (void *) ctx;
> +   sh->Task = _mesa_threadpool_queue_task(ctx->ThreadPool,
> +         deferred_compile_shader, (void *) sh);
> +   if (!sh->Task)
> +      sh->TaskData = NULL;
> +
> +   return (sh->Task != NULL);
> +}
>  
>  /**
>   * Compile a shader.
> @@ -844,10 +891,12 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
>           fflush(stderr);
>        }
>  
> -      /* this call will set the shader->CompileStatus field to indicate if
> -       * compilation was successful.
> +      /* This call will set the shader->CompileStatus field to indicate if
> +       * compilation was successful.  But if queueing succeeded, the field
> +       * will be set at a later point.
>         */
> -      _mesa_glsl_compile_shader(ctx, sh, false, false);
> +      if (!queue_compile_shader(ctx, sh))
> +         _mesa_glsl_compile_shader(ctx, sh, false, false);
>  
>        if (ctx->_Shader->Flags & GLSL_LOG) {
>           _mesa_write_shader_to_file(sh);
> @@ -870,7 +919,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
>  
>     }
>  
> -   if (!sh->CompileStatus) {
> +   if (ctx->_Shader->Flags && !sh->CompileStatus) {

I don't understand this change.  Is this because when Flags is set it
won't use the background compile?  Aren't there other things that could
cause queue_compile_shader to fail that would result in
GLSL_DUMP_ON_ERROR being ignored here?

>        if (ctx->_Shader->Flags & GLSL_DUMP_ON_ERROR) {
>           fprintf(stderr, "GLSL source for %s shader %d:\n",
>                   _mesa_shader_stage_to_string(sh->Stage), sh->Name);
> @@ -887,6 +936,49 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
>  }
>  
>  
> +static void
> +deferred_link_program(void *data)
> +{
> +   struct gl_shader_program *shProg = (struct gl_shader_program *) data;
> +   struct gl_context *ctx = (struct gl_context *) shProg->TaskData;
> +
> +   _mesa_wait_shaders(ctx, shProg->Shaders, shProg->NumShaders);
> +   _mesa_glsl_link_shader(ctx, shProg);
> +}
> +
> +static bool
> +queue_link_program(struct gl_context *ctx, struct gl_shader_program *shProg)
> +{
> +   int i;
> +
> +   if (!can_queue_task(ctx))
> +      return false;
> +   if (!ctx->Const.DeferLinkProgram)
> +      return false;
> +
> +   /*
> +    * Rather than adding _mesa_wait_shader_program calls here and there, we
> +    * simply disallow threaded linking when the program is current or active.
> +    */
> +   if (ctx->_Shader->ActiveProgram == shProg)
> +      return false;
> +   /* be careful for separate programs */
> +   if (ctx->_Shader->Name != 0) {
> +      for (i = 0; i < MESA_SHADER_STAGES; i++) {
> +         if (ctx->_Shader->CurrentProgram[i] == shProg)
> +            return false;
> +      }
> +   }
> +
> +   shProg->TaskData = (void *) ctx;
> +   shProg->Task = _mesa_threadpool_queue_task(ctx->ThreadPool,
> +         deferred_link_program, (void *) shProg);
> +   if (!shProg->Task)
> +      shProg->TaskData = NULL;
> +
> +   return (shProg->Task != NULL);
> +}
> +
>  /**
>   * Link a program's shaders.
>   */
> @@ -912,10 +1004,16 @@ link_program(struct gl_context *ctx, GLuint program)
>  
>     FLUSH_VERTICES(ctx, _NEW_PROGRAM);
>  
> -   _mesa_glsl_link_shader(ctx, shProg);
> +   if (ctx->Driver.NotifyLinkShader)
> +      ctx->Driver.NotifyLinkShader(ctx, shProg);
> +
> +   if (!queue_link_program(ctx, shProg)) {
> +      _mesa_wait_shaders(ctx, shProg->Shaders, shProg->NumShaders);
> +      _mesa_glsl_link_shader(ctx, shProg);
> +   }
>  
> -   if (shProg->LinkStatus == GL_FALSE && 
> -       (ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
> +   if ((ctx->_Shader->Flags & GLSL_REPORT_ERRORS) &&
> +       shProg->LinkStatus == GL_FALSE) {
>        _mesa_debug(ctx, "Error linking program %u:\n%s\n",
>                    shProg->Name, shProg->InfoLog);
>     }
> diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c
> index b9feff4..ab94d14 100644
> --- a/src/mesa/main/shaderobj.c
> +++ b/src/mesa/main/shaderobj.c
> @@ -41,6 +41,7 @@
>  #include "program/prog_parameter.h"
>  #include "program/hash_table.h"
>  #include "ralloc.h"
> +#include "threadpool.h"
>  
>  /**********************************************************************/
>  /*** Shader object functions                                        ***/
> @@ -95,6 +96,7 @@ _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
>  void
>  _mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader)
>  {
> +   mtx_init(&shader->Mutex, mtx_plain);
>     shader->RefCount = 1;
>  }
>  
> @@ -125,18 +127,51 @@ _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
>  static void
>  _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
>  {
> +   _mesa_wait_shaders(ctx, &sh, 1);
> +
>     free((void *)sh->Source);
>     free(sh->Label);
>     _mesa_reference_program(ctx, &sh->Program, NULL);
> +   mtx_destroy(&sh->Mutex);
>     ralloc_free(sh);
>  }
>  
>  
>  /**
> + * Wait for the threaded compile tasks to complete.
> + */
> +void
> +_mesa_wait_shaders(struct gl_context *ctx,
> +                   struct gl_shader **shaders,
> +                   int num_shaders)
> +{
> +   int i;
> +
> +   for (i = 0; i < num_shaders; i++) {
> +      struct gl_shader *sh = shaders[i];
> +
> +      mtx_lock(&sh->Mutex);
> +
> +      if (sh->Task) {
> +         struct gl_context *task_ctx = (struct gl_context *) sh->TaskData;
> +
> +         if (!_mesa_threadpool_complete_task(task_ctx->ThreadPool, sh->Task))
> +            sh->CompileStatus = GL_FALSE;
> +
> +         sh->Task = NULL;
> +         sh->TaskData = NULL;
> +      }
> +
> +      mtx_unlock(&sh->Mutex);
> +   }
> +}
> +
> +
> +/**
>   * Lookup a GLSL shader object.
>   */
>  struct gl_shader *
> -_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
> +_mesa_lookup_shader_no_wait(struct gl_context *ctx, GLuint name)
>  {
>     if (name) {
>        struct gl_shader *sh = (struct gl_shader *)
> @@ -158,7 +193,8 @@ _mesa_lookup_shader(struct gl_context *ctx, GLuint name)
>   * As above, but record an error if shader is not found.
>   */
>  struct gl_shader *
> -_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
> +_mesa_lookup_shader_err_no_wait(struct gl_context *ctx, GLuint name,
> +                                const char *caller)
>  {
>     if (!name) {
>        _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
> @@ -238,6 +274,8 @@ _mesa_reference_shader_program(struct gl_context *ctx,
>  void
>  _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog)
>  {
> +   mtx_init(&prog->Mutex, mtx_plain);
> +
>     prog->Type = GL_SHADER_PROGRAM_MESA;
>     prog->RefCount = 1;
>  
> @@ -373,17 +411,43 @@ _mesa_free_shader_program_data(struct gl_context *ctx,
>  static void
>  _mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg)
>  {
> +   _mesa_wait_shader_program(ctx, shProg);
> +
>     _mesa_free_shader_program_data(ctx, shProg);
> +   mtx_destroy(&shProg->Mutex);
>  
>     ralloc_free(shProg);
>  }
>  
>  
>  /**
> + * Wait for the threaded linking task to complete.
> + */
> +void
> +_mesa_wait_shader_program(struct gl_context *ctx,
> +                          struct gl_shader_program *shProg)
> +{
> +   mtx_lock(&shProg->Mutex);
> +
> +   if (shProg->Task) {
> +      struct gl_context *task_ctx = (struct gl_context *) shProg->TaskData;
> +
> +      if (!_mesa_threadpool_complete_task(task_ctx->ThreadPool,
> +                                          shProg->Task))
> +         shProg->LinkStatus = GL_FALSE;
> +      shProg->Task = NULL;
> +      shProg->TaskData = NULL;
> +   }
> +
> +   mtx_unlock(&shProg->Mutex);
> +}
> +
> +
> +/**
>   * Lookup a GLSL program object.
>   */
>  struct gl_shader_program *
> -_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
> +_mesa_lookup_shader_program_no_wait(struct gl_context *ctx, GLuint name)
>  {
>     struct gl_shader_program *shProg;
>     if (name) {
> @@ -406,8 +470,8 @@ _mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
>   * As above, but record an error if program is not found.
>   */
>  struct gl_shader_program *
> -_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
> -                                const char *caller)
> +_mesa_lookup_shader_program_err_no_wait(struct gl_context *ctx, GLuint name,
> +                                        const char *caller)
>  {
>     if (!name) {
>        _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
> diff --git a/src/mesa/main/shaderobj.h b/src/mesa/main/shaderobj.h
> index fae8be8..c2f8a0d 100644
> --- a/src/mesa/main/shaderobj.h
> +++ b/src/mesa/main/shaderobj.h
> @@ -53,13 +53,35 @@ extern void
>  _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
>                         struct gl_shader *sh);
>  
> +extern void
> +_mesa_wait_shaders(struct gl_context *ctx,
> +                   struct gl_shader **shaders,
> +                   int num_shaders);
> +
>  extern struct gl_shader *
> -_mesa_lookup_shader(struct gl_context *ctx, GLuint name);
> +_mesa_lookup_shader_no_wait(struct gl_context *ctx, GLuint name);
>  
>  extern struct gl_shader *
> -_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller);
> +_mesa_lookup_shader_err_no_wait(struct gl_context *ctx, GLuint name,
> +                                const char *caller);
>  
> +static inline struct gl_shader *
> +_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
> +{
> +   struct gl_shader *sh = _mesa_lookup_shader_no_wait(ctx, name);
> +   if (sh)
> +      _mesa_wait_shaders(ctx, &sh, 1);
> +   return sh;
> +}
>  
> +static inline struct gl_shader *
> +_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
> +{
> +   struct gl_shader *sh = _mesa_lookup_shader_err_no_wait(ctx, name, caller);
> +   if (sh)
> +      _mesa_wait_shaders(ctx, &sh, 1);
> +   return sh;
> +}
>  
>  extern void
>  _mesa_reference_shader_program(struct gl_context *ctx,
> @@ -74,12 +96,37 @@ _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
>  extern void
>  _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog);
>  
> +extern void
> +_mesa_wait_shader_program(struct gl_context *ctx,
> +                          struct gl_shader_program *shProg);
> +
>  extern struct gl_shader_program *
> -_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name);
> +_mesa_lookup_shader_program_no_wait(struct gl_context *ctx, GLuint name);
>  
>  extern struct gl_shader_program *
> +_mesa_lookup_shader_program_err_no_wait(struct gl_context *ctx, GLuint name,
> +                                        const char *caller);
> +
> +static inline struct gl_shader_program *
> +_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
> +{
> +   struct gl_shader_program *shProg =
> +      _mesa_lookup_shader_program_no_wait(ctx, name);
> +   if (shProg)
> +      _mesa_wait_shader_program(ctx, shProg);
> +   return shProg;
> +}
> +
> +static inline struct gl_shader_program *
>  _mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
> -                                const char *caller);
> +                                const char *caller)
> +{
> +   struct gl_shader_program *shProg =
> +      _mesa_lookup_shader_program_err_no_wait(ctx, name, caller);
> +   if (shProg)
> +      _mesa_wait_shader_program(ctx, shProg);
> +   return shProg;
> +}
>  
>  extern void
>  _mesa_clear_shader_program_data(struct gl_context *ctx,
> 



More information about the mesa-dev mailing list