[Mesa-dev] [PATCHv2 08/13] mesa: add infrastructure for threaded shader compilation
Ian Romanick
idr at freedesktop.org
Wed Aug 13 13:35:30 PDT 2014
On 07/09/2014 12:47 AM, Chia-I Wu wrote:
> Add _mesa_enable_glsl_threadpool to enable the thread pool for a context, and
> add ctx->Const.DeferCompileShader and ctx->Const.DeferLinkProgram to
> fine-control what gets threaded.
>
> Setting DeferCompileShader to true will make _mesa_glsl_compile_shader be
> executed in a worker thread. The function is thread-safe so there is no
> restriction on DeferCompileShader.
>
> Setting DeferLinkProgram to true will make _mesa_glsl_link_shader be executed
> in a worker thread. The function is thread-safe only when certain driver
> functions (as documented in struct gl_constants) are thread-safe. It is
> drivers' responsibility to fix those driver functions before setting
> DeferLinkProgram.
>
> When DeferLinkProgram is set, drivers are not supposed to inspect the context
> in their LinkShader callbacks. Instead, NotifyLinkShader is added. Drivers
> should inspect the context in NotifyLinkShader and save what they need for
> LinkShader in gl_shader_program.
>
> As a final note, most applications will not benefit from threaded shader
> compilation because they check GL_COMPILE_STATUS/GL_LINK_STATUS immediately,
> giving the worker threads no time to do their jobs. A possible improvement is
> to split LinkShader into two parts: the first part links and error checks
> while the second part optimizes and generates the machine code. With the
> split, we can always defer the second part to the thread pool.
>
> Signed-off-by: Chia-I Wu <olv at lunarg.com>
> ---
> src/mesa/main/context.c | 29 +++++++++++
> src/mesa/main/context.h | 3 ++
> src/mesa/main/dd.h | 8 +++
> src/mesa/main/mtypes.h | 34 ++++++++++++
> src/mesa/main/pipelineobj.c | 18 +++++++
> src/mesa/main/shaderapi.c | 122 +++++++++++++++++++++++++++++++++++++++-----
> src/mesa/main/shaderobj.c | 74 +++++++++++++++++++++++++--
> src/mesa/main/shaderobj.h | 55 ++++++++++++++++++--
> 8 files changed, 322 insertions(+), 21 deletions(-)
>
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index b082159..e27450c 100644
> --- a/src/mesa/main/context.c
> +++ b/src/mesa/main/context.c
> @@ -112,6 +112,7 @@
> #include "points.h"
> #include "polygon.h"
> #include "queryobj.h"
> +#include "shaderapi.h"
> #include "syncobj.h"
> #include "rastpos.h"
> #include "remap.h"
> @@ -139,6 +140,7 @@
> #endif
>
> #include "glsl_parser_extras.h"
> +#include "threadpool.h"
> #include <stdbool.h>
>
>
> @@ -1187,6 +1189,27 @@ _mesa_create_context(gl_api api,
> }
> }
>
> +void
> +_mesa_enable_glsl_threadpool(struct gl_context *ctx, int max_threads)
> +{
> + if (!ctx->ThreadPool)
> + ctx->ThreadPool = _mesa_glsl_get_threadpool(max_threads);
> +}
> +
> +static void
> +wait_shader_object_cb(GLuint id, void *data, void *userData)
> +{
> + struct gl_context *ctx = (struct gl_context *) userData;
> + struct gl_shader *sh = (struct gl_shader *) data;
> +
> + if (_mesa_validate_shader_target(ctx, sh->Type)) {
> + _mesa_wait_shaders(ctx, &sh, 1);
> + }
> + else {
> + struct gl_shader_program *shProg = (struct gl_shader_program *) data;
> + _mesa_wait_shader_program(ctx, shProg);
> + }
> +}
>
> /**
> * Free the data associated with the given context.
> @@ -1205,6 +1228,12 @@ _mesa_free_context_data( struct gl_context *ctx )
> _mesa_make_current(ctx, NULL, NULL);
> }
>
> + if (ctx->ThreadPool) {
> + _mesa_HashWalk(ctx->Shared->ShaderObjects, wait_shader_object_cb, ctx);
> + _mesa_threadpool_unref(ctx->ThreadPool);
> + ctx->ThreadPool = NULL;
> + }
> +
> /* unreference WinSysDraw/Read buffers */
> _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
> _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
> diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h
> index 792ab4c..b23f9fa 100644
> --- a/src/mesa/main/context.h
> +++ b/src/mesa/main/context.h
> @@ -118,6 +118,9 @@ _mesa_create_context(gl_api api,
> const struct dd_function_table *driverFunctions);
>
> extern void
> +_mesa_enable_glsl_threadpool(struct gl_context *ctx, int max_threads);
> +
> +extern void
> _mesa_free_context_data( struct gl_context *ctx );
>
> extern void
> diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
> index 633ea2c..38f8c68 100644
> --- a/src/mesa/main/dd.h
> +++ b/src/mesa/main/dd.h
> @@ -447,6 +447,14 @@ struct dd_function_table {
> */
> /*@{*/
> /**
> + * Called when a shader program is to be linked.
> + *
> + * This is optional and gives drivers an opportunity to inspect the context
> + * and prepare for LinkShader, which may be deferred to another thread.
> + */
> + void (*NotifyLinkShader)(struct gl_context *ctx,
> + struct gl_shader_program *shader);
> + /**
> * Called when a shader program is linked.
> *
> * This gives drivers an opportunity to clone the IR and make their
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index 5964576..316da23 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -71,6 +71,8 @@ typedef GLuint64 GLbitfield64;
> */
> /*@{*/
> struct _mesa_HashTable;
> +struct _mesa_threadpool;
> +struct _mesa_threadpool_task;
> struct gl_attrib_node;
> struct gl_list_extensions;
> struct gl_meta_state;
> @@ -2510,6 +2512,14 @@ struct gl_shader
> */
> unsigned LocalSize[3];
> } Comp;
> +
> + /**
> + * Deferred task of glCompileShader. We should extend the mutex, not only
> + * to protect the deferred task, but to protect the entire gl_shader.
> + */
> + mtx_t Mutex;
> + struct _mesa_threadpool_task *Task;
> + void *TaskData;
> };
>
>
> @@ -2770,6 +2780,15 @@ struct gl_shader_program
> * #extension ARB_fragment_coord_conventions: enable
> */
> GLboolean ARB_fragment_coord_conventions_enable;
> +
> + /**
> + * Deferred task of glLinkProgram. We should extend the mutex, not only
> + * to protect the deferred task, but to protect the entire
> + * gl_shader_program.
> + */
> + mtx_t Mutex;
> + struct _mesa_threadpool_task *Task;
> + void *TaskData;
> };
>
>
> @@ -3489,6 +3508,18 @@ struct gl_constants
> GLfloat MaxFragmentInterpolationOffset;
>
> GLboolean FakeSWMSAA;
> +
> + /*
> + * Defer certain operations to a thread pool.
> + *
> + * When DeferLinkProgram is set, these functions must be thread-safe
> + *
> + * ctx->Driver.NewShader
> + * ctx->Driver.DeleteShader
> + * ctx->Driver.LinkShader
> + */
> + GLboolean DeferCompileShader;
> + GLboolean DeferLinkProgram;
> };
>
>
> @@ -4262,6 +4293,9 @@ struct gl_context
> * Once this field becomes true, it is never reset to false.
> */
> GLboolean ShareGroupReset;
> +
> + /* A thread pool for threaded shader compilation */
> + struct _mesa_threadpool *ThreadPool;
> };
>
>
> diff --git a/src/mesa/main/pipelineobj.c b/src/mesa/main/pipelineobj.c
> index 90c1d00..ae4f80a 100644
> --- a/src/mesa/main/pipelineobj.c
> +++ b/src/mesa/main/pipelineobj.c
> @@ -211,6 +211,24 @@ _mesa_reference_pipeline_object_(struct gl_context *ctx,
> }
> else {
> obj->RefCount++;
> +
> + /*
> + * The current pipeline object (as set by glUseProgram or
> + * glBindProgramPipeline) cannot have unfinished tasks.
> + */
> + if (ptr == &ctx->_Shader) {
> + if (obj->ActiveProgram)
> + _mesa_wait_shader_program(ctx, obj->ActiveProgram);
> + if (obj->Name) {
> + int i;
> +
> + for (i = 0; i < MESA_SHADER_STAGES; i++) {
> + if (obj->CurrentProgram[i])
> + _mesa_wait_shader_program(ctx, obj->CurrentProgram[i]);
> + }
> + }
> + }
> +
> *ptr = obj;
> }
> mtx_unlock(&obj->Mutex);
> diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
> index 2bbef35..339d7a2 100644
> --- a/src/mesa/main/shaderapi.c
> +++ b/src/mesa/main/shaderapi.c
> @@ -53,6 +53,7 @@
> #include "program/prog_print.h"
> #include "program/prog_parameter.h"
> #include "ralloc.h"
> +#include "threadpool.h"
> #include <stdbool.h>
> #include "../glsl/glsl_parser_extras.h"
> #include "../glsl/ir.h"
> @@ -210,7 +211,8 @@ _mesa_validate_shader_target(const struct gl_context *ctx, GLenum type)
> static GLboolean
> is_program(struct gl_context *ctx, GLuint name)
> {
> - struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_no_wait(ctx, name);
> return shProg ? GL_TRUE : GL_FALSE;
> }
>
> @@ -218,7 +220,7 @@ is_program(struct gl_context *ctx, GLuint name)
> static GLboolean
> is_shader(struct gl_context *ctx, GLuint name)
> {
> - struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
> + struct gl_shader *shader = _mesa_lookup_shader_no_wait(ctx, name);
> return shader ? GL_TRUE : GL_FALSE;
> }
>
> @@ -239,7 +241,7 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
> if (!shProg)
> return;
>
> - sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
> + sh = _mesa_lookup_shader_err_no_wait(ctx, shader, "glAttachShader");
> if (!sh) {
> return;
> }
> @@ -341,7 +343,9 @@ delete_shader_program(struct gl_context *ctx, GLuint name)
> */
> struct gl_shader_program *shProg;
>
> - shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
> + /* no waiting until _mesa_delete_shader_program() */
> + shProg = _mesa_lookup_shader_program_err_no_wait(ctx, name,
> + "glDeleteProgram");
> if (!shProg)
> return;
>
> @@ -359,7 +363,8 @@ delete_shader(struct gl_context *ctx, GLuint shader)
> {
> struct gl_shader *sh;
>
> - sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
> + /* no waiting until _mesa_delete_shader() */
> + sh = _mesa_lookup_shader_err_no_wait(ctx, shader, "glDeleteShader");
> if (!sh)
> return;
>
> @@ -812,6 +817,48 @@ shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
> #endif
> }
>
> +static bool
> +can_queue_task(struct gl_context *ctx)
> +{
> + if (!ctx->ThreadPool)
> + return false;
> +
> + /* MESA_GLSL is set */
> + if (ctx->_Shader->Flags)
> + return false;
> +
> + /* context requires synchronized compiler warnings and errors */
> + if (_mesa_get_debug_state_int(ctx, GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB))
> + return false;
> +
> + return true;
> +}
> +
> +static void
> +deferred_compile_shader(void *data)
> +{
> + struct gl_shader *sh = (struct gl_shader *) data;
> + struct gl_context *ctx = (struct gl_context *) sh->TaskData;
> +
> + _mesa_glsl_compile_shader(ctx, sh, false, false);
> +}
> +
> +static bool
> +queue_compile_shader(struct gl_context *ctx, struct gl_shader *sh)
> +{
> + if (!can_queue_task(ctx))
> + return false;
> + if (!ctx->Const.DeferCompileShader)
> + return false;
> +
> + sh->TaskData = (void *) ctx;
> + sh->Task = _mesa_threadpool_queue_task(ctx->ThreadPool,
> + deferred_compile_shader, (void *) sh);
> + if (!sh->Task)
> + sh->TaskData = NULL;
> +
> + return (sh->Task != NULL);
> +}
>
> /**
> * Compile a shader.
> @@ -844,10 +891,12 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
> fflush(stderr);
> }
>
> - /* this call will set the shader->CompileStatus field to indicate if
> - * compilation was successful.
> + /* This call will set the shader->CompileStatus field to indicate if
> + * compilation was successful. But if queueing succeeded, the field
> + * will be set at a later point.
> */
> - _mesa_glsl_compile_shader(ctx, sh, false, false);
> + if (!queue_compile_shader(ctx, sh))
> + _mesa_glsl_compile_shader(ctx, sh, false, false);
>
> if (ctx->_Shader->Flags & GLSL_LOG) {
> _mesa_write_shader_to_file(sh);
> @@ -870,7 +919,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
>
> }
>
> - if (!sh->CompileStatus) {
> + if (ctx->_Shader->Flags && !sh->CompileStatus) {
I don't understand this change. Is this because when Flags is set it
won't use the background compile? Aren't there other things that could
cause queue_compile_shader to fail that would result in
GLSL_DUMP_ON_ERROR being ignored here?
> if (ctx->_Shader->Flags & GLSL_DUMP_ON_ERROR) {
> fprintf(stderr, "GLSL source for %s shader %d:\n",
> _mesa_shader_stage_to_string(sh->Stage), sh->Name);
> @@ -887,6 +936,49 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
> }
>
>
> +static void
> +deferred_link_program(void *data)
> +{
> + struct gl_shader_program *shProg = (struct gl_shader_program *) data;
> + struct gl_context *ctx = (struct gl_context *) shProg->TaskData;
> +
> + _mesa_wait_shaders(ctx, shProg->Shaders, shProg->NumShaders);
> + _mesa_glsl_link_shader(ctx, shProg);
> +}
> +
> +static bool
> +queue_link_program(struct gl_context *ctx, struct gl_shader_program *shProg)
> +{
> + int i;
> +
> + if (!can_queue_task(ctx))
> + return false;
> + if (!ctx->Const.DeferLinkProgram)
> + return false;
> +
> + /*
> + * Rather than adding _mesa_wait_shader_program calls here and there, we
> + * simply disallow threaded linking when the program is current or active.
> + */
> + if (ctx->_Shader->ActiveProgram == shProg)
> + return false;
> + /* be careful for separate programs */
> + if (ctx->_Shader->Name != 0) {
> + for (i = 0; i < MESA_SHADER_STAGES; i++) {
> + if (ctx->_Shader->CurrentProgram[i] == shProg)
> + return false;
> + }
> + }
> +
> + shProg->TaskData = (void *) ctx;
> + shProg->Task = _mesa_threadpool_queue_task(ctx->ThreadPool,
> + deferred_link_program, (void *) shProg);
> + if (!shProg->Task)
> + shProg->TaskData = NULL;
> +
> + return (shProg->Task != NULL);
> +}
> +
> /**
> * Link a program's shaders.
> */
> @@ -912,10 +1004,16 @@ link_program(struct gl_context *ctx, GLuint program)
>
> FLUSH_VERTICES(ctx, _NEW_PROGRAM);
>
> - _mesa_glsl_link_shader(ctx, shProg);
> + if (ctx->Driver.NotifyLinkShader)
> + ctx->Driver.NotifyLinkShader(ctx, shProg);
> +
> + if (!queue_link_program(ctx, shProg)) {
> + _mesa_wait_shaders(ctx, shProg->Shaders, shProg->NumShaders);
> + _mesa_glsl_link_shader(ctx, shProg);
> + }
>
> - if (shProg->LinkStatus == GL_FALSE &&
> - (ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
> + if ((ctx->_Shader->Flags & GLSL_REPORT_ERRORS) &&
> + shProg->LinkStatus == GL_FALSE) {
> _mesa_debug(ctx, "Error linking program %u:\n%s\n",
> shProg->Name, shProg->InfoLog);
> }
> diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c
> index b9feff4..ab94d14 100644
> --- a/src/mesa/main/shaderobj.c
> +++ b/src/mesa/main/shaderobj.c
> @@ -41,6 +41,7 @@
> #include "program/prog_parameter.h"
> #include "program/hash_table.h"
> #include "ralloc.h"
> +#include "threadpool.h"
>
> /**********************************************************************/
> /*** Shader object functions ***/
> @@ -95,6 +96,7 @@ _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
> void
> _mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader)
> {
> + mtx_init(&shader->Mutex, mtx_plain);
> shader->RefCount = 1;
> }
>
> @@ -125,18 +127,51 @@ _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
> static void
> _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
> {
> + _mesa_wait_shaders(ctx, &sh, 1);
> +
> free((void *)sh->Source);
> free(sh->Label);
> _mesa_reference_program(ctx, &sh->Program, NULL);
> + mtx_destroy(&sh->Mutex);
> ralloc_free(sh);
> }
>
>
> /**
> + * Wait for the threaded compile tasks to complete.
> + */
> +void
> +_mesa_wait_shaders(struct gl_context *ctx,
> + struct gl_shader **shaders,
> + int num_shaders)
> +{
> + int i;
> +
> + for (i = 0; i < num_shaders; i++) {
> + struct gl_shader *sh = shaders[i];
> +
> + mtx_lock(&sh->Mutex);
> +
> + if (sh->Task) {
> + struct gl_context *task_ctx = (struct gl_context *) sh->TaskData;
> +
> + if (!_mesa_threadpool_complete_task(task_ctx->ThreadPool, sh->Task))
> + sh->CompileStatus = GL_FALSE;
> +
> + sh->Task = NULL;
> + sh->TaskData = NULL;
> + }
> +
> + mtx_unlock(&sh->Mutex);
> + }
> +}
> +
> +
> +/**
> * Lookup a GLSL shader object.
> */
> struct gl_shader *
> -_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
> +_mesa_lookup_shader_no_wait(struct gl_context *ctx, GLuint name)
> {
> if (name) {
> struct gl_shader *sh = (struct gl_shader *)
> @@ -158,7 +193,8 @@ _mesa_lookup_shader(struct gl_context *ctx, GLuint name)
> * As above, but record an error if shader is not found.
> */
> struct gl_shader *
> -_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
> +_mesa_lookup_shader_err_no_wait(struct gl_context *ctx, GLuint name,
> + const char *caller)
> {
> if (!name) {
> _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
> @@ -238,6 +274,8 @@ _mesa_reference_shader_program(struct gl_context *ctx,
> void
> _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog)
> {
> + mtx_init(&prog->Mutex, mtx_plain);
> +
> prog->Type = GL_SHADER_PROGRAM_MESA;
> prog->RefCount = 1;
>
> @@ -373,17 +411,43 @@ _mesa_free_shader_program_data(struct gl_context *ctx,
> static void
> _mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg)
> {
> + _mesa_wait_shader_program(ctx, shProg);
> +
> _mesa_free_shader_program_data(ctx, shProg);
> + mtx_destroy(&shProg->Mutex);
>
> ralloc_free(shProg);
> }
>
>
> /**
> + * Wait for the threaded linking task to complete.
> + */
> +void
> +_mesa_wait_shader_program(struct gl_context *ctx,
> + struct gl_shader_program *shProg)
> +{
> + mtx_lock(&shProg->Mutex);
> +
> + if (shProg->Task) {
> + struct gl_context *task_ctx = (struct gl_context *) shProg->TaskData;
> +
> + if (!_mesa_threadpool_complete_task(task_ctx->ThreadPool,
> + shProg->Task))
> + shProg->LinkStatus = GL_FALSE;
> + shProg->Task = NULL;
> + shProg->TaskData = NULL;
> + }
> +
> + mtx_unlock(&shProg->Mutex);
> +}
> +
> +
> +/**
> * Lookup a GLSL program object.
> */
> struct gl_shader_program *
> -_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
> +_mesa_lookup_shader_program_no_wait(struct gl_context *ctx, GLuint name)
> {
> struct gl_shader_program *shProg;
> if (name) {
> @@ -406,8 +470,8 @@ _mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
> * As above, but record an error if program is not found.
> */
> struct gl_shader_program *
> -_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
> - const char *caller)
> +_mesa_lookup_shader_program_err_no_wait(struct gl_context *ctx, GLuint name,
> + const char *caller)
> {
> if (!name) {
> _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
> diff --git a/src/mesa/main/shaderobj.h b/src/mesa/main/shaderobj.h
> index fae8be8..c2f8a0d 100644
> --- a/src/mesa/main/shaderobj.h
> +++ b/src/mesa/main/shaderobj.h
> @@ -53,13 +53,35 @@ extern void
> _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
> struct gl_shader *sh);
>
> +extern void
> +_mesa_wait_shaders(struct gl_context *ctx,
> + struct gl_shader **shaders,
> + int num_shaders);
> +
> extern struct gl_shader *
> -_mesa_lookup_shader(struct gl_context *ctx, GLuint name);
> +_mesa_lookup_shader_no_wait(struct gl_context *ctx, GLuint name);
>
> extern struct gl_shader *
> -_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller);
> +_mesa_lookup_shader_err_no_wait(struct gl_context *ctx, GLuint name,
> + const char *caller);
>
> +static inline struct gl_shader *
> +_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
> +{
> + struct gl_shader *sh = _mesa_lookup_shader_no_wait(ctx, name);
> + if (sh)
> + _mesa_wait_shaders(ctx, &sh, 1);
> + return sh;
> +}
>
> +static inline struct gl_shader *
> +_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
> +{
> + struct gl_shader *sh = _mesa_lookup_shader_err_no_wait(ctx, name, caller);
> + if (sh)
> + _mesa_wait_shaders(ctx, &sh, 1);
> + return sh;
> +}
>
> extern void
> _mesa_reference_shader_program(struct gl_context *ctx,
> @@ -74,12 +96,37 @@ _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
> extern void
> _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog);
>
> +extern void
> +_mesa_wait_shader_program(struct gl_context *ctx,
> + struct gl_shader_program *shProg);
> +
> extern struct gl_shader_program *
> -_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name);
> +_mesa_lookup_shader_program_no_wait(struct gl_context *ctx, GLuint name);
>
> extern struct gl_shader_program *
> +_mesa_lookup_shader_program_err_no_wait(struct gl_context *ctx, GLuint name,
> + const char *caller);
> +
> +static inline struct gl_shader_program *
> +_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
> +{
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_no_wait(ctx, name);
> + if (shProg)
> + _mesa_wait_shader_program(ctx, shProg);
> + return shProg;
> +}
> +
> +static inline struct gl_shader_program *
> _mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
> - const char *caller);
> + const char *caller)
> +{
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err_no_wait(ctx, name, caller);
> + if (shProg)
> + _mesa_wait_shader_program(ctx, shProg);
> + return shProg;
> +}
>
> extern void
> _mesa_clear_shader_program_data(struct gl_context *ctx,
>
More information about the mesa-dev
mailing list