1 /*
2 * Copyright 2023 Valve Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "asahi/compiler/agx_compile.h"
7 #include "compiler/nir/nir_builder.h"
8 #include "shaders/geometry.h"
9 #include "util/compiler.h"
10 #include "agx_nir_lower_gs.h"
11 #include "libagx_shaders.h"
12 #include "nir.h"
13 #include "nir_builder_opcodes.h"
14 #include "nir_intrinsics.h"
15 #include "shader_enums.h"
16
17 /*
18 * This file implements input assembly in software for geometry/tessellation
19 * shaders. load_vertex_id is lowered based on the topology. Most of the logic
20 * lives in CL library routines.
21 */
22
23 nir_def *
agx_vertex_id_for_topology_class(nir_builder * b,nir_def * vert,enum mesa_prim cls)24 agx_vertex_id_for_topology_class(nir_builder *b, nir_def *vert,
25 enum mesa_prim cls)
26 {
27 nir_def *prim = nir_load_primitive_id(b);
28 nir_def *flatshade_first = nir_ieq_imm(b, nir_load_provoking_last(b), 0);
29 nir_def *nr = nir_load_num_vertices(b);
30 nir_def *topology = nir_load_input_topology_agx(b);
31
32 switch (cls) {
33 case MESA_PRIM_POINTS:
34 return prim;
35
36 case MESA_PRIM_LINES:
37 return libagx_vertex_id_for_line_class(b, topology, prim, vert, nr);
38
39 case MESA_PRIM_TRIANGLES:
40 return libagx_vertex_id_for_tri_class(b, topology, prim, vert,
41 flatshade_first);
42
43 case MESA_PRIM_LINES_ADJACENCY:
44 return libagx_vertex_id_for_line_adj_class(b, topology, prim, vert);
45
46 case MESA_PRIM_TRIANGLES_ADJACENCY:
47 return libagx_vertex_id_for_tri_adj_class(b, topology, prim, vert, nr,
48 flatshade_first);
49
50 default:
51 unreachable("invalid topology class");
52 }
53 }
54
55 struct state {
56 unsigned index_size;
57 bool patches;
58 };
59
60 static nir_def *
load_vertex_id(nir_builder * b,struct state * state)61 load_vertex_id(nir_builder *b, struct state *state)
62 {
63 nir_def *id = nir_load_primitive_id(b);
64
65 if (state->patches) {
66 id = nir_iadd(b, nir_imul(b, id, nir_load_patch_vertices_in(b)),
67 nir_load_invocation_id(b));
68 }
69
70 /* If drawing with an index buffer, pull the vertex ID. Otherwise, the
71 * vertex ID is just the index as-is.
72 */
73 if (state->index_size) {
74 nir_def *ia = nir_load_input_assembly_buffer_agx(b);
75
76 nir_def *address =
77 libagx_index_buffer(b, ia, id, nir_imm_int(b, state->index_size));
78
79 nir_def *index = nir_load_global_constant(b, address, state->index_size,
80 1, state->index_size * 8);
81
82 id = nir_u2uN(b, index, id->bit_size);
83 }
84
85 /* Add the "start", either an index bias or a base vertex. This must happen
86 * after indexing for proper index bias behaviour.
87 */
88 return nir_iadd(b, id, nir_load_first_vertex(b));
89 }
90
91 static bool
lower_vertex_id(nir_builder * b,nir_intrinsic_instr * intr,void * data)92 lower_vertex_id(nir_builder *b, nir_intrinsic_instr *intr, void *data)
93 {
94 if (intr->intrinsic != nir_intrinsic_load_vertex_id)
95 return false;
96
97 b->cursor = nir_instr_remove(&intr->instr);
98 assert(intr->def.bit_size == 32);
99 nir_def_rewrite_uses(&intr->def, load_vertex_id(b, data));
100 return true;
101 }
102
103 bool
agx_nir_lower_index_buffer(nir_shader * s,unsigned index_size_B,bool patches)104 agx_nir_lower_index_buffer(nir_shader *s, unsigned index_size_B, bool patches)
105 {
106 return nir_shader_intrinsics_pass(
107 s, lower_vertex_id, nir_metadata_block_index | nir_metadata_dominance,
108 &(struct state){index_size_B, patches});
109 }
110