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

Chia-I Wu olvaffe at gmail.com
Wed Jul 9 18:46:43 PDT 2014


On Wed, Jul 9, 2014 at 10:42 PM, Brian Paul <brianp at vmware.com> wrote:
> On 07/09/2014 01: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;
>
>
> AFAICT, TaskData is always a gl_context *.  If so, should it be changed to
> "struct gl_context *TaskContext"?  Same thing in gl_shader_program.
>
>
>
>
>>   };
>>
>>
>> @@ -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;
>> +}
>> +
>
>
>
>
> Can you add a comment on this function indicating that it's called from a
> threadpool thread?
This function is called from the main thread actually.  Only
deferred_compile_shader and deferred_link_program are called from a
threadpool thread.

I will update this patch to incorporate all other suggestions.  Thanks.

>
>
>> +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);
>> +}
>> +
>
>
>
> Maybe add a comment on this function too?
>
>
>> +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) {
>>         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.
>
>
> Update the comment to explain _no_wait ?
>
>
>>    */
>>   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.
>
>
> Update this comment too?
>
>
>>    */
>>   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,
>>
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev



-- 
olv at LunarG.com


More information about the mesa-dev mailing list