• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <keithw@vmware.com>
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 "vbo/vbo.h"
47 
48 #include "st_context.h"
49 #include "st_atom.h"
50 #include "st_cb_bitmap.h"
51 #include "st_debug.h"
52 #include "st_draw.h"
53 #include "st_program.h"
54 #include "st_util.h"
55 
56 #include "pipe/p_context.h"
57 #include "pipe/p_defines.h"
58 #include "util/u_cpu_detect.h"
59 #include "util/u_inlines.h"
60 #include "util/format/u_format.h"
61 #include "util/u_prim.h"
62 #include "util/u_draw.h"
63 #include "util/u_upload_mgr.h"
64 #include "util/u_threaded_context.h"
65 #include "draw/draw_context.h"
66 #include "cso_cache/cso_context.h"
67 
68 /* GL prims should match Gallium prims, spot-check a few */
69 static_assert(GL_POINTS == MESA_PRIM_POINTS, "enum mismatch");
70 static_assert(GL_QUADS == MESA_PRIM_QUADS, "enum mismatch");
71 static_assert(GL_TRIANGLE_STRIP_ADJACENCY == MESA_PRIM_TRIANGLE_STRIP_ADJACENCY, "enum mismatch");
72 static_assert(GL_PATCHES == MESA_PRIM_PATCHES, "enum mismatch");
73 
74 void
st_prepare_draw(struct gl_context * ctx,uint64_t state_mask)75 st_prepare_draw(struct gl_context *ctx, uint64_t state_mask)
76 {
77    struct st_context *st = ctx->st;
78 
79    /* Mesa core state should have been validated already */
80    assert(ctx->NewState == 0x0);
81 
82    if (unlikely(!st->bitmap.cache.empty))
83       st_flush_bitmap_cache(st);
84 
85    st_invalidate_readpix_cache(st);
86 
87    /* Validate state. */
88    st_validate_state(st, state_mask);
89 
90    /* Apply our thread scheduling policy for better multithreading
91     * performance.
92     */
93    if (unlikely(st->pin_thread_counter != ST_THREAD_SCHEDULER_DISABLED &&
94                 /* do it occasionally */
95                 ++st->pin_thread_counter % 512 == 0)) {
96       st->pin_thread_counter = 0;
97 
98       int cpu = util_get_current_cpu();
99       if (cpu >= 0) {
100          struct pipe_context *pipe = st->pipe;
101          uint16_t L3_cache = util_get_cpu_caps()->cpu_to_L3[cpu];
102 
103          if (L3_cache != U_CPU_INVALID_L3) {
104             pipe->set_context_param(pipe,
105                                     PIPE_CONTEXT_PARAM_UPDATE_THREAD_SCHEDULING,
106                                     cpu);
107          }
108       }
109    }
110 }
111 
112 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)113 st_draw_gallium(struct gl_context *ctx,
114                 const struct pipe_draw_info *info,
115                 unsigned drawid_offset,
116                 const struct pipe_draw_indirect_info *indirect,
117                 const struct pipe_draw_start_count_bias *draws,
118                 unsigned num_draws)
119 {
120    struct st_context *st = st_context(ctx);
121 
122    cso_draw_vbo(st->cso_context, info, drawid_offset, indirect, draws, num_draws);
123 }
124 
125 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)126 st_draw_gallium_multimode(struct gl_context *ctx,
127                           struct pipe_draw_info *info,
128                           const struct pipe_draw_start_count_bias *draws,
129                           const unsigned char *mode,
130                           unsigned num_draws)
131 {
132    struct st_context *st = st_context(ctx);
133 
134    unsigned i, first;
135    struct cso_context *cso = st->cso_context;
136 
137    /* Find consecutive draws where mode doesn't vary. */
138    for (i = 0, first = 0; i <= num_draws; i++) {
139       if (i == num_draws || mode[i] != mode[first]) {
140          info->mode = mode[first];
141          cso_draw_vbo(cso, info, 0, NULL, &draws[first], i - first);
142          first = i;
143 
144          /* We can pass the reference only once. st_buffer_object keeps
145           * the reference alive for later draws.
146           */
147          info->take_index_buffer_ownership = false;
148       }
149    }
150 }
151 
152 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)153 rewrite_partial_stride_indirect(struct st_context *st,
154                             const struct pipe_draw_info *info,
155                             const struct pipe_draw_indirect_info *indirect,
156                             const struct pipe_draw_start_count_bias draw)
157 {
158    unsigned draw_count = 0;
159    struct u_indirect_params *new_draws = util_draw_indirect_read(st->pipe, info, indirect, &draw_count);
160    if (!new_draws)
161       return;
162    for (unsigned i = 0; i < draw_count; i++)
163       st->ctx->Driver.DrawGallium(st->ctx, &new_draws[i].info, i, NULL, &new_draws[i].draw, 1);
164    free(new_draws);
165 }
166 
167 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)168 st_indirect_draw_vbo(struct gl_context *ctx,
169                      GLenum mode, GLenum index_type,
170                      GLintptr indirect_offset,
171                      GLintptr indirect_draw_count_offset,
172                      GLsizei draw_count, GLsizei stride)
173 {
174    struct gl_buffer_object *indirect_data = ctx->DrawIndirectBuffer;
175    struct gl_buffer_object *indirect_draw_count = ctx->ParameterBuffer;
176    struct st_context *st = st_context(ctx);
177    struct pipe_draw_info info;
178    struct pipe_draw_indirect_info indirect;
179    struct pipe_draw_start_count_bias draw = {0};
180 
181    /* If indirect_draw_count is set, drawcount is the maximum draw count.*/
182    if (!draw_count)
183       return;
184 
185    assert(stride);
186    st_prepare_draw(ctx, ST_PIPELINE_RENDER_STATE_MASK);
187 
188    memset(&indirect, 0, sizeof(indirect));
189    util_draw_init_info(&info);
190    info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
191 
192    switch (index_type) {
193    case GL_UNSIGNED_BYTE:
194       info.index_size = 1;
195       break;
196    case GL_UNSIGNED_SHORT:
197       info.index_size = 2;
198       break;
199    case GL_UNSIGNED_INT:
200       info.index_size = 4;
201       break;
202    }
203 
204    assert(st->has_multi_draw_indirect || !indirect_draw_count);
205 
206    if (info.index_size) {
207       struct gl_buffer_object *bufobj = ctx->Array.VAO->IndexBufferObj;
208 
209       /* indices are always in a real VBO */
210       assert(bufobj);
211 
212       if (st->pipe->draw_vbo == tc_draw_vbo &&
213           (draw_count == 1 || st->has_multi_draw_indirect)) {
214          /* Fast path for u_threaded_context to eliminate atomics. */
215          info.index.resource = _mesa_get_bufferobj_reference(ctx, bufobj);
216          info.take_index_buffer_ownership = true;
217       } else {
218          info.index.resource = bufobj->buffer;
219       }
220 
221       /* No index buffer storage allocated - nothing to do. */
222       if (!info.index.resource)
223          return;
224 
225       draw.start = 0;
226 
227       unsigned index_size_shift = util_logbase2(info.index_size);
228       info.restart_index = ctx->Array._RestartIndex[index_size_shift];
229       info.primitive_restart = ctx->Array._PrimitiveRestart[index_size_shift];
230    }
231 
232    info.mode = mode;
233    indirect.buffer = indirect_data->buffer;
234    indirect.offset = indirect_offset;
235 
236    /* Viewperf2020/Maya draws with a buffer that has no storage. */
237    if (!indirect.buffer)
238       return;
239 
240    if (!st->has_multi_draw_indirect) {
241       int i;
242 
243       indirect.draw_count = 1;
244       for (i = 0; i < draw_count; i++) {
245          ctx->Driver.DrawGallium(ctx, &info, i, &indirect, &draw, 1);
246          indirect.offset += stride;
247       }
248    } else {
249       indirect.draw_count = draw_count;
250       indirect.stride = stride;
251       if (!st->has_indirect_partial_stride && stride &&
252           (draw_count > 1 || indirect_draw_count)) {
253          /* DrawElementsIndirectCommand or DrawArraysIndirectCommand */
254          const size_t struct_size = info.index_size ? sizeof(uint32_t) * 5 : sizeof(uint32_t) * 4;
255          if (indirect.stride && indirect.stride < struct_size) {
256             rewrite_partial_stride_indirect(st, &info, &indirect, draw);
257             return;
258          }
259       }
260       if (indirect_draw_count) {
261          indirect.indirect_draw_count =
262             indirect_draw_count->buffer;
263          indirect.indirect_draw_count_offset = indirect_draw_count_offset;
264       }
265       ctx->Driver.DrawGallium(ctx, &info, 0, &indirect, &draw, 1);
266    }
267 
268    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
269       _mesa_flush(ctx);
270 }
271 
272 
273 void
st_init_draw_functions(struct pipe_screen * screen,struct dd_function_table * functions)274 st_init_draw_functions(struct pipe_screen *screen,
275                        struct dd_function_table *functions)
276 {
277    functions->DrawGallium = st_draw_gallium;
278    functions->DrawGalliumMultiMode = st_draw_gallium_multimode;
279 }
280 
281 
282 void
st_destroy_draw(struct st_context * st)283 st_destroy_draw(struct st_context *st)
284 {
285    draw_destroy(st->draw);
286 }
287 
288 /**
289  * Getter for the draw_context, so that initialization of it can happen only
290  * when needed (the TGSI exec machines take up quite a bit of memory).
291  */
292 struct draw_context *
st_get_draw_context(struct st_context * st)293 st_get_draw_context(struct st_context *st)
294 {
295    if (!st->draw) {
296       st->draw = draw_create(st->pipe);
297       if (!st->draw) {
298          _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation");
299          return NULL;
300       }
301    }
302 
303    /* Disable draw options that might convert points/lines to tris, etc.
304     * as that would foul-up feedback/selection mode.
305     */
306    draw_wide_line_threshold(st->draw, 1000.0f);
307    draw_wide_point_threshold(st->draw, 1000.0f);
308    draw_enable_line_stipple(st->draw, false);
309    draw_enable_point_sprites(st->draw, false);
310 
311    return st->draw;
312 }
313 
314 /**
315  * Draw a quad with given position, texcoords and color.
316  */
317 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)318 st_draw_quad(struct st_context *st,
319              float x0, float y0, float x1, float y1, float z,
320              float s0, float t0, float s1, float t1,
321              const float *color,
322              unsigned num_instances)
323 {
324    struct pipe_vertex_buffer vb = {0};
325    struct st_util_vertex *verts;
326 
327    u_upload_alloc(st->pipe->stream_uploader, 0,
328                   4 * sizeof(struct st_util_vertex), 4,
329                   &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
330    if (!vb.buffer.resource) {
331       return false;
332    }
333 
334    /* lower-left */
335    verts[0].x = x0;
336    verts[0].y = y1;
337    verts[0].z = z;
338    verts[0].r = color[0];
339    verts[0].g = color[1];
340    verts[0].b = color[2];
341    verts[0].a = color[3];
342    verts[0].s = s0;
343    verts[0].t = t0;
344 
345    /* lower-right */
346    verts[1].x = x1;
347    verts[1].y = y1;
348    verts[1].z = z;
349    verts[1].r = color[0];
350    verts[1].g = color[1];
351    verts[1].b = color[2];
352    verts[1].a = color[3];
353    verts[1].s = s1;
354    verts[1].t = t0;
355 
356    /* upper-right */
357    verts[2].x = x1;
358    verts[2].y = y0;
359    verts[2].z = z;
360    verts[2].r = color[0];
361    verts[2].g = color[1];
362    verts[2].b = color[2];
363    verts[2].a = color[3];
364    verts[2].s = s1;
365    verts[2].t = t1;
366 
367    /* upper-left */
368    verts[3].x = x0;
369    verts[3].y = y0;
370    verts[3].z = z;
371    verts[3].r = color[0];
372    verts[3].g = color[1];
373    verts[3].b = color[2];
374    verts[3].a = color[3];
375    verts[3].s = s0;
376    verts[3].t = t1;
377 
378    u_upload_unmap(st->pipe->stream_uploader);
379 
380    cso_set_vertex_buffers(st->cso_context, 1, true, &vb);
381 
382    if (num_instances > 1) {
383       cso_draw_arrays_instanced(st->cso_context, MESA_PRIM_TRIANGLE_FAN, 0, 4,
384                                 0, num_instances);
385    } else {
386       cso_draw_arrays(st->cso_context, MESA_PRIM_TRIANGLE_FAN, 0, 4);
387    }
388 
389    return true;
390 }
391 
392 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)393 st_hw_select_draw_gallium(struct gl_context *ctx,
394                           const struct pipe_draw_info *info,
395                           unsigned drawid_offset,
396                           const struct pipe_draw_indirect_info *indirect,
397                           const struct pipe_draw_start_count_bias *draws,
398                           unsigned num_draws)
399 {
400    struct st_context *st = st_context(ctx);
401    enum mesa_prim old_mode = info->mode;
402 
403    if (st_draw_hw_select_prepare_common(ctx) &&
404        /* Removing "const" is fine because we restore the changed mode
405         * at the end. */
406        st_draw_hw_select_prepare_mode(ctx, ((struct pipe_draw_info*)info))) {
407       cso_draw_vbo(st->cso_context, info, drawid_offset, indirect, draws,
408                    num_draws);
409    }
410 
411    ((struct pipe_draw_info*)info)->mode = old_mode;
412 }
413 
414 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)415 st_hw_select_draw_gallium_multimode(struct gl_context *ctx,
416                                     struct pipe_draw_info *info,
417                                     const struct pipe_draw_start_count_bias *draws,
418                                     const unsigned char *mode,
419                                     unsigned num_draws)
420 {
421    struct st_context *st = st_context(ctx);
422 
423    if (!st_draw_hw_select_prepare_common(ctx))
424       return;
425 
426    unsigned i, first;
427    struct cso_context *cso = st->cso_context;
428 
429    /* Find consecutive draws where mode doesn't vary. */
430    for (i = 0, first = 0; i <= num_draws; i++) {
431       if (i == num_draws || mode[i] != mode[first]) {
432          info->mode = mode[first];
433 
434          if (st_draw_hw_select_prepare_mode(ctx, info))
435             cso_draw_vbo(cso, info, 0, NULL, &draws[first], i - first);
436 
437          first = i;
438 
439          /* We can pass the reference only once. st_buffer_object keeps
440           * the reference alive for later draws.
441           */
442          info->take_index_buffer_ownership = false;
443       }
444    }
445 }
446 
447 void
st_init_hw_select_draw_functions(struct pipe_screen * screen,struct dd_function_table * functions)448 st_init_hw_select_draw_functions(struct pipe_screen *screen,
449                                  struct dd_function_table *functions)
450 {
451    functions->DrawGallium = st_hw_select_draw_gallium;
452    functions->DrawGalliumMultiMode = st_hw_select_draw_gallium_multimode;
453 }
454