1 /*
2 * Copyright 2024 Valve Corpoation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "nir.h"
7 #include "nir_builder.h"
8 #include "nir_builder_opcodes.h"
9
10 /**
11 * If load_frag_coord.xy is only used by conversions to integer,
12 * replace it with load_pixel_coord.
13 */
14
15 static bool
opt_frag_pos(nir_builder * b,nir_intrinsic_instr * intr,UNUSED void * data)16 opt_frag_pos(nir_builder *b, nir_intrinsic_instr *intr, UNUSED void *data)
17 {
18 if (intr->intrinsic != nir_intrinsic_load_frag_coord)
19 return false;
20
21 /* Don't increase precision. */
22 if (intr->def.bit_size != 32)
23 return false;
24
25 /* Check if xy are only used by casts to integers. */
26 nir_foreach_use(use, &intr->def) {
27 if (nir_src_is_if(use))
28 return false;
29
30 unsigned mask = nir_src_components_read(use);
31
32 if (!(mask & 0x3))
33 continue;
34
35 /* Don't handle instructions that read x/y and z/w for simplicity. */
36 if (mask & ~0x3)
37 return false;
38
39 nir_instr *use_instr = nir_src_parent_instr(use);
40
41 if (use_instr->type != nir_instr_type_alu)
42 return false;
43
44 switch (nir_instr_as_alu(use_instr)->op) {
45 case nir_op_f2i8:
46 case nir_op_f2i16:
47 case nir_op_f2i32:
48 case nir_op_f2i64:
49 case nir_op_f2u8:
50 case nir_op_f2u16:
51 case nir_op_f2u32:
52 case nir_op_f2u64:
53 case nir_op_ftrunc:
54 case nir_op_ffloor:
55 continue;
56 default:
57 return false;
58 }
59 }
60
61 b->cursor = nir_before_instr(&intr->instr);
62 nir_def *pixel_coord = nir_load_pixel_coord(b);
63
64 nir_foreach_use_safe(use, &intr->def) {
65 unsigned mask = nir_src_components_read(use);
66
67 if (!(mask & 0x3))
68 continue;
69
70 nir_src_rewrite(use, pixel_coord);
71
72 nir_alu_instr *use_instr = nir_instr_as_alu(nir_src_parent_instr(use));
73
74 /* load_frag_coord is always positive, so we should never sign extend here. */
75 bool needs_float = use_instr->op == nir_op_ffloor || use_instr->op == nir_op_ftrunc;
76 nir_alu_type dst_type = (needs_float ? nir_type_float : nir_type_uint) | use_instr->def.bit_size;
77 use_instr->op = nir_type_conversion_op(nir_type_uint16, dst_type, nir_rounding_mode_undef);
78 }
79
80 return true;
81 }
82
83 bool
nir_opt_frag_coord_to_pixel_coord(nir_shader * shader)84 nir_opt_frag_coord_to_pixel_coord(nir_shader *shader)
85 {
86 return nir_shader_intrinsics_pass(shader, opt_frag_pos,
87 nir_metadata_control_flow,
88 NULL);
89 }
90