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