[Mesa-dev] [PATCH 16/16] mesa/st: add support for NIR as possible driver IR

Rob Clark robdclark at gmail.com
Sun Mar 27 18:41:12 UTC 2016


oh, whoops, the ir3 bits were meant to be squashed into a different
patch on top of this patchset, which enables ir3 support for nir as
preferred IR..  and I think the nir_foreach_variable_safe() bit is
already in Jason's patchset (so I'll either pull in his patch or
rebase on top of his patchset so that goes away).  Was there anything
else you noticed?

BR,
-R

On Sun, Mar 27, 2016 at 2:23 PM, Marek Olšák <maraeo at gmail.com> wrote:
> This patch contains several unrelated changes and cleanups.
>
> Marek
>
> On Sat, Mar 26, 2016 at 10:02 PM, Rob Clark <robdclark at gmail.com> wrote:
>> From: Rob Clark <robclark at freedesktop.org>
>>
>> Signed-off-by: Rob Clark <robclark at freedesktop.org>
>> ---
>>  src/compiler/nir/nir.h                             |   2 +
>>  .../drivers/freedreno/ir3/ir3_compiler_nir.c       |   8 +
>>  src/mesa/Makefile.sources                          |   1 +
>>  src/mesa/state_tracker/st_glsl_to_nir.cpp          | 425 +++++++++++++++++++++
>>  src/mesa/state_tracker/st_glsl_to_tgsi.cpp         |  40 +-
>>  src/mesa/state_tracker/st_glsl_to_tgsi.h           |   5 +
>>  src/mesa/state_tracker/st_nir.h                    |  32 ++
>>  src/mesa/state_tracker/st_program.c                | 148 ++++++-
>>  src/mesa/state_tracker/st_program.h                |   6 +
>>  9 files changed, 643 insertions(+), 24 deletions(-)
>>  create mode 100644 src/mesa/state_tracker/st_glsl_to_nir.cpp
>>
>> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
>> index f12bc68..d6aecdc 100644
>> --- a/src/compiler/nir/nir.h
>> +++ b/src/compiler/nir/nir.h
>> @@ -333,6 +333,8 @@ typedef struct nir_variable {
>>
>>  #define nir_foreach_variable(var, var_list) \
>>     foreach_list_typed(nir_variable, var, node, var_list)
>> +#define nir_foreach_variable_safe(var, var_list) \
>> +   foreach_list_typed_safe(nir_variable, var, node, var_list)
>>
>>  static inline bool
>>  nir_variable_is_global(const nir_variable *var)
>> diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c
>> index 54315d2..7e851db 100644
>> --- a/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c
>> +++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c
>> @@ -1960,6 +1960,10 @@ setup_input(struct ir3_compile *ctx, nir_variable *in)
>>         DBG("; in: slot=%u, len=%ux%u, drvloc=%u",
>>                         slot, array_len, ncomp, n);
>>
>> +       /* let's pretend things other than vec4 don't exist: */
>> +       ncomp = MAX2(ncomp, 4);
>> +       compile_assert(ctx, ncomp == 4);
>> +
>>         so->inputs[n].slot = slot;
>>         so->inputs[n].compmask = (1 << ncomp) - 1;
>>         so->inputs_count = MAX2(so->inputs_count, n + 1);
>> @@ -2038,6 +2042,10 @@ setup_output(struct ir3_compile *ctx, nir_variable *out)
>>         DBG("; out: slot=%u, len=%ux%u, drvloc=%u",
>>                         slot, array_len, ncomp, n);
>>
>> +       /* let's pretend things other than vec4 don't exist: */
>> +       ncomp = MAX2(ncomp, 4);
>> +       compile_assert(ctx, ncomp == 4);
>> +
>>         if (ctx->so->type == SHADER_FRAGMENT) {
>>                 switch (slot) {
>>                 case FRAG_RESULT_DEPTH:
>> diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
>> index 6c93d07..54ac38e 100644
>> --- a/src/mesa/Makefile.sources
>> +++ b/src/mesa/Makefile.sources
>> @@ -487,6 +487,7 @@ STATETRACKER_FILES = \
>>         state_tracker/st_gen_mipmap.c \
>>         state_tracker/st_gen_mipmap.h \
>>         state_tracker/st_gl_api.h \
>> +       state_tracker/st_glsl_to_nir.cpp \
>>         state_tracker/st_glsl_to_tgsi.cpp \
>>         state_tracker/st_glsl_to_tgsi.h \
>>         state_tracker/st_glsl_types.cpp \
>> diff --git a/src/mesa/state_tracker/st_glsl_to_nir.cpp b/src/mesa/state_tracker/st_glsl_to_nir.cpp
>> new file mode 100644
>> index 0000000..a262cc8
>> --- /dev/null
>> +++ b/src/mesa/state_tracker/st_glsl_to_nir.cpp
>> @@ -0,0 +1,425 @@
>> +/*
>> + * Copyright © 2015 Red Hat
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + */
>> +
>> +#include "st_nir.h"
>> +
>> +#include "pipe/p_defines.h"
>> +#include "pipe/p_screen.h"
>> +#include "pipe/p_context.h"
>> +
>> +#include "program/program.h"
>> +#include "program/prog_statevars.h"
>> +#include "program/prog_parameter.h"
>> +#include "program/ir_to_mesa.h"
>> +#include "program/hash_table.h"
>> +#include "main/mtypes.h"
>> +#include "main/errors.h"
>> +#include "main/shaderapi.h"
>> +#include "main/uniforms.h"
>> +
>> +#include "st_context.h"
>> +#include "st_program.h"
>> +#include "st_glsl_types.h"
>> +
>> +#include "compiler/nir/nir.h"
>> +#include "compiler/nir/glsl_to_nir.h"
>> +#include "compiler/glsl_types.h"
>> +
>> +
>> +/* Depending on PIPE_CAP_TGSI_TEXCOORD (st->needs_texcoord_semantic) we
>> + * may need to fix up varying slots so the glsl->nir path is aligned
>> + * with the anything->tgsi->nir path.
>> + */
>> +static void
>> +st_nir_fixup_varying_slots(struct st_context *st, struct exec_list *var_list)
>> +{
>> +   if (st->needs_texcoord_semantic)
>> +      return;
>> +
>> +   nir_foreach_variable(var, var_list) {
>> +      if (var->data.location >= VARYING_SLOT_VAR0) {
>> +         var->data.location += 9;
>> +      } else if ((var->data.location >= VARYING_SLOT_TEX0) &&
>> +               (var->data.location <= VARYING_SLOT_TEX7)) {
>> +         var->data.location += VARYING_SLOT_VAR0 - VARYING_SLOT_TEX0;
>> +      }
>> +   }
>> +}
>> +
>> +/* input location assignment for VS inputs must be handled specially, so
>> + * that it is aligned w/ st's vbo state.
>> + * (This isn't the case with, for ex, FS inputs, which only need to agree
>> + * on varying-slot w/ the VS outputs)
>> + */
>> +static void
>> +st_nir_assign_vs_in_locations(struct gl_program *prog,
>> +                              struct exec_list *var_list, unsigned *size)
>> +{
>> +   unsigned attr, num_inputs = 0;
>> +   unsigned input_to_index[VERT_ATTRIB_MAX] = {0};
>> +
>> +   /* TODO de-duplicate w/ similar code in st_translate_vertex_program()? */
>> +   for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
>> +      if ((prog->InputsRead & BITFIELD64_BIT(attr)) != 0) {
>> +         input_to_index[attr] = num_inputs;
>> +         num_inputs++;
>> +         if ((prog->DoubleInputsRead & BITFIELD64_BIT(attr)) != 0) {
>> +            /* add placeholder for second part of a double attribute */
>> +            num_inputs++;
>> +         }
>> +      }
>> +   }
>> +
>> +   *size = 0;
>> +   nir_foreach_variable(var, var_list) {
>> +      attr = var->data.location;
>> +      assert(attr < ARRAY_SIZE(input_to_index));
>> +      var->data.driver_location = input_to_index[attr];
>> +      (*size)++;
>> +   }
>> +}
>> +
>> +static void
>> +st_nir_assign_uniform_locations(struct gl_program *prog,
>> +                                struct gl_shader_program *shader_program,
>> +                                struct exec_list *uniform_list, unsigned *size)
>> +{
>> +   int max = 0;
>> +   int shaderidx = 0;
>> +
>> +   nir_foreach_variable(uniform, uniform_list) {
>> +      int loc;
>> +
>> +      if (uniform->type->is_sampler()) {
>> +         unsigned val;
>> +         bool found = shader_program->UniformHash->get(val, uniform->name);
>> +         loc = shaderidx++;
>> +         assert(found);
>> +         /* this ensure that nir_lower_samplers looks at the correct
>> +          * shader_program->UniformStorage[location]:
>> +          */
>> +         uniform->data.location = val;
>> +      } else if (strncmp(uniform->name, "gl_", 3) == 0) {
>> +         const gl_state_index *const stateTokens = (gl_state_index *)uniform->state_slots[0].tokens;
>> +         /* This state reference has already been setup by ir_to_mesa, but we'll
>> +          * get the same index back here.
>> +          */
>> +         loc = _mesa_add_state_reference(prog->Parameters, stateTokens);
>> +      } else {
>> +         loc = _mesa_lookup_parameter_index(prog->Parameters, uniform->name);
>> +      }
>> +
>> +      /* is there a better way to do this?  If we have something like:
>> +       *
>> +       *    struct S {
>> +       *           float f;
>> +       *           vec4 v;
>> +       *    };
>> +       *    uniform S color;
>> +       *
>> +       * Then what we get in prog->Parameters looks like:
>> +       *
>> +       *    0: Name=color.f, Type=6, DataType=1406, Size=1
>> +       *    1: Name=color.v, Type=6, DataType=8b52, Size=4
>> +       *
>> +       * So the name doesn't match up and _mesa_lookup_parameter_index()
>> +       * fails.  In this case just find the first matching "color.*"..
>> +       *
>> +       * Note for arrays you could end up w/ color[n].f, for example.
>> +       */
>> +      if (loc < 0) {
>> +         int namelen = strlen(uniform->name);
>> +         for (unsigned i = 0; i < prog->Parameters->NumParameters; i++) {
>> +            struct gl_program_parameter *p = &prog->Parameters->Parameters[i];
>> +            if ((strncmp(p->Name, uniform->name, namelen) == 0) &&
>> +                ((p->Name[namelen] == '.') || (p->Name[namelen] == '['))) {
>> +               loc = i;
>> +               break;
>> +            }
>> +         }
>> +      }
>> +
>> +      uniform->data.driver_location = loc;
>> +
>> +      /*
>> +       * UBO's have their own address spaces, so don't count them towards the
>> +       * number of global uniforms
>> +       */
>> +      if ((uniform->data.mode == nir_var_uniform || uniform->data.mode == nir_var_shader_storage) &&
>> +          uniform->interface_type != NULL)
>> +         continue;
>> +
>> +      max = MAX2(max, loc + st_glsl_type_size(uniform->type));
>> +   }
>> +   *size = max;
>> +}
>> +
>> +extern "C" {
>> +
>> +/* First half of converting glsl_to_nir.. this leaves things in a pre-
>> + * nir_lower_io state, so that shader variants can more easily insert/
>> + * replace variables, etc.
>> + */
>> +nir_shader *
>> +st_glsl_to_nir(struct st_context *st, struct gl_program *prog,
>> +               struct gl_shader_program *shader_program,
>> +               gl_shader_stage stage)
>> +{
>> +   struct pipe_screen *pscreen = st->pipe->screen;
>> +   unsigned ptarget = st_shader_stage_to_ptarget(stage);
>> +   const nir_shader_compiler_options *options;
>> +   nir_shader *nir;
>> +
>> +   assert(pscreen->get_compiler_options);   /* drivers using NIR must implement this */
>> +
>> +   options = (const nir_shader_compiler_options *)
>> +      pscreen->get_compiler_options(pscreen, PIPE_SHADER_IR_NIR, ptarget);
>> +   assert(options);
>> +
>> +   if (prog->nir)
>> +      return prog->nir;
>> +
>> +   nir = glsl_to_nir(shader_program, stage, options);
>> +   prog->nir = nir;
>> +
>> +   OPT_V(nir, nir_lower_io_to_temporaries, true, true);
>> +   OPT_V(nir, nir_lower_global_vars_to_local);
>> +   OPT_V(nir, nir_split_var_copies);
>> +   OPT_V(nir, nir_lower_var_copies);
>> +   OPT_V(nir, st_nir_lower_builtin);
>> +
>> +   /* fragment shaders may need : */
>> +   if (stage == MESA_SHADER_FRAGMENT) {
>> +      static const gl_state_index wposTransformState[STATE_LENGTH] = {
>> +         STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM
>> +      };
>> +      nir_lower_wpos_ytransform_options wpos_options = {0};
>> +      struct pipe_screen *pscreen = st->pipe->screen;
>> +
>> +      memcpy(wpos_options.state_tokens, wposTransformState,
>> +             sizeof(wpos_options.state_tokens));
>> +      wpos_options.fs_coord_origin_upper_left =
>> +         pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT);
>> +      wpos_options.fs_coord_origin_lower_left =
>> +         pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT);
>> +      wpos_options.fs_coord_pixel_center_integer =
>> +         pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
>> +      wpos_options.fs_coord_pixel_center_half_integer =
>> +         pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER);
>> +
>> +      if (OPT(nir, nir_lower_wpos_ytransform, &wpos_options)) {
>> +         _mesa_add_state_reference(prog->Parameters, wposTransformState);
>> +      }
>> +   }
>> +
>> +   // XXX do we need anything else from brw_create_nir().. and what
>> +   // is best way to split up which things should be here vs driver?
>> +   // currently just trying to make the result here similar to what
>> +   // we get from tgsi_to_nir().. so lower_io, etc..
>> +
>> +   if (st->ctx->_Shader->Flags & GLSL_DUMP) {
>> +      _mesa_log("\n");
>> +      _mesa_log("NIR IR for linked %s program %d:\n",
>> +             _mesa_shader_stage_to_string(stage),
>> +             shader_program->Name);
>> +      nir_print_shader(nir, _mesa_get_log_file());
>> +      _mesa_log("\n\n");
>> +   }
>> +
>> +   return nir;
>> +}
>> +
>> +/* TODO any better helper somewhere to sort a list? */
>> +
>> +static void
>> +insert_sorted(struct exec_list *var_list, nir_variable *new_var)
>> +{
>> +   nir_foreach_variable(var, var_list) {
>> +      if (var->data.location > new_var->data.location) {
>> +         exec_node_insert_node_before(&var->node, &new_var->node);
>> +         return;
>> +      }
>> +   }
>> +   exec_list_push_tail(var_list, &new_var->node);
>> +}
>> +
>> +static void
>> +sort_varyings(struct exec_list *var_list)
>> +{
>> +   struct exec_list new_list;
>> +   exec_list_make_empty(&new_list);
>> +   nir_foreach_variable_safe(var, var_list) {
>> +      exec_node_remove(&var->node);
>> +      insert_sorted(&new_list, var);
>> +   }
>> +   exec_list_move_nodes_to(&new_list, var_list);
>> +}
>> +
>> +/* Second half of preparing nir from glsl, which happens after shader
>> + * variant lowering.
>> + */
>> +void
>> +st_finalize_nir(struct st_context *st, struct gl_program *prog, nir_shader *nir)
>> +{
>> +   OPT_V(nir, nir_split_var_copies);
>> +   OPT_V(nir, nir_lower_var_copies);
>> +   OPT_V(nir, nir_lower_io_types, st_glsl_type_size);
>> +
>> +   if (nir->stage == MESA_SHADER_VERTEX) {
>> +      /* Needs special handling so drvloc matches the vbo state: */
>> +      st_nir_assign_vs_in_locations(prog, &nir->inputs, &nir->num_inputs);
>> +      sort_varyings(&nir->outputs);
>> +      nir_assign_var_locations(&nir->outputs,
>> +                               &nir->num_outputs,
>> +                               st_glsl_type_size);
>> +      st_nir_fixup_varying_slots(st, &nir->outputs);
>> +   } else if (nir->stage == MESA_SHADER_FRAGMENT) {
>> +      sort_varyings(&nir->inputs);
>> +      nir_assign_var_locations(&nir->inputs,
>> +                               &nir->num_inputs,
>> +                               st_glsl_type_size);
>> +      st_nir_fixup_varying_slots(st, &nir->inputs);
>> +      nir_assign_var_locations(&nir->outputs,
>> +                               &nir->num_outputs,
>> +                               st_glsl_type_size);
>> +   } else {
>> +      unreachable("invalid shader type for tgsi bypass\n");
>> +   }
>> +
>> +   struct gl_shader_program *shader_program;
>> +   switch (nir->stage) {
>> +   case MESA_SHADER_VERTEX:
>> +      shader_program = ((struct st_vertex_program *)prog)->shader_program;
>> +      break;
>> +   case MESA_SHADER_FRAGMENT:
>> +      shader_program = ((struct st_fragment_program *)prog)->shader_program;
>> +      break;
>> +   default:
>> +      assert(!"should not be reached");
>> +      return;
>> +   }
>> +
>> +   st_nir_assign_uniform_locations(prog, shader_program,
>> +                                   &nir->uniforms, &nir->num_uniforms);
>> +
>> +   OPT_V(nir, nir_lower_system_values);
>> +   OPT_V(nir, nir_lower_io, nir_var_all, st_glsl_type_size);
>> +   OPT_V(nir, nir_lower_samplers, shader_program);
>> +}
>> +
>> +struct gl_program *
>> +st_nir_get_mesa_program(struct gl_context *ctx,
>> +                        struct gl_shader_program *shader_program,
>> +                        struct gl_shader *shader)
>> +{
>> +   struct gl_program *prog;
>> +   GLenum target = _mesa_shader_stage_to_program(shader->Stage);
>> +
>> +   validate_ir_tree(shader->ir);
>> +
>> +   prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name);
>> +   if (!prog)
>> +      return NULL;
>> +
>> +   prog->Parameters = _mesa_new_parameter_list();
>> +
>> +   _mesa_copy_linked_program_data(shader->Stage, shader_program, prog);
>> +   _mesa_generate_parameters_list_for_uniforms(shader_program, shader,
>> +                                               prog->Parameters);
>> +
>> +   /* Make a pass over the IR to add state references for any built-in
>> +    * uniforms that are used.  This has to be done now (during linking).
>> +    * Code generation doesn't happen until the first time this shader is
>> +    * used for rendering.  Waiting until then to generate the parameters is
>> +    * too late.  At that point, the values for the built-in uniforms won't
>> +    * get sent to the shader.
>> +    */
>> +   foreach_in_list(ir_instruction, node, shader->ir) {
>> +      ir_variable *var = node->as_variable();
>> +
>> +      if ((var == NULL) || (var->data.mode != ir_var_uniform) ||
>> +          (strncmp(var->name, "gl_", 3) != 0))
>> +         continue;
>> +
>> +      const ir_state_slot *const slots = var->get_state_slots();
>> +      assert(slots != NULL);
>> +
>> +      for (unsigned int i = 0; i < var->get_num_state_slots(); i++) {
>> +         _mesa_add_state_reference(prog->Parameters,
>> +                                   (gl_state_index *) slots[i].tokens);
>> +      }
>> +   }
>> +
>> +   if (ctx->_Shader->Flags & GLSL_DUMP) {
>> +      _mesa_log("\n");
>> +      _mesa_log("GLSL IR for linked %s program %d:\n",
>> +             _mesa_shader_stage_to_string(shader->Stage),
>> +             shader_program->Name);
>> +      _mesa_print_ir(_mesa_get_log_file(), shader->ir, NULL);
>> +      _mesa_log("\n\n");
>> +   }
>> +
>> +   prog->Instructions = NULL;
>> +   prog->NumInstructions = 0;
>> +
>> +   do_set_program_inouts(shader->ir, prog, shader->Stage);
>> +
>> +   prog->SamplersUsed = shader->active_samplers;
>> +   prog->ShadowSamplers = shader->shadow_samplers;
>> +   _mesa_update_shader_textures_used(shader_program, prog);
>> +
>> +   _mesa_reference_program(ctx, &shader->Program, prog);
>> +
>> +   /* Avoid reallocation of the program parameter list, because the uniform
>> +    * storage is only associated with the original parameter list.
>> +    * This should be enough for Bitmap and DrawPixels constants.
>> +    */
>> +   _mesa_reserve_parameter_storage(prog->Parameters, 8);
>> +
>> +   /* This has to be done last.  Any operation the can cause
>> +    * prog->ParameterValues to get reallocated (e.g., anything that adds a
>> +    * program constant) has to happen before creating this linkage.
>> +    */
>> +   _mesa_associate_uniform_storage(ctx, shader_program, prog->Parameters);
>> +
>> +   struct st_vertex_program *stvp;
>> +   struct st_fragment_program *stfp;
>> +
>> +   switch (shader->Type) {
>> +   case GL_VERTEX_SHADER:
>> +      stvp = (struct st_vertex_program *)prog;
>> +      stvp->shader_program = shader_program;
>> +      break;
>> +   case GL_FRAGMENT_SHADER:
>> +      stfp = (struct st_fragment_program *)prog;
>> +      stfp->shader_program = shader_program;
>> +      break;
>> +   default:
>> +      assert(!"should not be reached");
>> +      return NULL;
>> +   }
>> +
>> +   return prog;
>> +}
>> +
>> +} /* extern "C" */
>> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
>> index fa03c16..631ce3c 100644
>> --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
>> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
>> @@ -53,6 +53,7 @@
>>  #include "st_mesa_to_tgsi.h"
>>  #include "st_format.h"
>>  #include "st_glsl_types.h"
>> +#include "st_nir.h"
>>
>>
>>  #define PROGRAM_ANY_CONST ((1 << PROGRAM_STATE_VAR) |    \
>> @@ -6376,9 +6377,9 @@ out:
>>   * generating Mesa IR.
>>   */
>>  static struct gl_program *
>> -get_mesa_program(struct gl_context *ctx,
>> -                 struct gl_shader_program *shader_program,
>> -                 struct gl_shader *shader)
>> +get_mesa_program_tgsi(struct gl_context *ctx,
>> +                      struct gl_shader_program *shader_program,
>> +                      struct gl_shader *shader)
>>  {
>>     glsl_to_tgsi_visitor* v;
>>     struct gl_program *prog;
>> @@ -6586,6 +6587,29 @@ get_mesa_program(struct gl_context *ctx,
>>     return prog;
>>  }
>>
>> +static struct gl_program *
>> +get_mesa_program(struct gl_context *ctx,
>> +                 struct gl_shader_program *shader_program,
>> +                 struct gl_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);
>> +   if (preferred_ir == PIPE_SHADER_IR_NIR) {
>> +      /* TODO only for GLSL VS/FS for now: */
>> +      switch (shader->Type) {
>> +      case GL_VERTEX_SHADER:
>> +      case GL_FRAGMENT_SHADER:
>> +         return st_nir_get_mesa_program(ctx, shader_program, shader);
>> +      default:
>> +         break;
>> +      }
>> +   }
>> +   return get_mesa_program_tgsi(ctx, shader_program, shader);
>> +}
>> +
>> +
>>  extern "C" {
>>
>>  static void
>> @@ -6788,9 +6812,17 @@ st_translate_stream_output_info(glsl_to_tgsi_visitor *glsl_to_tgsi,
>>                                  const GLuint outputMapping[],
>>                                  struct pipe_stream_output_info *so)
>>  {
>> -   unsigned i;
>>     struct gl_transform_feedback_info *info =
>>        &glsl_to_tgsi->shader_program->LinkedTransformFeedback;
>> +   st_translate_stream_output_info2(info, outputMapping, so);
>> +}
>> +
>> +void
>> +st_translate_stream_output_info2(struct gl_transform_feedback_info *info,
>> +                                const GLuint outputMapping[],
>> +                                struct pipe_stream_output_info *so)
>> +{
>> +   unsigned i;
>>
>>     for (i = 0; i < info->NumOutputs; i++) {
>>        so->output[i].register_index =
>> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.h b/src/mesa/state_tracker/st_glsl_to_tgsi.h
>> index 729295b..1986025 100644
>> --- a/src/mesa/state_tracker/st_glsl_to_tgsi.h
>> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.h
>> @@ -63,6 +63,11 @@ st_translate_stream_output_info(struct glsl_to_tgsi_visitor *glsl_to_tgsi,
>>                                  const GLuint outputMapping[],
>>                                  struct pipe_stream_output_info *so);
>>
>> +void
>> +st_translate_stream_output_info2(struct gl_transform_feedback_info *info,
>> +                                const GLuint outputMapping[],
>> +                                struct pipe_stream_output_info *so);
>> +
>>  extern const unsigned _mesa_sysval_to_semantic[SYSTEM_VALUE_MAX];
>>
>>  #ifdef __cplusplus
>> diff --git a/src/mesa/state_tracker/st_nir.h b/src/mesa/state_tracker/st_nir.h
>> index 1c07c4c..8c8a1d5 100644
>> --- a/src/mesa/state_tracker/st_nir.h
>> +++ b/src/mesa/state_tracker/st_nir.h
>> @@ -23,6 +23,38 @@
>>
>>  #pragma once
>>
>> +#include "st_context.h"
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>>  typedef struct nir_shader nir_shader;
>>
>>  void st_nir_lower_builtin(nir_shader *shader);
>> +
>> +#include "compiler/shader_enums.h"
>> +
>> +nir_shader * st_glsl_to_nir(struct st_context *st, struct gl_program *prog,
>> +                            struct gl_shader_program *shader_program,
>> +                            gl_shader_stage stage);
>> +
>> +void st_finalize_nir(struct st_context *st, struct gl_program *prog, nir_shader *nir);
>> +
>> +struct gl_program *
>> +st_nir_get_mesa_program(struct gl_context *ctx,
>> +                        struct gl_shader_program *shader_program,
>> +                        struct gl_shader *shader);
>> +
>> +
>> +#define OPT(nir, pass, ...) ({                             \
>> +   bool this_progress = false;                             \
>> +   NIR_PASS(this_progress, nir, pass, ##__VA_ARGS__);      \
>> +   this_progress;                                          \
>> +})
>> +
>> +#define OPT_V(nir, pass, ...) NIR_PASS_V(nir, pass, ##__VA_ARGS__)
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif
>> diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
>> index 80dcfd8..048fe4b 100644
>> --- a/src/mesa/state_tracker/st_program.c
>> +++ b/src/mesa/state_tracker/st_program.c
>> @@ -38,6 +38,8 @@
>>  #include "program/prog_print.h"
>>  #include "program/programopt.h"
>>
>> +#include "compiler/nir/nir.h"
>> +
>>  #include "pipe/p_context.h"
>>  #include "pipe/p_defines.h"
>>  #include "pipe/p_shader_tokens.h"
>> @@ -53,6 +55,7 @@
>>  #include "st_context.h"
>>  #include "st_program.h"
>>  #include "st_mesa_to_tgsi.h"
>> +#include "st_nir.h"
>>  #include "cso_cache/cso_context.h"
>>
>>
>> @@ -69,10 +72,10 @@ delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv)
>>
>>     if (vpv->draw_shader)
>>        draw_delete_vertex_shader( st->draw, vpv->draw_shader );
>> -
>> -   if (vpv->tgsi.tokens)
>> +
>> +   if (((vpv->tgsi.type == PIPE_SHADER_IR_TGSI)) && vpv->tgsi.tokens)
>>        ureg_free_tokens(vpv->tgsi.tokens);
>> -
>> +
>>     free( vpv );
>>  }
>>
>> @@ -95,7 +98,7 @@ st_release_vp_variants( struct st_context *st,
>>
>>     stvp->variants = NULL;
>>
>> -   if (stvp->tgsi.tokens) {
>> +   if ((stvp->tgsi.type == PIPE_SHADER_IR_TGSI) && stvp->tgsi.tokens) {
>>        tgsi_free_tokens(stvp->tgsi.tokens);
>>        stvp->tgsi.tokens = NULL;
>>     }
>> @@ -132,7 +135,7 @@ st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp)
>>
>>     stfp->variants = NULL;
>>
>> -   if (stfp->tgsi.tokens) {
>> +   if ((stfp->tgsi.type == PIPE_SHADER_IR_TGSI) && stfp->tgsi.tokens) {
>>        ureg_free_tokens(stfp->tgsi.tokens);
>>        stfp->tgsi.tokens = NULL;
>>     }
>> @@ -355,9 +358,23 @@ st_translate_vertex_program(struct st_context *st,
>>     output_semantic_name[num_outputs] = TGSI_SEMANTIC_EDGEFLAG;
>>     output_semantic_index[num_outputs] = 0;
>>
>> -   if (!stvp->glsl_to_tgsi)
>> +   if (!stvp->glsl_to_tgsi && !stvp->shader_program)
>>        _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT);
>>
>> +   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,
>> +                                       &stvp->tgsi.stream_output);
>> +      return true;
>> +   }
>> +
>>     ureg = ureg_create_with_screen(TGSI_PROCESSOR_VERTEX, st->pipe->screen);
>>     if (ureg == NULL)
>>        return false;
>> @@ -437,10 +454,27 @@ st_create_vp_variant(struct st_context *st,
>>     struct pipe_context *pipe = st->pipe;
>>
>>     vpv->key = *key;
>> -   vpv->tgsi.tokens = tgsi_dup_tokens(stvp->tgsi.tokens);
>>     vpv->tgsi.stream_output = stvp->tgsi.stream_output;
>>     vpv->num_inputs = stvp->num_inputs;
>>
>> +   if (stvp->tgsi.type == PIPE_SHADER_IR_NIR) {
>> +      vpv->tgsi.type = PIPE_SHADER_IR_NIR;
>> +      vpv->tgsi.ir.nir = nir_shader_clone(NULL, stvp->tgsi.ir.nir);
>> +      if (key->clamp_color)
>> +         OPT_V(vpv->tgsi.ir.nir, nir_lower_clamp_color_outputs);
>> +      if (key->passthrough_edgeflags)
>> +         OPT_V(vpv->tgsi.ir.nir, nir_lower_passthrough_edgeflags);
>> +
>> +      st_finalize_nir(st, &stvp->Base.Base, vpv->tgsi.ir.nir);
>> +
>> +      vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi);
>> +      /* driver takes ownership of IR: */
>> +      vpv->tgsi.ir.nir = NULL;
>> +      return vpv;
>> +   }
>> +
>> +   vpv->tgsi.tokens = tgsi_dup_tokens(stvp->tgsi.tokens);
>> +
>>     /* Emulate features. */
>>     if (key->clamp_color || key->passthrough_edgeflags) {
>>        const struct tgsi_token *tokens;
>> @@ -550,7 +584,7 @@ st_translate_fragment_program(struct st_context *st,
>>
>>     memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr));
>>
>> -   if (!stfp->glsl_to_tgsi) {
>> +   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);
>> @@ -753,6 +787,17 @@ st_translate_fragment_program(struct st_context *st,
>>        }
>>     }
>>
>> +   if (stfp->shader_program) {
>> +      nir_shader *nir = st_glsl_to_nir(st, &stfp->Base.Base,
>> +                                       stfp->shader_program,
>> +                                       MESA_SHADER_FRAGMENT);
>> +
>> +      stfp->tgsi.type = PIPE_SHADER_IR_NIR;
>> +      stfp->tgsi.ir.nir = nir;
>> +
>> +      return true;
>> +   }
>> +
>>     ureg = ureg_create_with_screen(TGSI_PROCESSOR_FRAGMENT, st->pipe->screen);
>>     if (ureg == NULL)
>>        return false;
>> @@ -841,10 +886,84 @@ st_create_fp_variant(struct st_context *st,
>>     struct pipe_context *pipe = st->pipe;
>>     struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant);
>>     struct pipe_shader_state tgsi = {0};
>> +   struct gl_program_parameter_list *params = stfp->Base.Base.Parameters;
>> +   static const gl_state_index texcoord_state[STATE_LENGTH] =
>> +      { STATE_INTERNAL, STATE_CURRENT_ATTRIB, VERT_ATTRIB_TEX0 };
>> +   static const gl_state_index scale_state[STATE_LENGTH] =
>> +      { STATE_INTERNAL, STATE_PT_SCALE };
>> +   static const gl_state_index bias_state[STATE_LENGTH] =
>> +      { STATE_INTERNAL, STATE_PT_BIAS };
>>
>>     if (!variant)
>>        return NULL;
>>
>> +   if (stfp->tgsi.type == PIPE_SHADER_IR_NIR) {
>> +      tgsi.type = PIPE_SHADER_IR_NIR;
>> +      tgsi.ir.nir = nir_shader_clone(NULL, stfp->tgsi.ir.nir);
>> +
>> +      if (key->clamp_color)
>> +         OPT_V(tgsi.ir.nir, nir_lower_clamp_color_outputs);
>> +
>> +      if (key->persample_shading) {
>> +          nir_shader *shader = tgsi.ir.nir;
>> +          nir_foreach_variable(var, &shader->inputs)
>> +             var->data.sample = true;
>> +      }
>> +
>> +      assert(!(key->bitmap && key->drawpixels));
>> +
>> +      /* glBitmap */
>> +      if (key->bitmap) {
>> +         nir_lower_bitmap_options options = {0};
>> +
>> +         variant->bitmap_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1;
>> +         options.sampler = variant->bitmap_sampler;
>> +         options.swizzle_xxxx = (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM);
>> +
>> +         OPT_V(tgsi.ir.nir, nir_lower_bitmap, &options);
>> +      }
>> +
>> +      /* glDrawPixels (color only) */
>> +      if (key->drawpixels) {
>> +         nir_lower_drawpixels_options options = {0};
>> +         unsigned samplers_used = stfp->Base.Base.SamplersUsed;
>> +
>> +         /* Find the first unused slot. */
>> +         variant->drawpix_sampler = ffs(~samplers_used) - 1;
>> +         options.drawpix_sampler = variant->drawpix_sampler;
>> +         samplers_used |= (1 << variant->drawpix_sampler);
>> +
>> +         options.pixel_maps = key->pixelMaps;
>> +         if (key->pixelMaps) {
>> +            variant->pixelmap_sampler = ffs(~samplers_used) - 1;
>> +            options.pixelmap_sampler = variant->pixelmap_sampler;
>> +         }
>> +
>> +         options.scale_and_bias = key->scaleAndBias;
>> +         if (key->scaleAndBias) {
>> +            _mesa_add_state_reference(params, scale_state);
>> +            memcpy(options.scale_state_tokens, scale_state,
>> +                   sizeof(options.scale_state_tokens));
>> +            _mesa_add_state_reference(params, bias_state);
>> +            memcpy(options.bias_state_tokens, bias_state,
>> +                   sizeof(options.bias_state_tokens));
>> +         }
>> +
>> +         _mesa_add_state_reference(params, texcoord_state);
>> +         memcpy(options.texcoord_state_tokens, texcoord_state,
>> +                sizeof(options.texcoord_state_tokens));
>> +
>> +         OPT_V(tgsi.ir.nir, nir_lower_drawpixels, &options);
>> +      }
>> +
>> +      st_finalize_nir(st, &stfp->Base.Base, tgsi.ir.nir);
>> +
>> +      variant->driver_shader = pipe->create_fs_state(pipe, &tgsi);
>> +      variant->key = *key;
>> +
>> +      return variant;
>> +   }
>> +
>>     tgsi.tokens = stfp->tgsi.tokens;
>>
>>     assert(!(key->bitmap && key->drawpixels));
>> @@ -889,7 +1008,6 @@ st_create_fp_variant(struct st_context *st,
>>     if (key->drawpixels) {
>>        const struct tgsi_token *tokens;
>>        unsigned scale_const = 0, bias_const = 0, texcoord_const = 0;
>> -      struct gl_program_parameter_list *params = stfp->Base.Base.Parameters;
>>
>>        /* Find the first unused slot. */
>>        variant->drawpix_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1;
>> @@ -902,21 +1020,11 @@ st_create_fp_variant(struct st_context *st,
>>        }
>>
>>        if (key->scaleAndBias) {
>> -         static const gl_state_index scale_state[STATE_LENGTH] =
>> -            { STATE_INTERNAL, STATE_PT_SCALE };
>> -         static const gl_state_index bias_state[STATE_LENGTH] =
>> -            { STATE_INTERNAL, STATE_PT_BIAS };
>> -
>>           scale_const = _mesa_add_state_reference(params, scale_state);
>>           bias_const = _mesa_add_state_reference(params, bias_state);
>>        }
>>
>> -      {
>> -         static const gl_state_index state[STATE_LENGTH] =
>> -            { STATE_INTERNAL, STATE_CURRENT_ATTRIB, VERT_ATTRIB_TEX0 };
>> -
>> -         texcoord_const = _mesa_add_state_reference(params, state);
>> -      }
>> +      texcoord_const = _mesa_add_state_reference(params, texcoord_state);
>>
>>        tokens = st_get_drawpix_shader(tgsi.tokens,
>>                                       st->needs_texcoord_semantic,
>> diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h
>> index 028fba9..8278814 100644
>> --- a/src/mesa/state_tracker/st_program.h
>> +++ b/src/mesa/state_tracker/st_program.h
>> @@ -100,6 +100,9 @@ struct st_fragment_program
>>     struct pipe_shader_state tgsi;
>>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
>>
>> +   /* used when bypassing glsl_to_tgsi: */
>> +   struct gl_shader_program *shader_program;
>> +
>>     struct st_fp_variant *variants;
>>  };
>>
>> @@ -156,6 +159,9 @@ struct st_vertex_program
>>     struct pipe_shader_state tgsi;
>>     struct glsl_to_tgsi_visitor* glsl_to_tgsi;
>>
>> +   /* 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];
>> --
>> 2.5.5
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list