1 /*
2 * Copyright 2024 Valve Corporation
3 * Copyright 2024 Alyssa Rosenzweig
4 * Copyright 2022 Collabora Ltd.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "util/bitscan.h"
9 #include "hk_shader.h"
10 #include "nir.h"
11 #include "nir_builder.h"
12 #include "nir_xfb_info.h"
13 #include "shader_enums.h"
14
15 void
hk_nir_passthrough_gs(nir_builder * b,const void * key_)16 hk_nir_passthrough_gs(nir_builder *b, const void *key_)
17 {
18 nir_shader *s = b->shader;
19 const struct hk_passthrough_gs_key *key = key_;
20 assert(key->prim == u_decomposed_prim(key->prim));
21 assert(key->prim != MESA_PRIM_PATCHES && "tessellation consumes patches");
22
23 enum mesa_prim out;
24 if (key->prim == MESA_PRIM_POINTS)
25 out = MESA_PRIM_POINTS;
26 else if (u_reduced_prim(key->prim) == MESA_PRIM_LINES)
27 out = MESA_PRIM_LINE_STRIP;
28 else
29 out = MESA_PRIM_TRIANGLE_STRIP;
30
31 #if 0
32 assert((key->outputs &
33 (VARYING_BIT_BOUNDING_BOX0 | VARYING_BIT_BOUNDING_BOX1)) == 0 &&
34 "cull distance lowering not run yet");
35 #endif
36 /* XXX: need rework of preprocess_nir */
37 uint64_t outputs =
38 key->outputs & ~(VARYING_BIT_BOUNDING_BOX0 | VARYING_BIT_BOUNDING_BOX1);
39
40 s->info.outputs_written = s->info.inputs_read = outputs;
41 s->info.clip_distance_array_size = key->clip_distance_array_size;
42 s->info.cull_distance_array_size = key->cull_distance_array_size;
43 s->info.stage = MESA_SHADER_GEOMETRY;
44 s->info.gs.input_primitive = key->prim;
45 s->info.gs.output_primitive = out;
46 s->info.gs.vertices_in = mesa_vertices_per_prim(key->prim);
47 s->info.gs.vertices_out = mesa_vertices_per_prim(out);
48 s->info.gs.invocations = 1;
49 s->info.gs.active_stream_mask = 1;
50
51 if (key->xfb_info.output_count) {
52 size_t size = nir_xfb_info_size(key->xfb_info.output_count);
53 s->xfb_info = ralloc_memdup(s, &key->xfb_info, size);
54 s->info.has_transform_feedback_varyings = true;
55 memcpy(s->info.xfb_stride, key->xfb_stride, sizeof(key->xfb_stride));
56 }
57
58 unsigned int start_vert = key->prim == MESA_PRIM_LINES_ADJACENCY ? 1 : 0;
59 unsigned int step = key->prim == MESA_PRIM_TRIANGLES_ADJACENCY ? 2 : 1;
60
61 nir_def *zero = nir_imm_int(b, 0);
62 nir_def *one = nir_imm_int(b, 1);
63
64 for (unsigned i = 0; i < s->info.gs.vertices_out; ++i) {
65 nir_def *vertex = nir_imm_int(b, start_vert + (i * step));
66
67 /* Copy inputs to outputs. */
68 u_foreach_bit64(loc, outputs) {
69 unsigned adjusted_loc = loc;
70 nir_def *offset = zero;
71 unsigned num_slots = 1;
72
73 bool scalar = loc == VARYING_SLOT_LAYER ||
74 loc == VARYING_SLOT_VIEW_INDEX ||
75 loc == VARYING_SLOT_VIEWPORT || loc == VARYING_SLOT_PSIZ;
76 unsigned comps = scalar ? 1 : 4;
77
78 /* We use combined, compact clip/cull */
79 if (loc == VARYING_SLOT_CLIP_DIST1 || loc == VARYING_SLOT_CULL_DIST1) {
80 adjusted_loc--;
81 offset = one;
82 }
83
84 if (adjusted_loc == VARYING_SLOT_CLIP_DIST0 ||
85 adjusted_loc == VARYING_SLOT_CULL_DIST0) {
86 num_slots =
87 key->cull_distance_array_size + key->clip_distance_array_size;
88
89 if (loc > adjusted_loc)
90 comps = num_slots - 4;
91 else
92 comps = MIN2(num_slots, 4);
93 }
94
95 nir_io_semantics sem = {
96 .location = adjusted_loc,
97 .num_slots = num_slots,
98 };
99
100 nir_def *val = nir_load_per_vertex_input(b, comps, 32, vertex, offset,
101 .io_semantics = sem);
102
103 for (unsigned c = 0; c < comps; ++c) {
104 nir_store_output(b, nir_channel(b, val, c), offset,
105 .io_semantics = sem, .src_type = nir_type_uint32,
106 .component = c);
107 }
108 }
109
110 nir_emit_vertex(b, 0);
111 }
112 }
113