[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