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

Chia-I Wu olvaffe at gmail.com
Tue Aug 19 00:33:08 PDT 2014


On Thu, Aug 14, 2014 at 4:35 AM, Ian Romanick <idr at freedesktop.org> wrote:
> 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?
CompileStatus is not available immediately unless Flags is set (or
some other conditions are satisfied).  Everything inside this if-block
tests Flags before doing something so testing Flags here should not
cause anything to be skipped.

>
>>        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,
>>
>



-- 
olv at LunarG.com


More information about the mesa-dev mailing list