[Mesa-dev] [PATCH v2] mesa: remove link validation that should be done elsewhere

Ian Romanick idr at freedesktop.org
Tue Jan 19 14:09:05 PST 2016


On 01/05/2016 05:40 PM, Timothy Arceri wrote:
> Even if re-linking fails rendering shouldn't fail as the previous
> succesfully linked program will still be available. It also shouldn't
> be possible to have an unlinked program as part of the current rendering
> state.
> 
> This fixes a subtest in:
> ES31-CTS.sepshaderobjs.StateInteraction
> 
> This change should improve performance on CPU limited benchmarks as noted
> in commit d6c6b186cf308f.
> 
> From Section 7.3 (Program Objects) of the OpenGL 4.5 spec:
> 
>    "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. If such a program is attached to
>     any program pipeline object, the existing executables and associated state
>     will remain part of the program pipeline object until a subsequent call to
>     UseProgramStages removes them from use. An unsuccessfully linked program may
>     not be made part of the current rendering state by UseProgram or added to
>     program pipeline objects by UseProgramStages until it is successfully
>     re-linked."
> 
>    "void UseProgram(uint program);
> 
>    ...
> 
>    An INVALID_OPERATION error is generated if program has not been linked, or
>    was last linked unsuccessfully.  The current rendering state is not modified."

Right.... so if there's a problem with the program to begin with, that
should be caught by glUseProgram.  Once a program is in use, calling
glLinkProgram can't break it.  That sounds reasonable... and I'm always
in favor of removing things from draw-time validation.

Hmm... there is another potential for problem.  At what point does
glUseProgram exit if it detects that the in specified program is already
in use?  I would expect the following sequence to generate an error at
the second glUseProgram:

    glUseProgram(p);
    glDrawArrays(...);

    glShaderSource(s, 1, &source_with_a_linking_program, NULL);
    glAttachShader(p, s);
    glLinkProgram(p);  // linking should fail
    glUseProgram(p);   // this should generate an error, but...
                       // leave the old executable in place?
    glDrawArrays(...); // should generate same result as before

That's worth investigating.  It's probably also worth a couple piglit tests.

Either way, this patch is

Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>

> V2: apply the rule to both core and compat.
> 
> Cc: Tapani Pälli <tapani.palli at intel.com>
> Cc: Ian Romanick <ian.d.romanick at intel.com>
> Cc: Brian Paul <brianp at vmware.com>
> ---
>  src/mesa/main/context.c | 63 +++----------------------------------------------
>  1 file changed, 3 insertions(+), 60 deletions(-)
> 
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index be983d4..f3fd01f 100644
> --- a/src/mesa/main/context.c
> +++ b/src/mesa/main/context.c
> @@ -1930,31 +1930,6 @@ _mesa_check_blend_func_error(struct gl_context *ctx)
>     return GL_TRUE;
>  }
>  
> -static bool
> -shader_linked_or_absent(struct gl_context *ctx,
> -                        const struct gl_shader_program *shProg,
> -                        bool *shader_present, const char *where)
> -{
> -   if (shProg) {
> -      *shader_present = true;
> -
> -      if (!shProg->LinkStatus) {
> -         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(shader not linked)", where);
> -         return false;
> -      }
> -#if 0 /* not normally enabled */
> -      {
> -         char errMsg[100];
> -         if (!_mesa_validate_shader_program(ctx, shProg, errMsg)) {
> -            _mesa_warning(ctx, "Shader program %u is invalid: %s",
> -                          shProg->Name, errMsg);
> -         }
> -      }
> -#endif
> -   }
> -
> -   return true;
> -}
>  
>  /**
>   * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
> @@ -1967,54 +1942,22 @@ shader_linked_or_absent(struct gl_context *ctx,
>  GLboolean
>  _mesa_valid_to_render(struct gl_context *ctx, const char *where)
>  {
> -   unsigned i;
> -
>     /* This depends on having up to date derived state (shaders) */
>     if (ctx->NewState)
>        _mesa_update_state(ctx);
>  
> -   if (ctx->API == API_OPENGL_CORE || ctx->API == API_OPENGLES2) {
> -      bool from_glsl_shader[MESA_SHADER_COMPUTE] = { false };
> -
> -      for (i = 0; i < MESA_SHADER_COMPUTE; i++) {
> -         if (!shader_linked_or_absent(ctx, ctx->_Shader->CurrentProgram[i],
> -                                      &from_glsl_shader[i], where))
> -            return GL_FALSE;
> -      }
> -
> -      /* In OpenGL Core Profile and OpenGL ES 2.0 / 3.0, there are no assembly
> -       * shaders.  Don't check state related to those.
> -       */
> -   } else {
> -      bool has_vertex_shader = false;
> -      bool has_fragment_shader = false;
> -
> -      /* In OpenGL Compatibility Profile, there is only vertex shader and
> -       * fragment shader.  We take this path also for API_OPENGLES because
> -       * optimizing that path would make the other (more common) paths
> -       * slightly slower.
> -       */
> -      if (!shader_linked_or_absent(ctx,
> -                                   ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX],
> -                                   &has_vertex_shader, where))
> -         return GL_FALSE;
> -
> -      if (!shader_linked_or_absent(ctx,
> -                                   ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT],
> -                                   &has_fragment_shader, where))
> -         return GL_FALSE;
> -
> +   if (ctx->API == API_OPENGL_COMPAT) {
>        /* Any shader stages that are not supplied by the GLSL shader and have
>         * assembly shaders enabled must now be validated.
>         */
> -      if (!has_vertex_shader
> +      if (!ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX]
>            && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
>           _mesa_error(ctx, GL_INVALID_OPERATION,
>                       "%s(vertex program not valid)", where);
>           return GL_FALSE;
>        }
>  
> -      if (!has_fragment_shader) {
> +      if (!ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]) {
>           if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
>              _mesa_error(ctx, GL_INVALID_OPERATION,
>                          "%s(fragment program not valid)", where);
> 



More information about the mesa-dev mailing list