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
39#include "main/errors.h"
40#include "main/imports.h"
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_cb_bufferobjects.h"
54#include "st_cb_xformfb.h"
55#include "st_debug.h"
56#include "st_draw.h"
57#include "st_program.h"
58#include "st_util.h"
59
60#include "pipe/p_context.h"
61#include "pipe/p_defines.h"
62#include "util/u_cpu_detect.h"
63#include "util/u_inlines.h"
64#include "util/u_format.h"
65#include "util/u_prim.h"
66#include "util/u_draw.h"
67#include "util/u_upload_mgr.h"
68#include "draw/draw_context.h"
69#include "cso_cache/cso_context.h"
70
71#if defined(PIPE_OS_LINUX) && !defined(ANDROID)
72#include <sched.h>
73#define HAVE_SCHED_GETCPU 1
74#else
75#define sched_getcpu() 0
76#define HAVE_SCHED_GETCPU 0
77#endif
78
79/**
80 * Set the restart index.
81 */
82static void
83setup_primitive_restart(struct gl_context *ctx, struct pipe_draw_info *info)
84{
85   if (ctx->Array._PrimitiveRestart) {
86      unsigned index_size = info->index_size;
87
88      info->restart_index =
89         _mesa_primitive_restart_index(ctx, index_size);
90
91      /* Enable primitive restart only when the restart index can have an
92       * effect. This is required for correctness in radeonsi VI support.
93       * Other hardware may also benefit from taking a faster, non-restart path
94       * when possible.
95       */
96      if (index_size == 4 || info->restart_index < (1 << (index_size * 8)))
97         info->primitive_restart = true;
98   }
99}
100
101
102/**
103 * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
104 * the corresponding Gallium type.
105 */
106static unsigned
107translate_prim(const struct gl_context *ctx, unsigned prim)
108{
109   /* GL prims should match Gallium prims, spot-check a few */
110   STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS);
111   STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS);
112   STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
113   STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES);
114
115   return prim;
116}
117
118static inline void
119prepare_draw(struct st_context *st, struct gl_context *ctx)
120{
121   /* Mesa core state should have been validated already */
122   assert(ctx->NewState == 0x0);
123
124   if (unlikely(!st->bitmap.cache.empty))
125      st_flush_bitmap_cache(st);
126
127   st_invalidate_readpix_cache(st);
128
129   /* Validate state. */
130   if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK ||
131       st->gfx_shaders_may_be_dirty) {
132      st_validate_state(st, ST_PIPELINE_RENDER);
133   }
134
135   struct pipe_context *pipe = st->pipe;
136
137   /* Pin threads regularly to the same Zen CCX that the main thread is
138    * running on. The main thread can move between CCXs.
139    */
140   if (unlikely(HAVE_SCHED_GETCPU && /* Linux */
141                /* AMD Zen */
142                util_cpu_caps.nr_cpus != util_cpu_caps.cores_per_L3 &&
143                /* no glthread */
144                ctx->CurrentClientDispatch != ctx->MarshalExec &&
145                /* driver support */
146                pipe->set_context_param &&
147                /* do it occasionally */
148                ++st->pin_thread_counter % 512 == 0)) {
149      int cpu = sched_getcpu();
150      if (cpu >= 0) {
151         unsigned L3_cache = cpu / util_cpu_caps.cores_per_L3;
152
153         pipe->set_context_param(pipe,
154                                 PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE,
155                                 L3_cache);
156      }
157   }
158}
159
160/**
161 * This function gets plugged into the VBO module and is called when
162 * we have something to render.
163 * Basically, translate the information into the format expected by gallium.
164 *
165 * Try to keep this logic in sync with st_feedback_draw_vbo.
166 */
167static void
168st_draw_vbo(struct gl_context *ctx,
169            const struct _mesa_prim *prims,
170            GLuint nr_prims,
171            const struct _mesa_index_buffer *ib,
172	    GLboolean index_bounds_valid,
173            GLuint min_index,
174            GLuint max_index,
175            struct gl_transform_feedback_object *tfb_vertcount,
176            unsigned stream,
177            struct gl_buffer_object *indirect)
178{
179   struct st_context *st = st_context(ctx);
180   struct pipe_draw_info info;
181   unsigned i;
182   unsigned start = 0;
183
184   prepare_draw(st, ctx);
185
186   /* Initialize pipe_draw_info. */
187   info.primitive_restart = false;
188   info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices;
189   info.indirect = NULL;
190   info.count_from_stream_output = NULL;
191   info.restart_index = 0;
192
193   if (ib) {
194      struct gl_buffer_object *bufobj = ib->obj;
195
196      /* Get index bounds for user buffers. */
197      if (!index_bounds_valid && st->draw_needs_minmax_index) {
198         vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
199                                nr_prims);
200      }
201
202      info.index_size = ib->index_size;
203      info.min_index = min_index;
204      info.max_index = max_index;
205
206      if (_mesa_is_bufferobj(bufobj)) {
207         /* indices are in a real VBO */
208         info.has_user_indices = false;
209         info.index.resource = st_buffer_object(bufobj)->buffer;
210
211         /* Return if the bound element array buffer doesn't have any backing
212          * storage. (nothing to do)
213          */
214         if (!info.index.resource)
215            return;
216
217         start = pointer_to_offset(ib->ptr) / info.index_size;
218      } else {
219         /* indices are in user space memory */
220         info.has_user_indices = true;
221         info.index.user = ib->ptr;
222      }
223
224      setup_primitive_restart(ctx, &info);
225   }
226   else {
227      info.index_size = 0;
228      info.has_user_indices = false;
229
230      /* Transform feedback drawing is always non-indexed. */
231      /* Set info.count_from_stream_output. */
232      if (tfb_vertcount) {
233         if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &info))
234            return;
235      }
236   }
237
238   assert(!indirect);
239
240   /* do actual drawing */
241   for (i = 0; i < nr_prims; i++) {
242      info.count = prims[i].count;
243
244      /* Skip no-op draw calls. */
245      if (!info.count && !tfb_vertcount)
246         continue;
247
248      info.mode = translate_prim(ctx, prims[i].mode);
249      info.start = start + prims[i].start;
250      info.start_instance = prims[i].base_instance;
251      info.instance_count = prims[i].num_instances;
252      info.index_bias = prims[i].basevertex;
253      info.drawid = prims[i].draw_id;
254      if (!ib) {
255         info.min_index = info.start;
256         info.max_index = info.start + info.count - 1;
257      }
258
259      if (ST_DEBUG & DEBUG_DRAW) {
260         debug_printf("st/draw: mode %s  start %u  count %u  index_size %d\n",
261                      u_prim_name(info.mode),
262                      info.start,
263                      info.count,
264                      info.index_size);
265      }
266
267      /* Don't call u_trim_pipe_prim. Drivers should do it if they need it. */
268      cso_draw_vbo(st->cso_context, &info);
269   }
270}
271
272static void
273st_indirect_draw_vbo(struct gl_context *ctx,
274                     GLuint mode,
275                     struct gl_buffer_object *indirect_data,
276                     GLsizeiptr indirect_offset,
277                     unsigned draw_count,
278                     unsigned stride,
279                     struct gl_buffer_object *indirect_draw_count,
280                     GLsizeiptr indirect_draw_count_offset,
281                     const struct _mesa_index_buffer *ib)
282{
283   struct st_context *st = st_context(ctx);
284   struct pipe_draw_info info;
285   struct pipe_draw_indirect_info indirect;
286
287   assert(stride);
288   prepare_draw(st, ctx);
289
290   memset(&indirect, 0, sizeof(indirect));
291   util_draw_init_info(&info);
292   info.start = 0; /* index offset / index size */
293   info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
294
295   if (ib) {
296      struct gl_buffer_object *bufobj = ib->obj;
297
298      /* indices are always in a real VBO */
299      assert(_mesa_is_bufferobj(bufobj));
300
301      info.index_size = ib->index_size;
302      info.index.resource = st_buffer_object(bufobj)->buffer;
303      info.start = pointer_to_offset(ib->ptr) / info.index_size;
304
305      /* Primitive restart is not handled by the VBO module in this case. */
306      setup_primitive_restart(ctx, &info);
307   }
308
309   info.mode = translate_prim(ctx, mode);
310   info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices;
311   info.indirect = &indirect;
312   indirect.buffer = st_buffer_object(indirect_data)->buffer;
313   indirect.offset = indirect_offset;
314
315   if (ST_DEBUG & DEBUG_DRAW) {
316      debug_printf("st/draw indirect: mode %s drawcount %d index_size %d\n",
317                   u_prim_name(info.mode),
318                   draw_count,
319                   info.index_size);
320   }
321
322   if (!st->has_multi_draw_indirect) {
323      int i;
324
325      assert(!indirect_draw_count);
326      indirect.draw_count = 1;
327      for (i = 0; i < draw_count; i++) {
328         info.drawid = i;
329         cso_draw_vbo(st->cso_context, &info);
330         indirect.offset += stride;
331      }
332   } else {
333      indirect.draw_count = draw_count;
334      indirect.stride = stride;
335      if (indirect_draw_count) {
336         indirect.indirect_draw_count =
337            st_buffer_object(indirect_draw_count)->buffer;
338         indirect.indirect_draw_count_offset = indirect_draw_count_offset;
339      }
340      cso_draw_vbo(st->cso_context, &info);
341   }
342}
343
344
345void
346st_init_draw_functions(struct dd_function_table *functions)
347{
348   functions->Draw = st_draw_vbo;
349   functions->DrawIndirect = st_indirect_draw_vbo;
350}
351
352
353void
354st_destroy_draw(struct st_context *st)
355{
356   draw_destroy(st->draw);
357}
358
359/**
360 * Getter for the draw_context, so that initialization of it can happen only
361 * when needed (the TGSI exec machines take up quite a bit of memory).
362 */
363struct draw_context *
364st_get_draw_context(struct st_context *st)
365{
366   if (!st->draw) {
367      st->draw = draw_create(st->pipe);
368      if (!st->draw) {
369         _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation");
370         return NULL;
371      }
372   }
373
374   /* Disable draw options that might convert points/lines to tris, etc.
375    * as that would foul-up feedback/selection mode.
376    */
377   draw_wide_line_threshold(st->draw, 1000.0f);
378   draw_wide_point_threshold(st->draw, 1000.0f);
379   draw_enable_line_stipple(st->draw, FALSE);
380   draw_enable_point_sprites(st->draw, FALSE);
381
382   return st->draw;
383}
384
385/**
386 * Draw a quad with given position, texcoords and color.
387 */
388bool
389st_draw_quad(struct st_context *st,
390             float x0, float y0, float x1, float y1, float z,
391             float s0, float t0, float s1, float t1,
392             const float *color,
393             unsigned num_instances)
394{
395   struct pipe_vertex_buffer vb = {0};
396   struct st_util_vertex *verts;
397
398   vb.stride = sizeof(struct st_util_vertex);
399
400   u_upload_alloc(st->pipe->stream_uploader, 0,
401                  4 * sizeof(struct st_util_vertex), 4,
402                  &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
403   if (!vb.buffer.resource) {
404      return false;
405   }
406
407   /* lower-left */
408   verts[0].x = x0;
409   verts[0].y = y1;
410   verts[0].z = z;
411   verts[0].r = color[0];
412   verts[0].g = color[1];
413   verts[0].b = color[2];
414   verts[0].a = color[3];
415   verts[0].s = s0;
416   verts[0].t = t0;
417
418   /* lower-right */
419   verts[1].x = x1;
420   verts[1].y = y1;
421   verts[1].z = z;
422   verts[1].r = color[0];
423   verts[1].g = color[1];
424   verts[1].b = color[2];
425   verts[1].a = color[3];
426   verts[1].s = s1;
427   verts[1].t = t0;
428
429   /* upper-right */
430   verts[2].x = x1;
431   verts[2].y = y0;
432   verts[2].z = z;
433   verts[2].r = color[0];
434   verts[2].g = color[1];
435   verts[2].b = color[2];
436   verts[2].a = color[3];
437   verts[2].s = s1;
438   verts[2].t = t1;
439
440   /* upper-left */
441   verts[3].x = x0;
442   verts[3].y = y0;
443   verts[3].z = z;
444   verts[3].r = color[0];
445   verts[3].g = color[1];
446   verts[3].b = color[2];
447   verts[3].a = color[3];
448   verts[3].s = s0;
449   verts[3].t = t1;
450
451   u_upload_unmap(st->pipe->stream_uploader);
452
453   cso_set_vertex_buffers(st->cso_context, 0, 1, &vb);
454
455   if (num_instances > 1) {
456      cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4,
457                                0, num_instances);
458   } else {
459      cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4);
460   }
461
462   pipe_resource_reference(&vb.buffer.resource, NULL);
463
464   return true;
465}
466