nir: add support for gather offsets
authorKarol Herbst <kherbst@redhat.com>
Mon, 18 Mar 2019 20:23:59 +0000 (21:23 +0100)
committerKarol Herbst <karolherbst@gmail.com>
Thu, 21 Mar 2019 02:58:41 +0000 (02:58 +0000)
Values inside the offsets parameter of textureGatherOffsets are required to be
constants in the range of [GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET,
GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET].

As this range is never outside [-32, 31] for all existing drivers inside mesa,
we can simply store the offsets as a int8_t[4][2] array inside nir_tex_instr.

Right now only Nvidia hardware supports this in hardware, so we can turn this
on inside Nouveau for the NIR path as it is already enabled with the TGSI one.

v2: use memcpy instead of for loops
    add missing bits to nir_instr_set
    don't show offsets if they are all 0
v3: default offsets aren't all 0
v4: rename offsets -> tg4_offsets
    rename nir_tex_instr_has_explicit_offsets -> nir_tex_instr_has_explicit_tg4_offsets

Signed-off-by: Karol Herbst <kherbst@redhat.com>
src/compiler/glsl/glsl_to_nir.cpp
src/compiler/nir/nir.c
src/compiler/nir/nir.h
src/compiler/nir/nir_clone.c
src/compiler/nir/nir_instr_set.c
src/compiler/nir/nir_print.c
src/compiler/nir/nir_serialize.c
src/compiler/nir/nir_validate.c

index 9084803adf134f5ffb44c11ffca3bc6ac295162f..6a1a0b5f113e2d36555a809b0e8381ee306b105b 100644 (file)
@@ -2378,7 +2378,8 @@ nir_visitor::visit(ir_texture *ir)
       num_srcs++;
    if (ir->shadow_comparator != NULL)
       num_srcs++;
-   if (ir->offset != NULL)
+   /* offsets are constants we store inside nir_tex_intrs.offsets */
+   if (ir->offset != NULL && !ir->offset->type->is_array())
       num_srcs++;
 
    /* Add one for the texture deref */
@@ -2439,13 +2440,25 @@ nir_visitor::visit(ir_texture *ir)
    }
 
    if (ir->offset != NULL) {
-      /* we don't support multiple offsets yet */
-      assert(ir->offset->type->is_vector() || ir->offset->type->is_scalar());
+      if (ir->offset->type->is_array()) {
+         for (int i = 0; i < ir->offset->type->array_size(); i++) {
+            const ir_constant *c =
+               ir->offset->as_constant()->get_array_element(i);
+
+            for (unsigned j = 0; j < 2; ++j) {
+               int val = c->get_int_component(j);
+               assert(val <= 31 && val >= -32);
+               instr->tg4_offsets[i][j] = val;
+            }
+         }
+      } else {
+         assert(ir->offset->type->is_vector() || ir->offset->type->is_scalar());
 
-      instr->src[src_number].src =
-         nir_src_for_ssa(evaluate_rvalue(ir->offset));
-      instr->src[src_number].src_type = nir_tex_src_offset;
-      src_number++;
+         instr->src[src_number].src =
+            nir_src_for_ssa(evaluate_rvalue(ir->offset));
+         instr->src[src_number].src_type = nir_tex_src_offset;
+         src_number++;
+      }
    }
 
    switch (ir->op) {
index 4a7c757db3a4f8190097087f625ea7ac6334d155..0daafc4936daa77a28199536d3fb348e0d523567 100644 (file)
@@ -531,6 +531,14 @@ nir_call_instr_create(nir_shader *shader, nir_function *callee)
    return instr;
 }
 
+static int8_t default_tg4_offsets[4][2] =
+{
+   { 0, 1 },
+   { 1, 1 },
+   { 1, 0 },
+   { 0, 0 },
+};
+
 nir_tex_instr *
 nir_tex_instr_create(nir_shader *shader, unsigned num_srcs)
 {
@@ -547,6 +555,7 @@ nir_tex_instr_create(nir_shader *shader, unsigned num_srcs)
    instr->texture_index = 0;
    instr->texture_array_size = 0;
    instr->sampler_index = 0;
+   memcpy(instr->tg4_offsets, default_tg4_offsets, sizeof(instr->tg4_offsets));
 
    return instr;
 }
@@ -589,6 +598,15 @@ nir_tex_instr_remove_src(nir_tex_instr *tex, unsigned src_idx)
    tex->num_srcs--;
 }
 
