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