• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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