xref: /aosp_15_r20/external/mesa3d/src/mesa/state_tracker/st_draw.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
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
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 /*
29  * This file implements the st_draw_vbo() function which is called from
30  * Mesa's VBO module.  All point/line/triangle rendering is done through
31  * this function whether the user called glBegin/End, glDrawArrays,
32  * glDrawElements, glEvalMesh, or glCalList, etc.
33  *
34  * Authors:
35  *   Keith Whitwell <[email protected]>
36  */
37 
38 #include "main/context.h"
39 #include "main/errors.h"
40 
41 #include "main/image.h"
42 #include "main/bufferobj.h"
43 #include "main/macros.h"
44 #include "main/varray.h"
45 
46 #include "compiler/glsl/ir_uniform.h"
47 
48 #include "vbo/vbo.h"
49 
50 #include "st_context.h"
51 #include "st_atom.h"
52 #include "st_cb_bitmap.h"
53 #include "st_debug.h"
54 #include "st_draw.h"
55 #include "st_program.h"
56 #include "st_util.h"
57 
58 #include "pipe/p_context.h"
59 #include "pipe/p_defines.h"
60 #include "util/u_cpu_detect.h"
61 #include "util/u_inlines.h"
62 #include "util/format/u_format.h"
63 #include "util/u_prim.h"
64 #include "util/u_draw.h"
65 #include "util/u_upload_mgr.h"
66 #include "util/u_threaded_context.h"
67 #include "draw/draw_context.h"
68 #include "cso_cache/cso_context.h"
69 
70 /* GL prims should match Gallium prims, spot-check a few */
71 static_assert(GL_POINTS == MESA_PRIM_POINTS, "enum mismatch");
72 static_assert(GL_QUADS == MESA_PRIM_QUADS, "enum mismatch");
73 static_assert(GL_TRIANGLE_STRIP_ADJACENCY == MESA_PRIM_TRIANGLE_STRIP_ADJACENCY, "enum mismatch");
74 static_assert(GL_PATCHES == MESA_PRIM_PATCHES, "enum mismatch");
75 
76 void
st_prepare_draw(struct gl_context * ctx,uint64_t state_mask)77 st_prepare_draw(struct gl_context *ctx, uint64_t state_mask)
78 {
79    struct st_context *st = ctx->st;
80 
81    /* Mesa core state should have been validated already */
82    assert(ctx->NewState == 0x0);
83 
84    if (unlikely(!st->bitmap.cache.empty))
85       st_flush_bitmap_cache(st);
86 
87    st_invalidate_readpix_cache(st);
88 
89    /* Validate state. */
90    st_validate_state(st, state_mask);
91 
92    /* Apply our thread scheduling policy for better multithreading
93     * performance.
94     */
95    if (unlikely(st->pin_thread_counter != ST_THREAD_SCHEDULER_DISABLED &&
96                 /* do it occasionally */
97                 ++st->pin_thread_counter % 512 == 0)) {
98       st->pin_thread_counter = 0;
99 
100       int cpu = util_get_current_cpu();
101       if (cpu >= 0) {
102          struct pipe_context *pipe = st->pipe;
103          uint16_t L3_cache = util_get_cpu_caps()->cpu_to_L3[cpu];
104 
105          if (L3_cache != U_CPU_INVALID_L3) {
106             pipe->set_context_param(pipe,
107                                     PIPE_CONTEXT_PARAM_UPDATE_THREAD_SCHEDULING,
108                                     cpu);
109          }
110       }
111    }
112 }
113 
114 void
st_draw_gallium(struct gl_context * ctx,const struct pipe_draw_info * info,unsigned drawid_offset,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * draws,unsigned num_draws)115 st_draw_gallium(struct gl_context *ctx,
116                 const struct pipe_draw_info *info,
117                 unsigned drawid_offset,
118                 const struct pipe_draw_indirect_info *indirect,
119                 const struct pipe_draw_start_count_bias *draws,
120                 unsigned num_draws)
121 {
122    struct st_context *st = st_context(ctx);
123 
124    cso_draw_vbo(st->cso_context, info, drawid_offset, indirect, draws, num_draws);
125 }
126 
127 static void
st_draw_gallium_multimode(struct gl_context * ctx,struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draws,const unsigned char * mode,unsigned num_draws)128 st_draw_gallium_multimode(struct gl_context *ctx,
129                           struct pipe_draw_info *info,
130                           const struct pipe_draw_start_count_bias *draws,
131                           const unsigned char *mode,
132                           unsigned num_draws)
133 {
134    struct st_context *st = st_context(ctx);
135 
136    unsigned i, first;
137    struct cso_context *cso = st->cso_context;
138 
139    /* Find consecutive draws where mode doesn't vary. */
140    for (i = 0, first = 0; i <= num_draws; i++) {
141       if (i == num_draws || mode[i] != mode[first]) {
142          info->mode = mode[first];
143          cso_draw_vbo(cso, info, 0, NULL, &draws[first], i - first);
144          first = i;
145 
146          /* We can pass the reference only once. st_buffer_object keeps
147           * the reference alive for later draws.
148           */
149          info->take_index_buffer_ownership = false;
150       }
151    }
152 }
153 
154 static void
rewrite_partial_stride_indirect(struct st_context * st,const struct pipe_draw_info * info,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias draw)155 rewrite_partial_stride_indirect(struct st_context *st,
156                             const struct pipe_draw_info *info,
157                             const struct pipe_draw_indirect_info *indirect,
158                             const struct pipe_draw_start_count_bias draw)
159 {
160    unsigned draw_count = 0;
161    struct u_indirect_params *new_draws = util_draw_indirect_read(st->pipe, info, indirect, &draw_count);
162    if (!new_draws)
163       return;
164    for (unsigned i = 0; i < draw_count; i++)
165       st->ctx->Driver.DrawGallium(st->ctx, &new_draws[i].info, i, NULL, &new_draws[i].draw, 1);
166    free(new_draws);
167 }
168 
169 void
st_indirect_draw_vbo(struct gl_context * ctx,GLenum mode,GLenum index_type,GLintptr indirect_offset,GLintptr indirect_draw_count_offset,GLsizei draw_count,GLsizei stride)170 st_indirect_draw_vbo(struct gl_context *ctx,
171                      GLenum mode, GLenum index_type,
172                      GLintptr indirect_offset,
173                      GLintptr indirect_draw_count_offset,
174                      GLsizei draw_count, GLsizei stride)
175 {
176    struct gl_buffer_object *indirect_data = ctx->DrawIndirectBuffer;
177    struct gl_buffer_object *indirect_draw_count = ctx->ParameterBuffer;
178    struct st_context *st = st_context(ctx);
179    struct pipe_draw_info info;
180    struct pipe_draw_indirect_info indirect;
181    struct pipe_draw_start_count_bias draw = {0};
182 
183    /* If indirect_draw_count is set, drawcount is the maximum draw count.*/
184    if (!draw_count)
185       return;
186 
187    assert(stride);
188    st_prepare_draw(ctx, ST_PIPELINE_RENDER_STATE_MASK);
189 
190    memset(&indirect, 0, sizeof(indirect));
191    util_draw_init_info(&info);
192    info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
193 
194    switch (index_type) {
195    case GL_UNSIGNED_BYTE:
196       info.index_size = 1;
197       break;
198    case GL_UNSIGNED_SHORT:
199       info.index_size = 2;
200       break;
201    case GL_UNSIGNED_INT:
202       info.index_size = 4;
203       break;
204    }
205 
206    assert(st->has_multi_draw_indirect || !indirect_draw_count);
207 
208    if (info.index_size) {
209       struct gl_buffer_object *bufobj = ctx->Array.VAO->IndexBufferObj;
210 
211       /* indices are always in a real VBO */
212       assert(bufobj);
213 
214       if (st->pipe->draw_vbo == tc_draw_vbo &&
215           (draw_count == 1 || st->has_multi_draw_indirect)) {
216          /* Fast path for u_threaded_context to eliminate atomics. */
217          info.index.resource = _mesa_get_bufferobj_reference(ctx, bufobj);
218          info.take_index_buffer_ownership = true;
219       } else {
220          info.index.resource = bufobj->buffer;
221       }
222 
223       /* No index buffer storage allocated - nothing to do. */
224       if (!info.index.resource)
225          return;
226 
227       draw.start = 0;
228 
229       unsigned index_size_shift = util_logbase2(info.index_size);
230       info.restart_index = ctx->Array._RestartIndex[index_size_shift];
231       info.primitive_restart = ctx->Array._PrimitiveRestart[index_size_shift];
232    }
233 
234    info.mode = mode;
235    indirect.buffer = indirect_data->buffer;
236    indirect.offset = indirect_offset;
237 
238    /* Viewperf2020/Maya draws with a buffer that has no storage. */
239    if (!indirect.buffer)
240       return;
241 
242    if (!st->has_multi_draw_indirect) {
243       int i;
244 
245       indirect.draw_count = 1;
246       for (i = 0; i < draw_count; i++) {
247          ctx->Driver.DrawGallium(ctx, &info, i, &indirect, &draw, 1);
248          indirect.offset += stride;
249       }
250    } else {
251       indirect.draw_count = draw_count;
252       indirect.stride = stride;
253       if (!st->has_indirect_partial_stride && stride &&
254           (draw_count > 1 || indirect_draw_count)) {
255          /* DrawElementsIndirectCommand or DrawArraysIndirectCommand */
256          const size_t struct_size = info.index_size ? sizeof(uint32_t) * 5 : sizeof(uint32_t) * 4;
257          if (indirect.stride && indirect.stride < struct_size) {
258             rewrite_partial_stride_indirect(st, &info, &indirect, draw);
259             return;
260          }
261       }
262       if (indirect_draw_count) {
263          indirect.indirect_draw_count =
264             indirect_draw_count->buffer;
265          indirect.indirect_draw_count_offset = indirect_draw_count_offset;
266       }
267       ctx->Driver.DrawGallium(ctx, &info, 0, &indirect, &draw, 1);
268    }
269 
270    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
271       _mesa_flush(ctx);
272 }
273 
274 
275 void
st_init_draw_functions(struct pipe_screen * screen,struct dd_function_table * functions)276 st_init_draw_functions(struct pipe_screen *screen,
277                        struct dd_function_table *functions)
278 {
279    functions->DrawGallium = st_draw_gallium;
280    functions->DrawGalliumMultiMode = st_draw_gallium_multimode;
281 }
282 
283 
284 void
st_destroy_draw(struct st_context * st)285 st_destroy_draw(struct st_context *st)
286 {
287    draw_destroy(st->draw);
288 }
289 
290 /**
291  * Getter for the draw_context, so that initialization of it can happen only
292  * when needed (the TGSI exec machines take up quite a bit of memory).
293  */
294 struct draw_context *
st_get_draw_context(struct st_context * st)295 st_get_draw_context(struct st_context *st)
296 {
297    if (!st->draw) {
298       st->draw = draw_create(st->pipe);
299       if (!st->draw) {
300          _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation");
301          return NULL;
302       }
303    }
304 
305    /* Disable draw options that might convert points/lines to tris, etc.
306     * as that would foul-up feedback/selection mode.
307     */
308    draw_wide_line_threshold(st->draw, 1000.0f);
309    draw_wide_point_threshold(st->draw, 1000.0f);
310    draw_enable_line_stipple(st->draw, false);
311    draw_enable_point_sprites(st->draw, false);
312 
313    return st->draw;
314 }
315 
316 /**
317  * Draw a quad with given position, texcoords and color.
318  */
319 bool
st_draw_quad(struct st_context * st,float x0,float y0,float x1,float y1,float z,float s0,float t0,float s1,float t1,const float * color,unsigned num_instances)320 st_draw_quad(struct st_context *st,
321              float x0, float y0, float x1, float y1, float z,
322              float s0, float t0, float s1, float t1,
323              const float *color,
324              unsigned num_instances)
325 {
326    struct pipe_vertex_buffer vb = {0};
327    struct st_util_vertex *verts;
328 
329    u_upload_alloc(st->pipe->stream_uploader, 0,
330                   4 * sizeof(struct st_util_vertex), 4,
331                   &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
332    if (!vb.buffer.resource) {
333       return false;
334    }
335 
336    /* lower-left */
337    verts[0].x = x0;
338    verts[0].y = y1;
339    verts[0].z = z;
340    verts[0].r = color[0];
341    verts[0].g = color[1];
342    verts[0].b = color[2];
343    verts[0].a = color[3];
344    verts[0].s = s0;
345    verts[0].t = t0;
346 
347    /* lower-right */
348    verts[1].x = x1;
349    verts[1].y = y1;
350    verts[1].z = z;
351    verts[1].r = color[0];
352    verts[1].g = color[1];
353    verts[1].b = color[2];
354    verts[1].a = color[3];
355    verts[1].s = s1;
356    verts[1].t = t0;
357 
358    /* upper-right */
359    verts[2].x = x1;
360    verts[2].y = y0;
361    verts[2].z = z;
362    verts[2].r = color[0];
363    verts[2].g = color[1];
364    verts[2].b = color[2];
365    verts[2].a = color[3];
366    verts[2].s = s1;
367    verts[2].t = t1;
368 
369    /* upper-left */
370    verts[3].x = x0;
371    verts[3].y = y0;
372    verts[3].z = z;
373    verts[3].r = color[0];
374    verts[3].g = color[1];
375    verts[3].b = color[2];
376    verts[3].a = color[3];
377    verts[3].s = s0;
378    verts[3].t = t1;
379 
380    u_upload_unmap(st->pipe->stream_uploader);
381 
382    cso_set_vertex_buffers(st->cso_context, 1, true, &vb);
383 
384    if (num_instances > 1) {
385       cso_draw_arrays_instanced(st->cso_context, MESA_PRIM_TRIANGLE_FAN, 0, 4,
386                                 0, num_instances);
387    } else {
388       cso_draw_arrays(st->cso_context, MESA_PRIM_TRIANGLE_FAN, 0, 4);
389    }
390 
391    return true;
392 }
393 
394 static void
st_hw_select_draw_gallium(struct gl_context * ctx,const struct pipe_draw_info * info,unsigned drawid_offset,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * draws,unsigned num_draws)395 st_hw_select_draw_gallium(struct gl_context *ctx,
396                           const struct pipe_draw_info *info,
397                           unsigned drawid_offset,
398                           const struct pipe_draw_indirect_info *indirect,
399                           const struct pipe_draw_start_count_bias *draws,
400                           unsigned num_draws)
401 {
402    struct st_context *st = st_context(ctx);
403    enum mesa_prim old_mode = info->mode;
404 
405    if (st_draw_hw_select_prepare_common(ctx) &&
406        /* Removing "const" is fine because we restore the changed mode
407         * at the end. */
408        st_draw_hw_select_prepare_mode(ctx, ((struct pipe_draw_info*)info))) {
409       cso_draw_vbo(st->cso_context, info, drawid_offset, indirect, draws,
410                    num_draws);
411    }
412 
413    ((struct pipe_draw_info*)info)->mode = old_mode;
414 }
415 
416 static void
st_hw_select_draw_gallium_multimode(struct gl_context * ctx,struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draws,const unsigned char * mode,unsigned num_draws)417 st_hw_select_draw_gallium_multimode(struct gl_context *ctx,
418                                     struct pipe_draw_info *info,
419                                     const struct pipe_draw_start_count_bias *draws,
420                                     const unsigned char *mode,
421                                     unsigned num_draws)
422 {
423    struct st_context *st = st_context(ctx);
424 
425    if (!st_draw_hw_select_prepare_common(ctx))
426       return;
427 
428    unsigned i, first;
429    struct cso_context *cso = st->cso_context;
430 
431    /* Find consecutive draws where mode doesn't vary. */
432    for (i = 0, first = 0; i <= num_draws; i++) {
433       if (i == num_draws || mode[i] != mode[first]) {
434          info->mode = mode[first];
435 
436          if (st_draw_hw_select_prepare_mode(ctx, info))
437             cso_draw_vbo(cso, info, 0, NULL, &draws[first], i - first);
438 
439          first = i;
440 
441          /* We can pass the reference only once. st_buffer_object keeps
442           * the reference alive for later draws.
443           */
444          info->take_index_buffer_ownership = false;
445       }
446    }
447 }
448 
449 void
st_init_hw_select_draw_functions(struct pipe_screen * screen,struct dd_function_table * functions)450 st_init_hw_select_draw_functions(struct pipe_screen *screen,
451                                  struct dd_function_table *functions)
452 {
453    functions->DrawGallium = st_hw_select_draw_gallium;
454    functions->DrawGalliumMultiMode = st_hw_select_draw_gallium_multimode;
455 }
456