+bool
+nir_tex_instr_has_explicit_tg4_offsets(nir_tex_instr *tex)
+{
+   if (tex->op != nir_texop_tg4)
+      return false;
+   return memcmp(tex->tg4_offsets, default_tg4_offsets,
+                 sizeof(tex->tg4_offsets)) != 0;
+}
+
 nir_phi_instr *
 nir_phi_instr_create(nir_shader *shader)
 {
index f9c2adb83e5985b26b4565a9ec2e6dc547ce3104..2c1caf2687aff9137911b811d6cfc2b02a977d09 100644 (file)
@@ -1482,6 +1482,9 @@ typedef struct {
    /* gather component selector */
    unsigned component : 2;
 
+   /* gather offsets */
+   int8_t tg4_offsets[4][2];
+
    /** The texture index
     *
     * If this texture instruction has a nir_tex_src_texture_offset source,
@@ -1699,6 +1702,8 @@ void nir_tex_instr_add_src(nir_tex_instr *tex,
 
 void nir_tex_instr_remove_src(nir_tex_instr *tex, unsigned src_idx);
 
+bool nir_tex_instr_has_explicit_tg4_offsets(nir_tex_instr *tex);
+
 typedef struct {
    nir_instr instr;
 
index fa24f8b6028bd38b0baf7025d078c7a70d242f1c..9594eb8044d430d8cc2f5fbff2baaee1582301ad 100644 (file)
@@ -394,6 +394,7 @@ clone_tex(clone_state *state, const nir_tex_instr *tex)
    ntex->is_shadow = tex->is_shadow;
    ntex->is_new_style_shadow = tex->is_new_style_shadow;
    ntex->component = tex->component;
+   memcpy(ntex->tg4_offsets, tex->tg4_offsets, sizeof(tex->tg4_offsets));
 
    ntex->texture_index = tex->texture_index;
    ntex->texture_array_size = tex->texture_array_size;
index 8f4e971b89add855c9dd8d799caf7fcb50e0dc22..d106e9ebcae9e30432d01991128cf2ef5375879e 100644 (file)
@@ -200,6 +200,9 @@ hash_tex(uint32_t hash, const nir_tex_instr *instr)
    hash = HASH(hash, instr->is_new_style_shadow);
    unsigned component = instr->component;
    hash = HASH(hash, component);
+   for (unsigned i = 0; i < 4; ++i)
+      for (unsigned j = 0; j < 2; ++j)
+         hash = HASH(hash, instr->tg4_offsets[i][j]);
    hash = HASH(hash, instr->texture_index);
    hash = HASH(hash, instr->texture_array_size);
    hash = HASH(hash, instr->sampler_index);
@@ -403,6 +406,10 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2)
          return false;
       }
 
+      if (memcmp(tex1->tg4_offsets, tex2->tg4_offsets,
+                 sizeof(tex1->tg4_offsets)))
+         return false;
+
       return true;
    }
    case nir_instr_type_load_const: {
index 6b270394f9deca3cd8a9e0a69090e957d9a56725..8e714e6666b97a18588f7bdaf010686b07a6d770 100644 (file)
@@ -984,6 +984,14 @@ print_tex_instr(nir_tex_instr *instr, print_state *state)
       fprintf(fp, "%u (gather_component), ", instr->component);
    }
 
+   if (nir_tex_instr_has_explicit_tg4_offsets(instr)) {
+      fprintf(fp, "{ (%i, %i)", instr->tg4_offsets[0][0], instr->tg4_offsets[0][1]);
+      for (unsigned i = 1; i < 4; ++i)
+         fprintf(fp, ", (%i, %i)", instr->tg4_offsets[i][0],
+                 instr->tg4_offsets[i][1]);
+      fprintf(fp, " } (offsets), ");
+   }
+
    if (!has_texture_deref) {
       fprintf(fp, "%u (texture), ", instr->texture_index);
    }
index 840a1572786d75dc546c8a40e44eccecc785ad6a..fd8708fbb43d3b424c402efe6da335ce6c82f616 100644 (file)
@@ -617,6 +617,7 @@ write_tex(write_ctx *ctx, const nir_tex_instr *tex)
    blob_write_uint32(ctx->blob, tex->texture_index);
    blob_write_uint32(ctx->blob, tex->texture_array_size);
    blob_write_uint32(ctx->blob, tex->sampler_index);
+   blob_write_bytes(ctx->blob, tex->tg4_offsets, sizeof(tex->tg4_offsets));
 
    STATIC_ASSERT(sizeof(union packed_tex_data) == sizeof(uint32_t));
    union packed_tex_data packed = {
@@ -647,6 +648,7 @@ read_tex(read_ctx *ctx)
    tex->texture_index = blob_read_uint32(ctx->blob);
    tex->texture_array_size = blob_read_uint32(ctx->blob);
    tex->sampler_index = blob_read_uint32(ctx->blob);
+   blob_copy_bytes(ctx->blob, tex->tg4_offsets, sizeof(tex->tg4_offsets));
 
    union packed_tex_data packed;
    packed.u32 = blob_read_uint32(ctx->blob);
index 3a3c232d370044ac596dee33cc89bad89f85b39e..ef2e2b627834da729fd32bb510fc1a01986f7833 100644 (file)
@@ -598,6 +598,11 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state)
                    0, nir_tex_instr_src_size(instr, i));
    }
 
+   if (nir_tex_instr_has_explicit_tg4_offsets(instr)) {
+      validate_assert(state, instr->op == nir_texop_tg4);
+      validate_assert(state, !src_type_seen[nir_tex_src_offset]);
+   }
+
    validate_dest(&instr->dest, state, 0, nir_tex_instr_dest_size(instr));
 }