1 /*
2 * Copyright 2023 Valve Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "compiler/nir/nir_builder.h"
7 #include "libagx/geometry.h"
8 #include "libagx/libagx.h"
9 #include "agx_nir_lower_gs.h"
10 #include "nir.h"
11
12 /*
13 * This file implements basic input assembly in software. It runs on software
14 * vertex shaders, as part of geometry/tessellation lowering. It does not apply
15 * the topology, which happens in the geometry shader.
16 */
17 nir_def *
agx_nir_load_vertex_id(nir_builder * b,nir_def * id,unsigned index_size_B)18 agx_nir_load_vertex_id(nir_builder *b, nir_def *id, unsigned index_size_B)
19 {
20 /* If drawing with an index buffer, pull the vertex ID. Otherwise, the
21 * vertex ID is just the index as-is.
22 */
23 if (index_size_B) {
24 nir_def *ia = nir_load_input_assembly_buffer_agx(b);
25 id = libagx_load_index_buffer(b, ia, id, nir_imm_int(b, index_size_B));
26 }
27
28 /* Add the "start", either an index bias or a base vertex. This must happen
29 * after indexing for proper index bias behaviour.
30 */
31 return nir_iadd(b, id, nir_load_first_vertex(b));
32 }
33
34 static bool
lower(nir_builder * b,nir_intrinsic_instr * intr,void * data)35 lower(nir_builder *b, nir_intrinsic_instr *intr, void *data)
36 {
37 unsigned *index_size_B = data;
38 b->cursor = nir_before_instr(&intr->instr);
39
40 if (intr->intrinsic == nir_intrinsic_load_vertex_id) {
41 nir_def *id = nir_channel(b, nir_load_global_invocation_id(b, 32), 0);
42 nir_def_replace(&intr->def, agx_nir_load_vertex_id(b, id, *index_size_B));
43 return true;
44 } else if (intr->intrinsic == nir_intrinsic_load_instance_id) {
45 nir_def_replace(&intr->def,
46 nir_channel(b, nir_load_global_invocation_id(b, 32), 1));
47 return true;
48 }
49
50 return false;
51 }
52
53 bool
agx_nir_lower_sw_vs(nir_shader * s,unsigned index_size_B)54 agx_nir_lower_sw_vs(nir_shader *s, unsigned index_size_B)
55 {
56 return nir_shader_intrinsics_pass(s, lower, nir_metadata_control_flow,
57 &index_size_B);
58 }
59