1 /*
2 * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
3 * The term “Broadcom” refers to Broadcom Inc.
4 * and/or its subsidiaries.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "draw/draw_vbuf.h"
9 #include "draw/draw_context.h"
10 #include "draw/draw_vertex.h"
11
12 #include "util/u_debug.h"
13 #include "util/u_inlines.h"
14 #include "util/u_math.h"
15 #include "util/u_memory.h"
16
17 #include "svga_context.h"
18 #include "svga_state.h"
19 #include "svga_swtnl.h"
20
21 #include "svga_reg.h"
22 #include "svga3d_reg.h"
23 #include "svga_draw.h"
24 #include "svga_shader.h"
25 #include "svga_swtnl_private.h"
26
27
28 static const struct vertex_info *
svga_vbuf_render_get_vertex_info(struct vbuf_render * render)29 svga_vbuf_render_get_vertex_info(struct vbuf_render *render)
30 {
31 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
32 struct svga_context *svga = svga_render->svga;
33
34 svga_swtnl_update_vdecl(svga);
35
36 return &svga_render->vertex_info;
37 }
38
39
40 static bool
svga_vbuf_render_allocate_vertices(struct vbuf_render * render,uint16_t vertex_size,uint16_t nr_vertices)41 svga_vbuf_render_allocate_vertices(struct vbuf_render *render,
42 uint16_t vertex_size,
43 uint16_t nr_vertices)
44 {
45 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
46 struct svga_context *svga = svga_render->svga;
47 struct pipe_screen *screen = svga->pipe.screen;
48 size_t size = (size_t)nr_vertices * (size_t)vertex_size;
49 bool new_vbuf = false;
50 bool new_ibuf = false;
51
52 SVGA_STATS_TIME_PUSH(svga_sws(svga),
53 SVGA_STATS_TIME_VBUFRENDERALLOCVERT);
54
55 if (svga_render->vertex_size != vertex_size)
56 svga->swtnl.new_vdecl = true;
57 svga_render->vertex_size = (size_t)vertex_size;
58
59 if (svga->swtnl.new_vbuf)
60 new_ibuf = new_vbuf = true;
61 svga->swtnl.new_vbuf = false;
62
63 if (svga_render->vbuf_size
64 < svga_render->vbuf_offset + svga_render->vbuf_used + size)
65 new_vbuf = true;
66
67 if (new_vbuf)
68 pipe_resource_reference(&svga_render->vbuf, NULL);
69 if (new_ibuf)
70 pipe_resource_reference(&svga_render->ibuf, NULL);
71
72 if (!svga_render->vbuf) {
73 svga_render->vbuf_size = MAX2(size, svga_render->vbuf_alloc_size);
74 svga_render->vbuf = SVGA_TRY_PTR(pipe_buffer_create
75 (screen, PIPE_BIND_VERTEX_BUFFER,
76 PIPE_USAGE_STREAM,
77 svga_render->vbuf_size));
78 if (!svga_render->vbuf) {
79 svga_retry_enter(svga);
80 svga_context_flush(svga, NULL);
81 assert(!svga_render->vbuf);
82 svga_render->vbuf = pipe_buffer_create(screen,
83 PIPE_BIND_VERTEX_BUFFER,
84 PIPE_USAGE_STREAM,
85 svga_render->vbuf_size);
86 /* The buffer allocation may fail if we run out of memory.
87 * The draw module's vbuf code should handle that without crashing.
88 */
89 svga_retry_exit(svga);
90 }
91
92 svga->swtnl.new_vdecl = true;
93 svga_render->vbuf_offset = 0;
94 } else {
95 svga_render->vbuf_offset += svga_render->vbuf_used;
96 }
97
98 svga_render->vbuf_used = 0;
99
100 if (svga->swtnl.new_vdecl)
101 svga_render->vdecl_offset = svga_render->vbuf_offset;
102
103 SVGA_STATS_TIME_POP(svga_sws(svga));
104
105 return true;
106 }
107
108
109 static void *
svga_vbuf_render_map_vertices(struct vbuf_render * render)110 svga_vbuf_render_map_vertices(struct vbuf_render *render)
111 {
112 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
113 struct svga_context *svga = svga_render->svga;
114 void * retPtr = NULL;
115
116 SVGA_STATS_TIME_PUSH(svga_sws(svga),
117 SVGA_STATS_TIME_VBUFRENDERMAPVERT);
118
119 if (svga_render->vbuf) {
120 char *ptr = (char*)pipe_buffer_map(&svga->pipe,
121 svga_render->vbuf,
122 PIPE_MAP_WRITE |
123 PIPE_MAP_FLUSH_EXPLICIT |
124 PIPE_MAP_DISCARD_RANGE |
125 PIPE_MAP_UNSYNCHRONIZED,
126 &svga_render->vbuf_transfer);
127 if (ptr) {
128 svga_render->vbuf_ptr = ptr;
129 retPtr = ptr + svga_render->vbuf_offset;
130 }
131 else {
132 svga_render->vbuf_ptr = NULL;
133 svga_render->vbuf_transfer = NULL;
134 retPtr = NULL;
135 }
136 }
137 else {
138 /* we probably ran out of memory when allocating the vertex buffer */
139 retPtr = NULL;
140 }
141
142 SVGA_STATS_TIME_POP(svga_sws(svga));
143 return retPtr;
144 }
145
146
147 static void
svga_vbuf_render_unmap_vertices(struct vbuf_render * render,uint16_t min_index,uint16_t max_index)148 svga_vbuf_render_unmap_vertices(struct vbuf_render *render,
149 uint16_t min_index,
150 uint16_t max_index)
151 {
152 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
153 struct svga_context *svga = svga_render->svga;
154 unsigned offset, length;
155 size_t used = svga_render->vertex_size * ((size_t)max_index + 1);
156
157 SVGA_STATS_TIME_PUSH(svga_sws(svga),
158 SVGA_STATS_TIME_VBUFRENDERUNMAPVERT);
159
160 offset = svga_render->vbuf_offset + svga_render->vertex_size * min_index;
161 length = svga_render->vertex_size * (max_index + 1 - min_index);
162
163 if (0) {
164 /* dump vertex data */
165 const float *f = (const float *) ((char *) svga_render->vbuf_ptr +
166 svga_render->vbuf_offset);
167 unsigned i;
168 debug_printf("swtnl vertex data:\n");
169 for (i = 0; i < length / 4; i += 4) {
170 debug_printf("%u: %f %f %f %f\n", i, f[i], f[i+1], f[i+2], f[i+3]);
171 }
172 }
173
174 pipe_buffer_flush_mapped_range(&svga->pipe,
175 svga_render->vbuf_transfer,
176 offset, length);
177 pipe_buffer_unmap(&svga->pipe, svga_render->vbuf_transfer);
178 svga_render->min_index = min_index;
179 svga_render->max_index = max_index;
180 svga_render->vbuf_used = MAX2(svga_render->vbuf_used, used);
181
182 SVGA_STATS_TIME_POP(svga_sws(svga));
183 }
184
185
186 static void
svga_vbuf_render_set_primitive(struct vbuf_render * render,enum mesa_prim prim)187 svga_vbuf_render_set_primitive(struct vbuf_render *render,
188 enum mesa_prim prim)
189 {
190 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
191 svga_render->prim = prim;
192 }
193
194
195 static void
svga_vbuf_submit_state(struct svga_vbuf_render * svga_render)196 svga_vbuf_submit_state(struct svga_vbuf_render *svga_render)
197 {
198 struct svga_context *svga = svga_render->svga;
199 SVGA3dVertexDecl vdecl[PIPE_MAX_ATTRIBS];
200 unsigned i;
201 static const unsigned zero[PIPE_MAX_ATTRIBS] = {0};
202 bool retried;
203
204 /* if the vdecl or vbuf hasn't changed do nothing */
205 if (!svga->swtnl.new_vdecl)
206 return;
207
208 SVGA_STATS_TIME_PUSH(svga_sws(svga),
209 SVGA_STATS_TIME_VBUFSUBMITSTATE);
210
211 memcpy(vdecl, svga_render->vdecl, sizeof(vdecl));
212
213 /* flush the hw state */
214 SVGA_RETRY_CHECK(svga, svga_hwtnl_flush(svga->hwtnl), retried);
215 if (retried) {
216 /* if we hit this path we might become synced with hw */
217 svga->swtnl.new_vbuf = true;
218 }
219
220 for (i = 0; i < svga_render->vdecl_count; i++) {
221 vdecl[i].array.offset += svga_render->vdecl_offset;
222 }
223
224 svga_hwtnl_vertex_decls(svga->hwtnl,
225 svga_render->vdecl_count,
226 vdecl,
227 zero,
228 svga_render->layout_id);
229
230 /* Specify the vertex buffer (there's only ever one) */
231 {
232 struct pipe_vertex_buffer vb;
233 vb.is_user_buffer = false;
234 vb.buffer.resource = svga_render->vbuf;
235 vb.buffer_offset = svga_render->vdecl_offset;
236 svga_hwtnl_vertex_buffers(svga->hwtnl, 1, &vb);
237 }
238
239 /* We have already taken care of flatshading, so let the hwtnl
240 * module use whatever is most convenient:
241 */
242 if (svga->state.sw.need_pipeline) {
243 svga_hwtnl_set_flatshade(svga->hwtnl, false, false);
244 svga_hwtnl_set_fillmode(svga->hwtnl, PIPE_POLYGON_MODE_FILL);
245 }
246 else {
247 svga_hwtnl_set_flatshade(svga->hwtnl,
248 svga->curr.rast->templ.flatshade ||
249 svga_is_using_flat_shading(svga),
250 svga->curr.rast->templ.flatshade_first);
251
252 svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
253 }
254
255 svga->swtnl.new_vdecl = false;
256 SVGA_STATS_TIME_POP(svga_sws(svga));
257 }
258
259
260 static void
svga_vbuf_render_draw_arrays(struct vbuf_render * render,unsigned start,uint nr)261 svga_vbuf_render_draw_arrays(struct vbuf_render *render,
262 unsigned start, uint nr)
263 {
264 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
265 struct svga_context *svga = svga_render->svga;
266 unsigned bias = (svga_render->vbuf_offset - svga_render->vdecl_offset)
267 / svga_render->vertex_size;
268 /* instancing will already have been resolved at this point by 'draw' */
269 const unsigned start_instance = 0;
270 const unsigned instance_count = 1;
271 bool retried;
272
273 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_VBUFDRAWARRAYS);
274
275 /* off to hardware */
276 svga_vbuf_submit_state(svga_render);
277
278 /* Need to call update_state() again as the draw module may have
279 * altered some of our state behind our backs. Testcase:
280 * redbook/polys.c
281 */
282 svga_update_state_retry(svga, SVGA_STATE_HW_DRAW);
283 SVGA_RETRY_CHECK(svga, svga_hwtnl_draw_arrays
284 (svga->hwtnl, svga_render->prim, start + bias,
285 nr, start_instance, instance_count, 0), retried);
286 if (retried) {
287 svga->swtnl.new_vbuf = true;
288 }
289
290 SVGA_STATS_TIME_POP(svga_sws(svga));
291 }
292
293
294 static void
svga_vbuf_render_draw_elements(struct vbuf_render * render,const uint16_t * indices,uint nr_indices)295 svga_vbuf_render_draw_elements(struct vbuf_render *render,
296 const uint16_t *indices,
297 uint nr_indices)
298 {
299 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
300 struct svga_context *svga = svga_render->svga;
301 int bias = (svga_render->vbuf_offset - svga_render->vdecl_offset)
302 / svga_render->vertex_size;
303 bool retried;
304 /* instancing will already have been resolved at this point by 'draw' */
305 const struct pipe_draw_info info = {
306 .index_size = 2,
307 .mode = svga_render->prim,
308 .has_user_indices = 1,
309 .index.user = indices,
310 .start_instance = 0,
311 .instance_count = 1,
312 .index_bounds_valid = true,
313 .min_index = svga_render->min_index,
314 .max_index = svga_render->max_index,
315 };
316 const struct pipe_draw_start_count_bias draw = {
317 .start = 0,
318 .count = nr_indices,
319 .index_bias = bias,
320 };
321
322 assert((svga_render->vbuf_offset - svga_render->vdecl_offset)
323 % svga_render->vertex_size == 0);
324
325 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_VBUFDRAWELEMENTS);
326
327 /* off to hardware */
328 svga_vbuf_submit_state(svga_render);
329
330 /* Need to call update_state() again as the draw module may have
331 * altered some of our state behind our backs. Testcase:
332 * redbook/polys.c
333 */
334 svga_update_state_retry(svga, SVGA_STATE_HW_DRAW);
335 SVGA_RETRY_CHECK(svga, svga_hwtnl_draw_range_elements(svga->hwtnl, &info,
336 &draw,
337 nr_indices), retried);
338 if (retried) {
339 svga->swtnl.new_vbuf = true;
340 }
341
342 SVGA_STATS_TIME_POP(svga_sws(svga));
343 }
344
345
346 static void
svga_vbuf_render_release_vertices(struct vbuf_render * render)347 svga_vbuf_render_release_vertices(struct vbuf_render *render)
348 {
349
350 }
351
352
353 static void
svga_vbuf_render_destroy(struct vbuf_render * render)354 svga_vbuf_render_destroy(struct vbuf_render *render)
355 {
356 struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
357
358 pipe_resource_reference(&svga_render->vbuf, NULL);
359 pipe_resource_reference(&svga_render->ibuf, NULL);
360 FREE(svga_render);
361 }
362
363
364 /**
365 * Create a new primitive render.
366 */
367 struct vbuf_render *
svga_vbuf_render_create(struct svga_context * svga)368 svga_vbuf_render_create(struct svga_context *svga)
369 {
370 struct svga_vbuf_render *svga_render = CALLOC_STRUCT(svga_vbuf_render);
371
372 svga_render->svga = svga;
373 svga_render->ibuf_size = 0;
374 svga_render->vbuf_size = 0;
375 svga_render->ibuf_alloc_size = 4*1024;
376 svga_render->vbuf_alloc_size = 64*1024;
377 svga_render->layout_id = SVGA3D_INVALID_ID;
378 svga_render->base.max_vertex_buffer_bytes = 64*1024/10;
379 svga_render->base.max_indices = 65536;
380 svga_render->base.get_vertex_info = svga_vbuf_render_get_vertex_info;
381 svga_render->base.allocate_vertices = svga_vbuf_render_allocate_vertices;
382 svga_render->base.map_vertices = svga_vbuf_render_map_vertices;
383 svga_render->base.unmap_vertices = svga_vbuf_render_unmap_vertices;
384 svga_render->base.set_primitive = svga_vbuf_render_set_primitive;
385 svga_render->base.draw_elements = svga_vbuf_render_draw_elements;
386 svga_render->base.draw_arrays = svga_vbuf_render_draw_arrays;
387 svga_render->base.release_vertices = svga_vbuf_render_release_vertices;
388 svga_render->base.destroy = svga_vbuf_render_destroy;
389
390 return &svga_render->base;
391 }
392