• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Valve Corporation
3  * Copyright 2023 Alyssa Rosenzweig
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "agx_tilebuffer.h"
8 #include "nir_builder.h"
9 
10 static nir_def *
mask_by_sample_id(nir_builder * b,nir_def * mask)11 mask_by_sample_id(nir_builder *b, nir_def *mask)
12 {
13    nir_def *id_mask =
14       nir_ishl(b, nir_imm_intN_t(b, 1, mask->bit_size), nir_load_sample_id(b));
15    return nir_iand(b, mask, id_mask);
16 }
17 
18 static bool
lower_to_sample(nir_builder * b,nir_intrinsic_instr * intr,void * _)19 lower_to_sample(nir_builder *b, nir_intrinsic_instr *intr, void *_)
20 {
21    b->cursor = nir_before_instr(&intr->instr);
22 
23    switch (intr->intrinsic) {
24    case nir_intrinsic_load_sample_pos: {
25       /* Lower sample positions to decode the packed fixed-point register:
26        *
27        *    uint32_t packed = load_sample_positions();
28        *    uint32_t shifted = packed >> (sample_id * 8);
29        *
30        *    for (i = 0; i < 2; ++i) {
31        *       uint8_t nibble = (shifted >> (i * 4)) & 0xF;
32        *       xy[component] = ((float)nibble) / 16.0;
33        *    }
34        */
35       nir_def *packed = nir_load_sample_positions_agx(b);
36 
37       /* The n'th sample is the in the n'th byte of the register */
38       nir_def *shifted = nir_ushr(
39          b, packed, nir_u2u32(b, nir_imul_imm(b, nir_load_sample_id(b), 8)));
40 
41       nir_def *xy[2];
42       for (unsigned i = 0; i < 2; ++i) {
43          /* Get the appropriate nibble */
44          nir_def *nibble =
45             nir_iand_imm(b, nir_ushr_imm(b, shifted, i * 4), 0xF);
46 
47          /* Convert it from fixed point to float */
48          xy[i] = nir_fmul_imm(b, nir_u2f16(b, nibble), 1.0 / 16.0);
49 
50          /* Upconvert if necessary */
51          xy[i] = nir_f2fN(b, xy[i], intr->def.bit_size);
52       }
53 
54       /* Collect and rewrite */
55       nir_def_rewrite_uses(&intr->def, nir_vec2(b, xy[0], xy[1]));
56       nir_instr_remove(&intr->instr);
57       return true;
58    }
59 
60    case nir_intrinsic_load_sample_mask_in: {
61       /* In OpenGL, gl_SampleMaskIn is only supposed to have the single bit set
62        * of the sample currently being shaded when sample shading is used. Mask
63        * by the sample ID to make that happen.
64        */
65       b->cursor = nir_after_instr(&intr->instr);
66       nir_def *old = &intr->def;
67       nir_def *lowered = mask_by_sample_id(b, old);
68       nir_def_rewrite_uses_after(old, lowered, lowered->parent_instr);
69       return true;
70    }
71 
72    case nir_intrinsic_load_barycentric_sample: {
73       /* Lower fragment varyings with "sample" interpolation to
74        * interpolateAtSample() with the sample ID
75        */
76       b->cursor = nir_after_instr(&intr->instr);
77       nir_def *old = &intr->def;
78 
79       nir_def *lowered = nir_load_barycentric_at_sample(
80          b, intr->def.bit_size, nir_load_sample_id(b),
81          .interp_mode = nir_intrinsic_interp_mode(intr));
82 
83       nir_def_rewrite_uses_after(old, lowered, lowered->parent_instr);
84       return true;
85    }
86 
87    default:
88       return false;
89    }
90 }
91 
92 /*
93  * In a fragment shader using sample shading, lower intrinsics like
94  * load_sample_position to variants in terms of load_sample_id. Except for a
95  * possible API bit to force sample shading in shaders that don't otherwise need
96  * it, this pass does not depend on the shader key. In particular, it does not
97  * depend on the sample count. So it runs on fragment shaders at compile-time.
98  * The load_sample_id intrinsics themselves are lowered later, with different
99  * lowerings for monolithic vs epilogs.
100  *
101  * Note that fragment I/O (like store_local_pixel_agx and discard_agx) does not
102  * get lowered here, because that lowering is different for monolithic vs FS
103  * epilogs even though there's no dependency on sample count.
104  */
105 bool
agx_nir_lower_sample_intrinsics(nir_shader * shader)106 agx_nir_lower_sample_intrinsics(nir_shader *shader)
107 {
108    /* If sample shading is disabled, the unlowered shader will broadcast pixel
109     * values across the sample (the default). By definition, there are no sample
110     * position or sample barycentrics, as these trigger sample shading.
111     */
112    if (!shader->info.fs.uses_sample_shading)
113       return false;
114 
115    return nir_shader_intrinsics_pass(
116       shader, lower_to_sample,
117       nir_metadata_block_index | nir_metadata_dominance, NULL);
118 }
119