Exemplo n.º 1
0
/**
 * Try to mark a portion of the given varying as used.  Caller must ensure
 * that the variable represents a shader input or output.
 *
 * If the index can't be interpreted as a constant, or some other problem
 * occurs, then nothing will be marked and false will be returned.
 */
static bool
try_mask_partial_io(nir_shader *shader, nir_variable *var,
                    nir_deref_instr *deref, bool is_output_read)
{
   const struct glsl_type *type = var->type;

   if (nir_is_per_vertex_io(var, shader->info.stage)) {
      assert(glsl_type_is_array(type));
      type = glsl_get_array_element(type);
   }

   /* The code below only handles:
    *
    * - Indexing into matrices
    * - Indexing into arrays of (arrays, matrices, vectors, or scalars)
    *
    * For now, we just give up if we see varying structs and arrays of structs
    * here marking the entire variable as used.
    */
   if (!(glsl_type_is_matrix(type) ||
         (glsl_type_is_array(type) && !var->data.compact &&
          (glsl_type_is_numeric(glsl_without_array(type)) ||
           glsl_type_is_boolean(glsl_without_array(type)))))) {

      /* If we don't know how to handle this case, give up and let the
       * caller mark the whole variable as used.
       */
      return false;
   }

   unsigned offset = get_io_offset(deref, false);
   if (offset == -1)
      return false;

   unsigned num_elems;
   unsigned elem_width = 1;
   unsigned mat_cols = 1;
   if (glsl_type_is_array(type)) {
      num_elems = glsl_get_aoa_size(type);
      if (glsl_type_is_matrix(glsl_without_array(type)))
         mat_cols = glsl_get_matrix_columns(glsl_without_array(type));
   } else {
      num_elems = glsl_get_matrix_columns(type);
   }

   /* double element width for double types that takes two slots */
   if (glsl_type_is_dual_slot(glsl_without_array(type)))
      elem_width *= 2;

   if (offset >= num_elems * elem_width * mat_cols) {
      /* Constant index outside the bounds of the matrix/array.  This could
       * arise as a result of constant folding of a legal GLSL program.
       *
       * Even though the spec says that indexing outside the bounds of a
       * matrix/array results in undefined behaviour, we don't want to pass
       * out-of-range values to set_io_mask() (since this could result in
       * slots that don't exist being marked as used), so just let the caller
       * mark the whole variable as used.
       */
      return false;
   }

   set_io_mask(shader, var, offset, elem_width, is_output_read);
   return true;
}
Exemplo n.º 2
0
static void
gather_intrinsic_info(nir_intrinsic_instr *instr, nir_shader *shader,
                      void *dead_ctx)
{
   switch (instr->intrinsic) {
   case nir_intrinsic_discard:
   case nir_intrinsic_discard_if:
      assert(shader->info.stage == MESA_SHADER_FRAGMENT);
      shader->info.fs.uses_discard = true;
      break;

   case nir_intrinsic_interp_deref_at_centroid:
   case nir_intrinsic_interp_deref_at_sample:
   case nir_intrinsic_interp_deref_at_offset:
   case nir_intrinsic_load_deref:
   case nir_intrinsic_store_deref:{
      nir_deref_instr *deref = nir_src_as_deref(instr->src[0]);
      nir_variable *var = nir_deref_instr_get_variable(deref);

      if (var->data.mode == nir_var_shader_in ||
          var->data.mode == nir_var_shader_out) {
         bool is_output_read = false;
         if (var->data.mode == nir_var_shader_out &&
             instr->intrinsic == nir_intrinsic_load_deref)
            is_output_read = true;

         if (!try_mask_partial_io(shader, var, deref, is_output_read))
            mark_whole_variable(shader, var, is_output_read);

         /* We need to track which input_reads bits correspond to a
          * dvec3/dvec4 input attribute */
         if (shader->info.stage == MESA_SHADER_VERTEX &&
             var->data.mode == nir_var_shader_in &&
             glsl_type_is_dual_slot(glsl_without_array(var->type))) {
            for (unsigned i = 0; i < glsl_count_attribute_slots(var->type, false); i++) {
               int idx = var->data.location + i;
               shader->info.vs.double_inputs |= BITFIELD64_BIT(idx);
            }
         }
      }
      break;
   }

   case nir_intrinsic_load_draw_id:
   case nir_intrinsic_load_frag_coord:
   case nir_intrinsic_load_front_face:
   case nir_intrinsic_load_vertex_id:
   case nir_intrinsic_load_vertex_id_zero_base:
   case nir_intrinsic_load_base_vertex:
   case nir_intrinsic_load_first_vertex:
   case nir_intrinsic_load_is_indexed_draw:
   case nir_intrinsic_load_base_instance:
   case nir_intrinsic_load_instance_id:
   case nir_intrinsic_load_sample_id:
   case nir_intrinsic_load_sample_pos:
   case nir_intrinsic_load_sample_mask_in:
   case nir_intrinsic_load_primitive_id:
   case nir_intrinsic_load_invocation_id:
   case nir_intrinsic_load_local_invocation_id:
   case nir_intrinsic_load_local_invocation_index:
   case nir_intrinsic_load_work_group_id:
   case nir_intrinsic_load_num_work_groups:
   case nir_intrinsic_load_tess_coord:
   case nir_intrinsic_load_tess_level_outer:
   case nir_intrinsic_load_tess_level_inner:
   case nir_intrinsic_load_patch_vertices_in:
      shader->info.system_values_read |=
         (1ull << nir_system_value_from_intrinsic(instr->intrinsic));
      break;

   case nir_intrinsic_end_primitive:
   case nir_intrinsic_end_primitive_with_counter:
      assert(shader->info.stage == MESA_SHADER_GEOMETRY);
      shader->info.gs.uses_end_primitive = 1;
      /* fall through */

   case nir_intrinsic_emit_vertex:
      if (nir_intrinsic_stream_id(instr) > 0)
         shader->info.gs.uses_streams = true;

      break;

   default:
      break;
   }
}
Exemplo n.º 3
0
static void
var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
                  const struct vtn_decoration *dec, void *void_var)
{
   struct vtn_variable *vtn_var = void_var;

   /* Handle decorations that apply to a vtn_variable as a whole */
   switch (dec->decoration) {
   case SpvDecorationNonWritable:
      /* Do nothing with this for now */
      return;
   case SpvDecorationBinding:
      vtn_var->binding = dec->literals[0];
      return;
   case SpvDecorationDescriptorSet:
      vtn_var->descriptor_set = dec->literals[0];
      return;

   case SpvDecorationLocation: {
      unsigned location = dec->literals[0];
      bool is_vertex_input;
      if (b->shader->stage == MESA_SHADER_FRAGMENT &&
          vtn_var->mode == vtn_variable_mode_output) {
         is_vertex_input = false;
         location += FRAG_RESULT_DATA0;
      } else if (b->shader->stage == MESA_SHADER_VERTEX &&
                 vtn_var->mode == vtn_variable_mode_input) {
         is_vertex_input = true;
         location += VERT_ATTRIB_GENERIC0;
      } else if (vtn_var->mode == vtn_variable_mode_input ||
                 vtn_var->mode == vtn_variable_mode_output) {
         is_vertex_input = false;
         location += VARYING_SLOT_VAR0;
      } else {
         assert(!"Location must be on input or output variable");
      }

      if (vtn_var->var) {
         vtn_var->var->data.location = location;
         vtn_var->var->data.explicit_location = true;
      } else {
         assert(vtn_var->members);
         unsigned length =
            glsl_get_length(glsl_without_array(vtn_var->type->type));
         for (unsigned i = 0; i < length; i++) {
            vtn_var->members[i]->data.location = location;
            vtn_var->members[i]->data.explicit_location = true;
            location +=
               glsl_count_attribute_slots(vtn_var->members[i]->interface_type,
                                          is_vertex_input);
         }
      }
      return;
   }

   default:
      break;
   }

   /* Now we handle decorations that apply to a particular nir_variable */
   nir_variable *nir_var = vtn_var->var;
   if (val->value_type == vtn_value_type_access_chain) {
      assert(val->access_chain->length == 0);
      assert(val->access_chain->var == void_var);
      assert(member == -1);
   } else {
      assert(val->value_type == vtn_value_type_type);
      if (member != -1)
         nir_var = vtn_var->members[member];
   }

   if (nir_var == NULL)
      return;

   switch (dec->decoration) {
   case SpvDecorationRelaxedPrecision:
      break; /* FIXME: Do nothing with this for now. */
   case SpvDecorationNoPerspective:
      nir_var->data.interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
      break;
   case SpvDecorationFlat:
      nir_var->data.interpolation = INTERP_QUALIFIER_FLAT;
      break;
   case SpvDecorationCentroid:
      nir_var->data.centroid = true;
      break;
   case SpvDecorationSample:
      nir_var->data.sample = true;
      break;
   case SpvDecorationInvariant:
      nir_var->data.invariant = true;
      break;
   case SpvDecorationConstant:
      assert(nir_var->constant_initializer != NULL);
      nir_var->data.read_only = true;
      break;
   case SpvDecorationNonWritable:
      nir_var->data.read_only = true;
      break;
   case SpvDecorationComponent:
      nir_var->data.location_frac = dec->literals[0];
      break;
   case SpvDecorationIndex:
      nir_var->data.explicit_index = true;
      nir_var->data.index = dec->literals[0];
      break;
   case SpvDecorationBuiltIn: {
      SpvBuiltIn builtin = dec->literals[0];

      if (builtin == SpvBuiltInWorkgroupSize) {
         /* This shouldn't be a builtin.  It's actually a constant. */
         nir_var->data.mode = nir_var_global;
         nir_var->data.read_only = true;

         nir_constant *c = rzalloc(nir_var, nir_constant);
         c->value.u[0] = b->shader->info.cs.local_size[0];
         c->value.u[1] = b->shader->info.cs.local_size[1];
         c->value.u[2] = b->shader->info.cs.local_size[2];
         nir_var->constant_initializer = c;
         break;
      }

      nir_variable_mode mode = nir_var->data.mode;
      vtn_get_builtin_location(b, builtin, &nir_var->data.location, &mode);
      nir_var->data.explicit_location = true;
      nir_var->data.mode = mode;

      if (builtin == SpvBuiltInFragCoord || builtin == SpvBuiltInSamplePosition)
         nir_var->data.origin_upper_left = b->origin_upper_left;
      break;
   }
   case SpvDecorationRowMajor:
   case SpvDecorationColMajor:
   case SpvDecorationGLSLShared:
   case SpvDecorationPatch:
   case SpvDecorationRestrict:
   case SpvDecorationAliased:
   case SpvDecorationVolatile:
   case SpvDecorationCoherent:
   case SpvDecorationNonReadable:
   case SpvDecorationUniform:
      /* This is really nice but we have no use for it right now. */
   case SpvDecorationCPacked:
   case SpvDecorationSaturatedConversion:
   case SpvDecorationStream:
   case SpvDecorationOffset:
   case SpvDecorationXfbBuffer:
   case SpvDecorationFuncParamAttr:
   case SpvDecorationFPRoundingMode:
   case SpvDecorationFPFastMathMode:
   case SpvDecorationLinkageAttributes:
   case SpvDecorationSpecId:
      break;
   default:
      unreachable("Unhandled variable decoration");
   }
}