[Mesa-dev] [PATCH 4/8] st/mesa: determine states used or affected by shaders at compile time

Nicolai Hähnle nhaehnle at gmail.com
Tue Aug 9 10:56:59 UTC 2016


On 07.08.2016 03:12, Marek Olšák wrote:
> From: Marek Olšák <marek.olsak at amd.com>
>
> At compile time, each shader determines which ST_NEW flags should be set
> at shader bind time.
>
> This just sets the new field for all shaders. The next commit will use it.
> ---
>  src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 175 ++++++++++++++++++++++++++++-
>  src/mesa/state_tracker/st_program.c        |  37 +++++-
>  src/mesa/state_tracker/st_program.h        |   6 +
>  3 files changed, 215 insertions(+), 3 deletions(-)
>
> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> index 362559f..fd14766 100644
> --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> @@ -6666,31 +6666,202 @@ get_mesa_program_tgsi(struct gl_context *ctx,
>
>  static struct gl_program *
>  get_mesa_program(struct gl_context *ctx,
>                   struct gl_shader_program *shader_program,
>                   struct gl_linked_shader *shader)
>  {
>     struct pipe_screen *pscreen = ctx->st->pipe->screen;
>     unsigned ptarget = st_shader_stage_to_ptarget(shader->Stage);
>     enum pipe_shader_ir preferred_ir = (enum pipe_shader_ir)
>        pscreen->get_shader_param(pscreen, ptarget, PIPE_SHADER_CAP_PREFERRED_IR);
> +   struct gl_program *prog = NULL;
> +
>     if (preferred_ir == PIPE_SHADER_IR_NIR) {
>        /* TODO only for GLSL VS/FS for now: */
>        switch (shader->Stage) {
>        case MESA_SHADER_VERTEX:
>        case MESA_SHADER_FRAGMENT:
> -         return st_nir_get_mesa_program(ctx, shader_program, shader);
> +         prog = st_nir_get_mesa_program(ctx, shader_program, shader);
>        default:
>           break;
>        }
> +   } else {
> +      prog = get_mesa_program_tgsi(ctx, shader_program, shader);
> +   }
> +
> +   if (prog) {
> +      uint64_t *states;
> +
> +      /* This determines which states will be updated when the shader is
> +       * bound.
> +       */
> +      switch (shader->Stage) {
> +      case MESA_SHADER_VERTEX:
> +         states = &((struct st_vertex_program*)prog)->affected_states;
> +
> +         *states = ST_NEW_VS_STATE |
> +                   ST_NEW_RASTERIZER |
> +                   ST_NEW_VERTEX_ARRAYS;
> +
> +         if (prog->Parameters->NumParameters)
> +            *states |= ST_NEW_VS_CONSTANTS;
> +
> +         if (shader->num_samplers)
> +            *states |= ST_NEW_VS_SAMPLER_VIEWS |
> +                       ST_NEW_RENDER_SAMPLERS;
> +
> +         if (shader->NumImages)
> +            *states |= ST_NEW_VS_IMAGES;
> +
> +         if (shader->NumUniformBlocks)
> +            *states |= ST_NEW_VS_UBOS;
> +
> +         if (shader->NumShaderStorageBlocks)
> +            *states |= ST_NEW_VS_SSBOS;
> +
> +         if (shader->NumAtomicBuffers)
> +            *states |= ST_NEW_VS_ATOMICS;

I'm not overly fond of the code duplication here. Perhaps these could 
all be expressed relative to a stage-specific base flag?

Nicolai


> +         break;
> +
> +      case MESA_SHADER_TESS_CTRL:
> +         states = &((struct st_tessctrl_program*)prog)->affected_states;
> +
> +         *states = ST_NEW_TCS_STATE;
> +
> +         if (prog->Parameters->NumParameters)
> +            *states |= ST_NEW_TCS_CONSTANTS;
> +
> +         if (shader->num_samplers)
> +            *states |= ST_NEW_TCS_SAMPLER_VIEWS |
> +                       ST_NEW_RENDER_SAMPLERS;
> +
> +         if (shader->NumImages)
> +            *states |= ST_NEW_TCS_IMAGES;
> +
> +         if (shader->NumUniformBlocks)
> +            *states |= ST_NEW_TCS_UBOS;
> +
> +         if (shader->NumShaderStorageBlocks)
> +            *states |= ST_NEW_TCS_SSBOS;
> +
> +         if (shader->NumAtomicBuffers)
> +            *states |= ST_NEW_TCS_ATOMICS;
> +         break;
> +
> +      case MESA_SHADER_TESS_EVAL:
> +         states = &((struct st_tesseval_program*)prog)->affected_states;
> +
> +         *states = ST_NEW_TES_STATE |
> +                   ST_NEW_RASTERIZER;
> +
> +         if (prog->Parameters->NumParameters)
> +            *states |= ST_NEW_TES_CONSTANTS;
> +
> +         if (shader->num_samplers)
> +            *states |= ST_NEW_TES_SAMPLER_VIEWS |
> +                       ST_NEW_RENDER_SAMPLERS;
> +
> +         if (shader->NumImages)
> +            *states |= ST_NEW_TES_IMAGES;
> +
> +         if (shader->NumUniformBlocks)
> +            *states |= ST_NEW_TES_UBOS;
> +
> +         if (shader->NumShaderStorageBlocks)
> +            *states |= ST_NEW_TES_SSBOS;
> +
> +         if (shader->NumAtomicBuffers)
> +            *states |= ST_NEW_TES_ATOMICS;
> +         break;
> +
> +      case MESA_SHADER_GEOMETRY:
> +         states = &((struct st_geometry_program*)prog)->affected_states;
> +
> +         *states = ST_NEW_GS_STATE |
> +                   ST_NEW_RASTERIZER;
> +
> +         if (prog->Parameters->NumParameters)
> +            *states |= ST_NEW_GS_CONSTANTS;
> +
> +         if (shader->num_samplers)
> +            *states |= ST_NEW_GS_SAMPLER_VIEWS |
> +                       ST_NEW_RENDER_SAMPLERS;
> +
> +         if (shader->NumImages)
> +            *states |= ST_NEW_GS_IMAGES;
> +
> +         if (shader->NumUniformBlocks)
> +            *states |= ST_NEW_GS_UBOS;
> +
> +         if (shader->NumShaderStorageBlocks)
> +            *states |= ST_NEW_GS_SSBOS;
> +
> +         if (shader->NumAtomicBuffers)
> +            *states |= ST_NEW_GS_ATOMICS;
> +         break;
> +
> +      case MESA_SHADER_FRAGMENT:
> +         states = &((struct st_fragment_program*)prog)->affected_states;
> +
> +         /* gl_FragCoord and glDrawPixels always use constants. */
> +         *states = ST_NEW_FS_STATE |
> +                   ST_NEW_SAMPLE_SHADING |
> +                   ST_NEW_FS_CONSTANTS;
> +
> +         if (shader->num_samplers)
> +            *states |= ST_NEW_FS_SAMPLER_VIEWS |
> +                       ST_NEW_RENDER_SAMPLERS;
> +
> +         if (shader->NumImages)
> +            *states |= ST_NEW_FS_IMAGES;
> +
> +         if (shader->NumUniformBlocks)
> +            *states |= ST_NEW_FS_UBOS;
> +
> +         if (shader->NumShaderStorageBlocks)
> +            *states |= ST_NEW_FS_SSBOS;
> +
> +         if (shader->NumAtomicBuffers)
> +            *states |= ST_NEW_FS_ATOMICS;
> +         break;
> +
> +      case MESA_SHADER_COMPUTE:
> +         states = &((struct st_compute_program*)prog)->affected_states;
> +
> +         *states = ST_NEW_CS_STATE;
> +
> +         if (prog->Parameters->NumParameters)
> +            *states |= ST_NEW_CS_CONSTANTS;
> +
> +         if (shader->num_samplers)
> +            *states |= ST_NEW_CS_SAMPLER_VIEWS |
> +                       ST_NEW_CS_SAMPLERS;
> +
> +         if (shader->NumImages)
> +            *states |= ST_NEW_CS_IMAGES;
> +
> +         if (shader->NumUniformBlocks)
> +            *states |= ST_NEW_CS_UBOS;
> +
> +         if (shader->NumShaderStorageBlocks)
> +            *states |= ST_NEW_CS_SSBOS;
> +
> +         if (shader->NumAtomicBuffers)
> +            *states |= ST_NEW_CS_ATOMICS;
> +         break;
> +
> +      default:
> +         unreachable("unhandled shader stage");
> +      }
>     }
> -   return get_mesa_program_tgsi(ctx, shader_program, shader);
> +
> +   return prog;
>  }
>
>
>  extern "C" {
>
>  /**
>   * Link a shader.
>   * Called via ctx->Driver.LinkShader()
>   * This actually involves converting GLSL IR into an intermediate TGSI-like IR
>   * with code lowering and other optimizations.
> diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
> index e297bb1..03a685c 100644
> --- a/src/mesa/state_tracker/st_program.c
> +++ b/src/mesa/state_tracker/st_program.c
> @@ -357,23 +357,37 @@ st_translate_vertex_program(struct st_context *st,
>                 st_get_generic_varying_index(st, attr);
>              break;
>           }
>        }
>     }
>     /* similar hack to above, presetup potentially unused edgeflag output */
>     stvp->result_to_output[VARYING_SLOT_EDGE] = num_outputs;
>     output_semantic_name[num_outputs] = TGSI_SEMANTIC_EDGEFLAG;
>     output_semantic_index[num_outputs] = 0;
>
> -   if (!stvp->glsl_to_tgsi && !stvp->shader_program)
> +   /* ARB_vp: */
> +   if (!stvp->glsl_to_tgsi && !stvp->shader_program) {
>        _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT);
>
> +      /* This determines which states will be updated when the assembly
> +       * shader is bound.
> +       */
> +      stvp->affected_states = ST_NEW_VS_STATE |
> +                              ST_NEW_RASTERIZER |
> +                              ST_NEW_VERTEX_ARRAYS;
> +
> +      if (stvp->Base.Base.Parameters->NumParameters)
> +         stvp->affected_states |= ST_NEW_VS_CONSTANTS;
> +
> +      /* No samplers are allowed in ARB_vp. */
> +   }
> +
>     if (stvp->shader_program) {
>        nir_shader *nir = st_glsl_to_nir(st, &stvp->Base.Base,
>                                         stvp->shader_program,
>                                         MESA_SHADER_VERTEX);
>
>        stvp->tgsi.type = PIPE_SHADER_IR_NIR;
>        stvp->tgsi.ir.nir = nir;
>
>        st_translate_stream_output_info2(&stvp->shader_program->LinkedTransformFeedback,
>                                         stvp->result_to_output,
> @@ -586,24 +600,45 @@ st_translate_fragment_program(struct st_context *st,
>     ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS];
>     ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
>     uint fs_num_inputs = 0;
>
>     ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
>     ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
>     uint fs_num_outputs = 0;
>
>     memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr));
>
> +   /* Non-GLSL programs: */
>     if (!stfp->glsl_to_tgsi && !stfp->shader_program) {
>        _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT);
>        if (st->ctx->Const.GLSLFragCoordIsSysVal)
>           _mesa_program_fragment_position_to_sysval(&stfp->Base.Base);
> +
> +      /* This determines which states will be updated when the assembly
> +       * shader is bound.
> +       *
> +       * fragment.position and glDrawPixels always use constants.
> +       */
> +      stfp->affected_states = ST_NEW_FS_STATE |
> +                              ST_NEW_SAMPLE_SHADING |
> +                              ST_NEW_FS_CONSTANTS;
> +
> +      if (stfp->ati_fs) {
> +         /* Just set them for ATI_fs unconditionally. */
> +         stfp->affected_states |= ST_NEW_FS_SAMPLER_VIEWS |
> +                                  ST_NEW_RENDER_SAMPLERS;
> +      } else {
> +         /* ARB_fp */
> +         if (stfp->Base.Base.SamplersUsed)
> +            stfp->affected_states |= ST_NEW_FS_SAMPLER_VIEWS |
> +                                     ST_NEW_RENDER_SAMPLERS;
> +      }
>     }
>
>     /*
>      * Convert Mesa program inputs to TGSI input register semantics.
>      */
>     inputsRead = stfp->Base.Base.InputsRead;
>     for (attr = 0; attr < VARYING_SLOT_MAX; attr++) {
>        if ((inputsRead & BITFIELD64_BIT(attr)) != 0) {
>           const GLuint slot = fs_num_inputs++;
>
> diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h
> index e6db106..8e11bf0 100644
> --- a/src/mesa/state_tracker/st_program.h
> +++ b/src/mesa/state_tracker/st_program.h
> @@ -100,20 +100,21 @@ struct st_fp_variant
>
>  /**
>   * Derived from Mesa gl_fragment_program:
>   */
>  struct st_fragment_program
>  {
>     struct gl_fragment_program Base;
>     struct pipe_shader_state tgsi;
>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
>     struct ati_fragment_shader *ati_fs;
> +   uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
>
>     /* used when bypassing glsl_to_tgsi: */
>     struct gl_shader_program *shader_program;
>
>     struct st_fp_variant *variants;
>  };
>
>
>
>  /** Vertex program variant key */
> @@ -159,20 +160,21 @@ struct st_vp_variant
>
>
>  /**
>   * Derived from Mesa gl_fragment_program:
>   */
>  struct st_vertex_program
>  {
>     struct gl_vertex_program Base;  /**< The Mesa vertex program */
>     struct pipe_shader_state tgsi;
>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
> +   uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
>
>     /* used when bypassing glsl_to_tgsi: */
>     struct gl_shader_program *shader_program;
>
>     /** maps a Mesa VERT_ATTRIB_x to a packed TGSI input index */
>     /** maps a TGSI input index back to a Mesa VERT_ATTRIB_x */
>     GLuint index_to_input[PIPE_MAX_SHADER_INPUTS];
>     GLuint num_inputs;
>
>     /** Maps VARYING_SLOT_x to slot */
> @@ -207,59 +209,63 @@ struct st_basic_variant
>
>
>  /**
>   * Derived from Mesa gl_geometry_program:
>   */
>  struct st_geometry_program
>  {
>     struct gl_geometry_program Base;  /**< The Mesa geometry program */
>     struct pipe_shader_state tgsi;
>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
> +   uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
>
>     struct st_basic_variant *variants;
>  };
>
>
>  /**
>   * Derived from Mesa gl_tess_ctrl_program:
>   */
>  struct st_tessctrl_program
>  {
>     struct gl_tess_ctrl_program Base;  /**< The Mesa tess ctrl program */
>     struct pipe_shader_state tgsi;
>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
> +   uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
>
>     struct st_basic_variant *variants;
>  };
>
>
>  /**
>   * Derived from Mesa gl_tess_eval_program:
>   */
>  struct st_tesseval_program
>  {
>     struct gl_tess_eval_program Base;  /**< The Mesa tess eval program */
>     struct pipe_shader_state tgsi;
>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
> +   uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
>
>     struct st_basic_variant *variants;
>  };
>
>
>  /**
>   * Derived from Mesa gl_compute_program:
>   */
>  struct st_compute_program
>  {
>     struct gl_compute_program Base;  /**< The Mesa compute program */
>     struct pipe_compute_state tgsi;
>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
> +   uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
>
>     struct st_basic_variant *variants;
>  };
>
>
>  static inline struct st_fragment_program *
>  st_fragment_program( struct gl_fragment_program *fp )
>  {
>     return (struct st_fragment_program *)fp;
>  }
>


More information about the mesa-dev mailing list