xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/svga/svga_draw_arrays.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 "svga_cmd.h"
9 
10 #include "indices/u_indices.h"
11 #include "util/u_inlines.h"
12 #include "util/u_prim.h"
13 
14 #include "svga_hw_reg.h"
15 #include "svga_draw.h"
16 #include "svga_draw_private.h"
17 #include "svga_context.h"
18 #include "svga_shader.h"
19 
20 
21 #define DBG 0
22 
23 
24 static enum pipe_error
generate_indices(struct svga_hwtnl * hwtnl,unsigned nr,unsigned index_size,u_generate_func generate,struct pipe_resource ** out_buf)25 generate_indices(struct svga_hwtnl *hwtnl,
26                  unsigned nr,
27                  unsigned index_size,
28                  u_generate_func generate, struct pipe_resource **out_buf)
29 {
30    struct pipe_context *pipe = &hwtnl->svga->pipe;
31    struct pipe_transfer *transfer;
32    unsigned size = index_size * nr;
33    struct pipe_resource *dst = NULL;
34    void *dst_map = NULL;
35 
36    dst = pipe_buffer_create(pipe->screen, PIPE_BIND_INDEX_BUFFER,
37                             PIPE_USAGE_IMMUTABLE, size);
38    if (!dst)
39       goto fail;
40 
41    dst_map = pipe_buffer_map(pipe, dst, PIPE_MAP_WRITE, &transfer);
42    if (!dst_map)
43       goto fail;
44 
45    generate(0, nr, dst_map);
46 
47    pipe_buffer_unmap(pipe, transfer);
48 
49    *out_buf = dst;
50    return PIPE_OK;
51 
52 fail:
53    if (dst_map)
54       pipe_buffer_unmap(pipe, transfer);
55 
56    if (dst)
57       pipe->screen->resource_destroy(pipe->screen, dst);
58 
59    return PIPE_ERROR_OUT_OF_MEMORY;
60 }
61 
62 
63 static bool
compare(unsigned cached_nr,unsigned nr,unsigned type)64 compare(unsigned cached_nr, unsigned nr, unsigned type)
65 {
66    if (type == U_GENERATE_REUSABLE)
67       return cached_nr >= nr;
68    else
69       return cached_nr == nr;
70 }
71 
72 
73 static enum pipe_error
retrieve_or_generate_indices(struct svga_hwtnl * hwtnl,enum mesa_prim prim,unsigned gen_type,unsigned gen_nr,unsigned gen_size,u_generate_func generate,struct pipe_resource ** out_buf)74 retrieve_or_generate_indices(struct svga_hwtnl *hwtnl,
75                              enum mesa_prim prim,
76                              unsigned gen_type,
77                              unsigned gen_nr,
78                              unsigned gen_size,
79                              u_generate_func generate,
80                              struct pipe_resource **out_buf)
81 {
82    enum pipe_error ret = PIPE_OK;
83    int i;
84 
85    SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_GENERATEINDICES);
86 
87    for (i = 0; i < IDX_CACHE_MAX; i++) {
88       if (hwtnl->index_cache[prim][i].buffer != NULL &&
89           hwtnl->index_cache[prim][i].generate == generate) {
90          if (compare(hwtnl->index_cache[prim][i].gen_nr, gen_nr, gen_type)) {
91             pipe_resource_reference(out_buf,
92                                     hwtnl->index_cache[prim][i].buffer);
93 
94             if (DBG)
95                debug_printf("%s retrieve %d/%d\n", __func__, i, gen_nr);
96 
97             goto done;
98          }
99          else if (gen_type == U_GENERATE_REUSABLE) {
100             pipe_resource_reference(&hwtnl->index_cache[prim][i].buffer,
101                                     NULL);
102 
103             if (DBG)
104                debug_printf("%s discard %d/%d\n", __func__,
105                             i, hwtnl->index_cache[prim][i].gen_nr);
106 
107             break;
108          }
109       }
110    }
111 
112    if (i == IDX_CACHE_MAX) {
113       unsigned smallest = 0;
114       unsigned smallest_size = ~0;
115 
116       for (i = 0; i < IDX_CACHE_MAX && smallest_size; i++) {
117          if (hwtnl->index_cache[prim][i].buffer == NULL) {
118             smallest = i;
119             smallest_size = 0;
120          }
121          else if (hwtnl->index_cache[prim][i].gen_nr < smallest) {
122             smallest = i;
123             smallest_size = hwtnl->index_cache[prim][i].gen_nr;
124          }
125       }
126 
127       assert(smallest != IDX_CACHE_MAX);
128 
129       pipe_resource_reference(&hwtnl->index_cache[prim][smallest].buffer,
130                               NULL);
131 
132       if (DBG)
133          debug_printf("%s discard smallest %d/%d\n", __func__,
134                       smallest, smallest_size);
135 
136       i = smallest;
137    }
138 
139    ret = generate_indices(hwtnl, gen_nr, gen_size, generate, out_buf);
140    if (ret != PIPE_OK)
141       goto done;
142 
143    hwtnl->index_cache[prim][i].generate = generate;
144    hwtnl->index_cache[prim][i].gen_nr = gen_nr;
145    pipe_resource_reference(&hwtnl->index_cache[prim][i].buffer, *out_buf);
146 
147    if (DBG)
148       debug_printf("%s cache %d/%d\n", __func__,
149                    i, hwtnl->index_cache[prim][i].gen_nr);
150 
151 done:
152    SVGA_STATS_TIME_POP(svga_sws(hwtnl->svga));
153    return ret;
154 }
155 
156 
157 static enum pipe_error
simple_draw_arrays(struct svga_hwtnl * hwtnl,enum mesa_prim prim,unsigned start,unsigned count,unsigned start_instance,unsigned instance_count,uint8_t vertices_per_patch)158 simple_draw_arrays(struct svga_hwtnl *hwtnl,
159                    enum mesa_prim prim, unsigned start, unsigned count,
160                    unsigned start_instance, unsigned instance_count,
161                    uint8_t vertices_per_patch)
162 {
163    SVGA3dPrimitiveRange range;
164    unsigned hw_prim;
165    unsigned hw_count;
166 
167    hw_prim = svga_translate_prim(prim, count, &hw_count, vertices_per_patch);
168    if (hw_count == 0)
169       return PIPE_ERROR_BAD_INPUT;
170 
171    range.primType = hw_prim;
172    range.primitiveCount = hw_count;
173    range.indexArray.surfaceId = SVGA3D_INVALID_ID;
174    range.indexArray.offset = 0;
175    range.indexArray.stride = 0;
176    range.indexWidth = 0;
177    range.indexBias = start;
178 
179    /* Min/max index should be calculated prior to applying bias, so we
180     * end up with min_index = 0, max_index = count - 1 and everybody
181     * looking at those numbers knows to adjust them by
182     * range.indexBias.
183     */
184    return svga_hwtnl_prim(hwtnl, &range, count,
185                           0, count - 1, NULL,
186                           start_instance, instance_count,
187                           NULL, NULL);
188 }
189 
190 
191 enum pipe_error
svga_hwtnl_draw_arrays(struct svga_hwtnl * hwtnl,enum mesa_prim prim,unsigned start,unsigned count,unsigned start_instance,unsigned instance_count,uint8_t vertices_per_patch)192 svga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl,
193                        enum mesa_prim prim, unsigned start, unsigned count,
194                        unsigned start_instance, unsigned instance_count,
195                        uint8_t vertices_per_patch)
196 {
197    enum mesa_prim gen_prim;
198    unsigned gen_size, gen_nr;
199    enum indices_mode gen_type;
200    u_generate_func gen_func;
201    enum pipe_error ret = PIPE_OK;
202    unsigned api_pv = hwtnl->api_pv;
203    struct svga_context *svga = hwtnl->svga;
204 
205    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_HWTNLDRAWARRAYS);
206 
207    if (svga->curr.rast->templ.fill_front !=
208        svga->curr.rast->templ.fill_back) {
209       assert(hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL);
210    }
211 
212    if (svga->curr.rast->templ.flatshade &&
213          svga_fs_variant(svga->state.hw_draw.fs)->constant_color_output) {
214       /* The fragment color is a constant, not per-vertex so the whole
215        * primitive will be the same color (except for possible blending).
216        * We can ignore the current provoking vertex state and use whatever
217        * the hardware wants.
218        */
219       api_pv = hwtnl->hw_pv;
220 
221       if (hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL) {
222          /* Do some simple primitive conversions to avoid index buffer
223           * generation below.  Note that polygons and quads are not directly
224           * supported by the svga device.  Also note, we can only do this
225           * for flat/constant-colored rendering because of provoking vertex.
226           */
227          if (prim == MESA_PRIM_POLYGON) {
228             prim = MESA_PRIM_TRIANGLE_FAN;
229          }
230          else if (prim == MESA_PRIM_QUADS && count == 4) {
231             prim = MESA_PRIM_TRIANGLE_FAN;
232          }
233       }
234    }
235 
236    if (svga_need_unfilled_fallback(hwtnl, prim)) {
237       /* Convert unfilled polygons into points, lines, triangles */
238       gen_type = u_unfilled_generator(prim,
239                                       start,
240                                       count,
241                                       hwtnl->api_fillmode,
242                                       &gen_prim,
243                                       &gen_size, &gen_nr, &gen_func);
244    }
245    else {
246       /* Convert MESA_PRIM_LINE_LOOP to MESA_PRIM_LINESTRIP,
247        * convert MESA_PRIM_POLYGON to MESA_PRIM_TRIANGLE_FAN,
248        * etc, if needed (as determined by svga_hw_prims mask).
249        */
250       gen_type = u_index_generator(svga_hw_prims,
251                                    prim,
252                                    start,
253                                    count,
254                                    api_pv,
255                                    hwtnl->hw_pv,
256                                    &gen_prim, &gen_size, &gen_nr, &gen_func);
257    }
258 
259    if (gen_type == U_GENERATE_LINEAR) {
260       ret = simple_draw_arrays(hwtnl, gen_prim, start, count,
261                                start_instance, instance_count,
262                                vertices_per_patch);
263    }
264    else {
265       struct pipe_resource *gen_buf = NULL;
266 
267       /* Need to draw as indexed primitive.
268        * Potentially need to run the gen func to build an index buffer.
269        */
270       ret = retrieve_or_generate_indices(hwtnl,
271                                          prim,
272                                          gen_type,
273                                          gen_nr,
274                                          gen_size, gen_func, &gen_buf);
275       if (ret == PIPE_OK) {
276          util_debug_message(&svga->debug.callback, PERF_INFO,
277                             "generating temporary index buffer for drawing %s",
278                             u_prim_name(prim));
279 
280          ret = svga_hwtnl_simple_draw_range_elements(hwtnl,
281                                                      gen_buf,
282                                                      gen_size,
283                                                      start,
284                                                      0,
285                                                      count - 1,
286                                                      gen_prim, 0, gen_nr,
287                                                      start_instance,
288                                                      instance_count,
289                                                      vertices_per_patch);
290       }
291 
292       if (gen_buf) {
293          pipe_resource_reference(&gen_buf, NULL);
294       }
295    }
296 
297    SVGA_STATS_TIME_POP(svga_sws(svga));
298    return ret;
299 }
300