[Mesa-dev] [PATCH] mesa/shaderapi: Do a dry run of linking an in-use program
Timothy Arceri
tarceri at itsqueeze.com
Thu Nov 2 20:33:53 UTC 2017
I think I'd rather see this handled by releasing the uniforms only after
the second link is successful and using a temp/fallback pointer to hold
it until then. We need to do a similar type of thing with shader source
and the shader cache e.g [1].
[1]
https://cgit.freedesktop.org/mesa/mesa/commit/?id=e5bb4a0b0f4743fa0a0567991dca751ef49a7200
On 03/11/17 05:35, Neil Roberts wrote:
> If an in-use program is unsuccessfully linked, the GL spec requires
> that the executable and the uniform state of the program should remain
> until a new program is bound. Previously this sort of worked in Mesa
> except that it would free the uniform state before attempting to link.
> At least on i965 this would usually continue to work because it
> accesses the uniform values via a dangling pointer. However it was
> causing sporadic failures in one of the CTS tests.
>
> To fix it, when an in-use program is about to be linked, it will now
> make a copy of the program and first try to link that instead. If it
> works it will let the link continue, otherwise it will copy the status
> to the new program and abandon the link. That way the link status and
> info log is preserved without freeing the uniform state.
>
> This isn’t very efficient but it would probably quite a big overhaul
> to fix it properly and it doesn’t seem worth it because I can’t
> imagine that any performance-sensitive application would be hitting
> this very strange corner case of the API.
>
> Fixes: KHR-GL46.sepshaderobjs.StateInteraction
>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=102177
> ---
> src/mesa/main/shaderapi.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 57 insertions(+), 1 deletion(-)
>
> diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
> index 7282435..3f7fe02 100644
> --- a/src/mesa/main/shaderapi.c
> +++ b/src/mesa/main/shaderapi.c
> @@ -1134,6 +1134,58 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh)
> }
> }
>
> +static bool
> +try_link_in_use_program(struct gl_context *ctx,
> + struct gl_shader_program *shProg)
> +{
> + struct gl_shader_program *shProgCopy = _mesa_new_shader_program(0);
> + bool ret;
> + int i;
> +
> + /* If the program is in use then try linking a copy of the program first.
> + * If it won’t work then we’ll copy the link status to the old program and
> + * abandon the linking. Otherwise we let it relink as normal. This is done
> + * because relinking destroys the uniform state of the program but the GL
> + * spec actually requires that the state be preserved when the program is
> + * in use and the link fails. This isn’t terribly efficent but in practice
> + * it is probably not worth optimising because it’s a rather strange corner
> + * case of the spec.
> + *
> + * GLSL 4.6 spec section 7.3:
> + *
> + * “If a program object that is active for any shader stage is re-linked
> + * unsuccessfully, the link status will be set to FALSE, but any existing
> + * executables and associated state will remain part of the current
> + * rendering state until a subsequent call to UseProgram,
> + * UseProgramStages, or BindProgramPipeline removes them from use.”
> + */
> +
> + for (i = 0; i < shProg->NumShaders; i++)
> + attach_shader(ctx, shProgCopy, shProg->Shaders[i]);
> +
> + shProgCopy->BinaryRetreivableHint = shProg->BinaryRetreivableHint;
> + shProgCopy->SeparateShader = shProg->SeparateShader;
> +
> + _mesa_glsl_link_shader(ctx, shProgCopy);
> +
> + if (shProgCopy->data->LinkStatus) {
> + ret = true;
> + } else {
> + shProg->data->LinkStatus = shProgCopy->data->LinkStatus;
> + shProg->data->Validated = shProgCopy->data->Validated;
> + shProg->data->Version = shProgCopy->data->Version;
> + shProg->IsES = shProgCopy->IsES;
> + ralloc_free(shProg->data->InfoLog);
> + shProg->data->InfoLog =
> + ralloc_strdup(shProg->data, shProgCopy->data->InfoLog);
> +
> + ret = false;
> + }
> +
> + _mesa_reference_shader_program(ctx, &shProgCopy, NULL);
> +
> + return ret;
> +}
>
> /**
> * Link a program's shaders.
> @@ -1159,12 +1211,16 @@ link_program(struct gl_context *ctx, struct gl_shader_program *shProg,
> }
>
> unsigned programs_in_use = 0;
> - if (ctx->_Shader)
> + if (ctx->_Shader) {
> for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
> if (ctx->_Shader->CurrentProgram[stage] &&
> ctx->_Shader->CurrentProgram[stage]->Id == shProg->Name) {
> programs_in_use |= 1 << stage;
> }
> + }
> +
> + if (programs_in_use && !try_link_in_use_program(ctx, shProg))
> + return;
> }
>
> FLUSH_VERTICES(ctx, 0);
>
More information about the mesa-dev
mailing list