On Thu, Aug 14, 2014 at 4:35 AM, Ian Romanick <i...@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 <o...@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, >> > -- o...@lunarg.com _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev