1 /**************************************************************************
2 *
3 * Copyright 2023 Red Hat.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 **************************************************************************/
25
26 /*
27 * Mesh primitive assembler
28 *
29 * This takes vertex and per-primitive data, and assembles a linear set
30 * of draw compatible vertices.
31 */
32 #include "draw_mesh_prim.h"
33
34 #include "draw/draw_context.h"
35 #include "draw/draw_private.h"
36 #include "util/u_debug.h"
37 #include "util/u_memory.h"
38
39 #include "pipe/p_defines.h"
40
41 struct draw_mesh_prim
42 {
43 struct draw_context *draw;
44
45 struct draw_prim_info *output_prims;
46 struct draw_vertex_info *output_verts;
47
48 const struct draw_prim_info *input_prims;
49 const struct draw_vertex_info *input_verts;
50
51 unsigned num_prims;
52 const char *per_prim;
53 uint32_t num_per_prim;
54 uint32_t added_prim_size;
55 int cull_prim_idx;
56 };
57
58 static void
add_prim(struct draw_mesh_prim * asmblr,unsigned length)59 add_prim(struct draw_mesh_prim *asmblr, unsigned length)
60 {
61 struct draw_prim_info *output_prims = asmblr->output_prims;
62
63 output_prims->primitive_lengths = realloc(output_prims->primitive_lengths, sizeof(unsigned) * (output_prims->primitive_count + 1));
64 output_prims->primitive_lengths[output_prims->primitive_count] = length;
65 output_prims->primitive_count++;
66 }
67
68
69 /*
70 * Copy the vertex header along with its data from the current
71 * vertex buffer into a buffer holding vertices arranged
72 * into decomposed primitives (i.e. buffer without the
73 * adjacency vertices)
74 */
75 static void
copy_verts(struct draw_mesh_prim * asmblr,unsigned * indices,unsigned num_indices)76 copy_verts(struct draw_mesh_prim *asmblr,
77 unsigned *indices, unsigned num_indices)
78 {
79 char *output = (char*)asmblr->output_verts->verts;
80 const char *input = (const char*)asmblr->input_verts->verts;
81
82 for (unsigned i = 0; i < num_indices; ++i) {
83 unsigned idx = indices[i];
84 unsigned output_offset =
85 asmblr->output_verts->count * asmblr->output_verts->stride;
86 unsigned input_offset = asmblr->input_verts->stride * idx;
87 memcpy(output + output_offset, input + input_offset,
88 asmblr->input_verts->vertex_size);
89
90 memcpy(output + output_offset + asmblr->input_verts->vertex_size,
91 asmblr->per_prim + (asmblr->num_prims * asmblr->added_prim_size * 8),
92 asmblr->added_prim_size);
93 asmblr->output_verts->count += 1;
94 }
95 ++asmblr->num_prims;
96 }
97
98 static bool
cull_prim(struct draw_mesh_prim * asmblr)99 cull_prim(struct draw_mesh_prim *asmblr)
100 {
101 if (asmblr->cull_prim_idx == -1)
102 return false;
103
104 const uint32_t *cull_prim_ptr = (uint32_t *)(asmblr->per_prim + (asmblr->num_prims * asmblr->added_prim_size * 8));
105 cull_prim_ptr += (asmblr->cull_prim_idx * 4);
106
107 return (*cull_prim_ptr) ? true : false;
108 }
109
110
111 static void
prim_point(struct draw_mesh_prim * asmblr,unsigned idx)112 prim_point(struct draw_mesh_prim *asmblr,
113 unsigned idx)
114 {
115 unsigned indices[1];
116
117 indices[0] = idx;
118
119 if (cull_prim(asmblr)) {
120 ++asmblr->num_prims;
121 return;
122 }
123 add_prim(asmblr, 1);
124 copy_verts(asmblr, indices, 1);
125 }
126
127
128 static void
prim_line(struct draw_mesh_prim * asmblr,unsigned i0,unsigned i1)129 prim_line(struct draw_mesh_prim *asmblr,
130 unsigned i0, unsigned i1)
131 {
132 unsigned indices[2];
133
134 indices[0] = i0;
135 indices[1] = i1;
136
137 if (cull_prim(asmblr)) {
138 ++asmblr->num_prims;
139 return;
140 }
141 add_prim(asmblr, 2);
142 copy_verts(asmblr, indices, 2);
143 }
144
145
146 static void
prim_tri(struct draw_mesh_prim * asmblr,unsigned i0,unsigned i1,unsigned i2)147 prim_tri(struct draw_mesh_prim *asmblr,
148 unsigned i0, unsigned i1, unsigned i2)
149 {
150 unsigned indices[3];
151
152 indices[0] = i0;
153 indices[1] = i1;
154 indices[2] = i2;
155
156 if (cull_prim(asmblr)) {
157 ++asmblr->num_prims;
158 return;
159 }
160 add_prim(asmblr, 3);
161 copy_verts(asmblr, indices, 3);
162 }
163
164
165 #define FUNC assembler_run_linear
166 #define GET_ELT(idx) (start + (idx))
167 #include "draw_mesh_prim_tmp.h"
168
169 #define FUNC assembler_run_elts
170 #define LOCAL_VARS const uint16_t *elts = input_prims->elts;
171 #define GET_ELT(idx) (elts[start + (idx)])
172 #include "draw_mesh_prim_tmp.h"
173
174
175 void
draw_mesh_prim_run(struct draw_context * draw,unsigned num_per_prim_inputs,void * per_prim_inputs,int cull_prim_idx,const struct draw_prim_info * input_prims,const struct draw_vertex_info * input_verts,struct draw_prim_info * output_prims,struct draw_vertex_info * output_verts)176 draw_mesh_prim_run(struct draw_context *draw,
177 unsigned num_per_prim_inputs,
178 void *per_prim_inputs,
179 int cull_prim_idx,
180 const struct draw_prim_info *input_prims,
181 const struct draw_vertex_info *input_verts,
182 struct draw_prim_info *output_prims,
183 struct draw_vertex_info *output_verts)
184 {
185 struct draw_mesh_prim asmblr_mesh;
186 struct draw_mesh_prim *asmblr = &asmblr_mesh;
187 unsigned start, i;
188 unsigned max_primitives = input_prims->primitive_count;
189 unsigned max_verts = mesa_vertices_per_prim(input_prims->prim) * max_primitives;
190
191 asmblr->output_prims = output_prims;
192 asmblr->output_verts = output_verts;
193 asmblr->input_prims = input_prims;
194 asmblr->input_verts = input_verts;
195 asmblr->num_prims = 0;
196 asmblr->num_per_prim = num_per_prim_inputs;
197 asmblr->per_prim = per_prim_inputs;
198 asmblr->cull_prim_idx = cull_prim_idx;
199
200 output_prims->linear = true;
201 output_prims->elts = NULL;
202 output_prims->start = 0;
203 output_prims->prim = input_prims->prim;
204 output_prims->flags = 0x0;
205 output_prims->primitive_lengths = MALLOC(sizeof(unsigned));
206 output_prims->primitive_lengths[0] = 0;
207 output_prims->primitive_count = 0;
208
209 asmblr->added_prim_size = asmblr->num_per_prim * (4 * sizeof(float));
210 output_verts->vertex_size = input_verts->vertex_size + asmblr->added_prim_size;
211 output_verts->stride = output_verts->vertex_size;
212 output_verts->verts = (struct vertex_header*)MALLOC(
213 output_verts->vertex_size * max_verts);
214 output_verts->count = 0;
215
216 for (start = i = 0; i < input_prims->primitive_count;
217 start += input_prims->primitive_lengths[i], i++) {
218 unsigned count = input_prims->primitive_lengths[i];
219 if (input_prims->linear) {
220 assembler_run_linear(asmblr, input_prims, input_verts,
221 start, count);
222 } else {
223 assembler_run_elts(asmblr, input_prims, input_verts,
224 start, count);
225 }
226 }
227
228 output_prims->count = output_verts->count;
229 }
230