draw_pt.c revision cdca3c58aa2d9549f5188910e2a77b438516714f
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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  * Authors:
30  *   Keith Whitwell <keith@tungstengraphics.com>
31  */
32
33#include "draw/draw_context.h"
34#include "draw/draw_gs.h"
35#include "draw/draw_private.h"
36#include "draw/draw_pt.h"
37#include "draw/draw_vs.h"
38#include "tgsi/tgsi_dump.h"
39#include "util/u_math.h"
40#include "util/u_prim.h"
41#include "util/u_format.h"
42#include "util/u_draw.h"
43
44
45DEBUG_GET_ONCE_BOOL_OPTION(draw_fse, "DRAW_FSE", FALSE)
46DEBUG_GET_ONCE_BOOL_OPTION(draw_no_fse, "DRAW_NO_FSE", FALSE)
47
48/* Overall we split things into:
49 *     - frontend -- prepare fetch_elts, draw_elts - eg vsplit
50 *     - middle   -- fetch, shade, cliptest, viewport
51 *     - pipeline -- the prim pipeline: clipping, wide lines, etc
52 *     - backend  -- the vbuf_render provided by the driver.
53 */
54static boolean
55draw_pt_arrays(struct draw_context *draw,
56               unsigned prim,
57               unsigned start,
58               unsigned count)
59{
60   struct draw_pt_front_end *frontend = NULL;
61   struct draw_pt_middle_end *middle = NULL;
62   unsigned opt = 0;
63
64   /* Sanitize primitive length:
65    */
66   {
67      unsigned first, incr;
68      draw_pt_split_prim(prim, &first, &incr);
69      count = draw_pt_trim_count(count, first, incr);
70      if (count < first)
71         return TRUE;
72   }
73
74   if (!draw->force_passthrough) {
75      unsigned gs_out_prim = (draw->gs.geometry_shader ?
76                              draw->gs.geometry_shader->output_primitive :
77                              prim);
78
79      if (!draw->render) {
80         opt |= PT_PIPELINE;
81      }
82
83      if (draw_need_pipeline(draw,
84                             draw->rasterizer,
85                             gs_out_prim)) {
86         opt |= PT_PIPELINE;
87      }
88
89      if ((draw->clip_xy ||
90           draw->clip_z ||
91           draw->clip_user) && !draw->pt.test_fse) {
92         opt |= PT_CLIPTEST;
93      }
94
95      opt |= PT_SHADE;
96   }
97
98   if (draw->pt.middle.llvm) {
99      middle = draw->pt.middle.llvm;
100   } else {
101      if (opt == 0)
102         middle = draw->pt.middle.fetch_emit;
103      else if (opt == PT_SHADE && !draw->pt.no_fse)
104         middle = draw->pt.middle.fetch_shade_emit;
105      else
106         middle = draw->pt.middle.general;
107   }
108
109   frontend = draw->pt.front.vsplit;
110
111   frontend->prepare( frontend, prim, middle, opt );
112
113   frontend->run(frontend, start, count);
114
115   frontend->finish( frontend );
116
117   return TRUE;
118}
119
120
121boolean draw_pt_init( struct draw_context *draw )
122{
123   draw->pt.test_fse = debug_get_option_draw_fse();
124   draw->pt.no_fse = debug_get_option_draw_no_fse();
125
126   draw->pt.front.vsplit = draw_pt_vsplit(draw);
127   if (!draw->pt.front.vsplit)
128      return FALSE;
129
130   draw->pt.middle.fetch_emit = draw_pt_fetch_emit( draw );
131   if (!draw->pt.middle.fetch_emit)
132      return FALSE;
133
134   draw->pt.middle.fetch_shade_emit = draw_pt_middle_fse( draw );
135   if (!draw->pt.middle.fetch_shade_emit)
136      return FALSE;
137
138   draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit( draw );
139   if (!draw->pt.middle.general)
140      return FALSE;
141
142#if HAVE_LLVM
143   if (draw->llvm)
144      draw->pt.middle.llvm = draw_pt_fetch_pipeline_or_emit_llvm( draw );
145#endif
146
147   return TRUE;
148}
149
150
151void draw_pt_destroy( struct draw_context *draw )
152{
153   if (draw->pt.middle.llvm) {
154      draw->pt.middle.llvm->destroy( draw->pt.middle.llvm );
155      draw->pt.middle.llvm = NULL;
156   }
157
158   if (draw->pt.middle.general) {
159      draw->pt.middle.general->destroy( draw->pt.middle.general );
160      draw->pt.middle.general = NULL;
161   }
162
163   if (draw->pt.middle.fetch_emit) {
164      draw->pt.middle.fetch_emit->destroy( draw->pt.middle.fetch_emit );
165      draw->pt.middle.fetch_emit = NULL;
166   }
167
168   if (draw->pt.middle.fetch_shade_emit) {
169      draw->pt.middle.fetch_shade_emit->destroy( draw->pt.middle.fetch_shade_emit );
170      draw->pt.middle.fetch_shade_emit = NULL;
171   }
172
173   if (draw->pt.front.vsplit) {
174      draw->pt.front.vsplit->destroy( draw->pt.front.vsplit );
175      draw->pt.front.vsplit = NULL;
176   }
177}
178
179
180/**
181 * Debug- print the first 'count' vertices.
182 */
183static void
184draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count)
185{
186   uint i;
187
188   debug_printf("Draw arrays(prim = %u, start = %u, count = %u)\n",
189                prim, start, count);
190
191   for (i = 0; i < count; i++) {
192      uint ii = 0;
193      uint j;
194
195      if (draw->pt.user.eltSize) {
196         const char *elts;
197
198         /* indexed arrays */
199         elts = (const char *) draw->pt.user.elts;
200         elts += draw->pt.index_buffer.offset;
201
202         switch (draw->pt.user.eltSize) {
203         case 1:
204            {
205               const ubyte *elem = (const ubyte *) elts;
206               ii = elem[start + i];
207            }
208            break;
209         case 2:
210            {
211               const ushort *elem = (const ushort *) elts;
212               ii = elem[start + i];
213            }
214            break;
215         case 4:
216            {
217               const uint *elem = (const uint *) elts;
218               ii = elem[start + i];
219            }
220            break;
221         default:
222            assert(0);
223            return;
224         }
225         ii += draw->pt.user.eltBias;
226         debug_printf("Element[%u + %u] + %i -> Vertex %u:\n", start, i,
227                      draw->pt.user.eltBias, ii);
228      }
229      else {
230         /* non-indexed arrays */
231         ii = start + i;
232         debug_printf("Vertex %u:\n", ii);
233      }
234
235      for (j = 0; j < draw->pt.nr_vertex_elements; j++) {
236         uint buf = draw->pt.vertex_element[j].vertex_buffer_index;
237         ubyte *ptr = (ubyte *) draw->pt.user.vbuffer[buf];
238
239         if (draw->pt.vertex_element[j].instance_divisor) {
240            ii = draw->instance_id / draw->pt.vertex_element[j].instance_divisor;
241         }
242
243         ptr += draw->pt.vertex_buffer[buf].buffer_offset;
244         ptr += draw->pt.vertex_buffer[buf].stride * ii;
245         ptr += draw->pt.vertex_element[j].src_offset;
246
247         debug_printf("  Attr %u: ", j);
248         switch (draw->pt.vertex_element[j].src_format) {
249         case PIPE_FORMAT_R32_FLOAT:
250            {
251               float *v = (float *) ptr;
252               debug_printf("R %f  @ %p\n", v[0], (void *) v);
253            }
254            break;
255         case PIPE_FORMAT_R32G32_FLOAT:
256            {
257               float *v = (float *) ptr;
258               debug_printf("RG %f %f  @ %p\n", v[0], v[1], (void *) v);
259            }
260            break;
261         case PIPE_FORMAT_R32G32B32_FLOAT:
262            {
263               float *v = (float *) ptr;
264               debug_printf("RGB %f %f %f  @ %p\n", v[0], v[1], v[2], (void *) v);
265            }
266            break;
267         case PIPE_FORMAT_R32G32B32A32_FLOAT:
268            {
269               float *v = (float *) ptr;
270               debug_printf("RGBA %f %f %f %f  @ %p\n", v[0], v[1], v[2], v[3],
271                            (void *) v);
272            }
273            break;
274         case PIPE_FORMAT_B8G8R8A8_UNORM:
275            {
276               ubyte *u = (ubyte *) ptr;
277               debug_printf("BGRA %d %d %d %d  @ %p\n", u[0], u[1], u[2], u[3],
278                            (void *) u);
279            }
280            break;
281         default:
282            debug_printf("other format %s (fix me)\n",
283                     util_format_name(draw->pt.vertex_element[j].src_format));
284         }
285      }
286   }
287}
288
289
290/** Helper code for below */
291#define PRIM_RESTART_LOOP(elements) \
292   do { \
293      for (i = start; i < end; i++) { \
294         if (elements[i] == info->restart_index) { \
295            if (cur_count > 0) { \
296               /* draw elts up to prev pos */ \
297               draw_pt_arrays(draw, prim, cur_start, cur_count); \
298            } \
299            /* begin new prim at next elt */ \
300            cur_start = i + 1; \
301            cur_count = 0; \
302         } \
303         else { \
304            cur_count++; \
305         } \
306      } \
307      if (cur_count > 0) { \
308         draw_pt_arrays(draw, prim, cur_start, cur_count); \
309      } \
310   } while (0)
311
312
313/**
314 * For drawing prims with primitive restart enabled.
315 * Scan for restart indexes and draw the runs of elements/vertices between
316 * the restarts.
317 */
318static void
319draw_pt_arrays_restart(struct draw_context *draw,
320                       const struct pipe_draw_info *info)
321{
322   const unsigned prim = info->mode;
323   const unsigned start = info->start;
324   const unsigned count = info->count;
325   const unsigned end = start + count;
326   unsigned i, cur_start, cur_count;
327
328   assert(info->primitive_restart);
329
330   if (draw->pt.user.elts) {
331      /* indexed prims (draw_elements) */
332      cur_start = start;
333      cur_count = 0;
334
335      switch (draw->pt.user.eltSize) {
336      case 1:
337         {
338            const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts;
339            PRIM_RESTART_LOOP(elt_ub);
340         }
341         break;
342      case 2:
343         {
344            const ushort *elt_us = (const ushort *) draw->pt.user.elts;
345            PRIM_RESTART_LOOP(elt_us);
346         }
347         break;
348      case 4:
349         {
350            const uint *elt_ui = (const uint *) draw->pt.user.elts;
351            PRIM_RESTART_LOOP(elt_ui);
352         }
353         break;
354      default:
355         assert(0 && "bad eltSize in draw_arrays()");
356      }
357   }
358   else {
359      /* Non-indexed prims (draw_arrays).
360       * Primitive restart should have been handled in the state tracker.
361       */
362      draw_pt_arrays(draw, prim, start, count);
363   }
364}
365
366
367
368/**
369 * Non-instanced drawing.
370 * \sa draw_arrays_instanced
371 */
372void
373draw_arrays(struct draw_context *draw, unsigned prim,
374            unsigned start, unsigned count)
375{
376   draw_arrays_instanced(draw, prim, start, count, 0, 1);
377}
378
379
380/**
381 * Instanced drawing.
382 * \sa draw_vbo
383 */
384void
385draw_arrays_instanced(struct draw_context *draw,
386                      unsigned mode,
387                      unsigned start,
388                      unsigned count,
389                      unsigned startInstance,
390                      unsigned instanceCount)
391{
392   struct pipe_draw_info info;
393
394   util_draw_init_info(&info);
395
396   info.mode = mode;
397   info.start = start;
398   info.count = count;
399   info.start_instance = startInstance;
400   info.instance_count = instanceCount;
401
402   info.indexed = (draw->pt.user.elts != NULL);
403   if (!info.indexed) {
404      info.min_index = start;
405      info.max_index = start + count - 1;
406   }
407
408   draw_vbo(draw, &info);
409}
410
411
412/**
413 * Draw vertex arrays.
414 * This is the main entrypoint into the drawing module.  If drawing an indexed
415 * primitive, the draw_set_index_buffer() and draw_set_mapped_index_buffer()
416 * functions should have already been called to specify the element/index
417 * buffer information.
418 */
419void
420draw_vbo(struct draw_context *draw,
421         const struct pipe_draw_info *info)
422{
423   unsigned reduced_prim = u_reduced_prim(info->mode);
424   unsigned instance;
425
426   assert(info->instance_count > 0);
427   if (info->indexed)
428      assert(draw->pt.user.elts);
429
430   draw->pt.user.eltSize =
431      (info->indexed) ? draw->pt.index_buffer.index_size : 0;
432
433   draw->pt.user.eltBias = info->index_bias;
434   draw->pt.user.min_index = info->min_index;
435   draw->pt.user.max_index = info->max_index;
436
437   if (reduced_prim != draw->reduced_prim) {
438      draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
439      draw->reduced_prim = reduced_prim;
440   }
441
442   if (0)
443      debug_printf("draw_vbo(mode=%u start=%u count=%u):\n",
444                   info->mode, info->start, info->count);
445
446   if (0)
447      tgsi_dump(draw->vs.vertex_shader->state.tokens, 0);
448
449   if (0) {
450      unsigned int i;
451      debug_printf("Elements:\n");
452      for (i = 0; i < draw->pt.nr_vertex_elements; i++) {
453         debug_printf("  %u: src_offset=%u  inst_div=%u   vbuf=%u  format=%s\n",
454                      i,
455                      draw->pt.vertex_element[i].src_offset,
456                      draw->pt.vertex_element[i].instance_divisor,
457                      draw->pt.vertex_element[i].vertex_buffer_index,
458                      util_format_name(draw->pt.vertex_element[i].src_format));
459      }
460      debug_printf("Buffers:\n");
461      for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
462         debug_printf("  %u: stride=%u offset=%u ptr=%p\n",
463                      i,
464                      draw->pt.vertex_buffer[i].stride,
465                      draw->pt.vertex_buffer[i].buffer_offset,
466                      draw->pt.user.vbuffer[i]);
467      }
468   }
469
470   if (0)
471      draw_print_arrays(draw, info->mode, info->start, MIN2(info->count, 20));
472
473   for (instance = 0; instance < info->instance_count; instance++) {
474      draw->instance_id = instance + info->start_instance;
475
476      if (info->primitive_restart) {
477         draw_pt_arrays_restart(draw, info);
478      }
479      else {
480         draw_pt_arrays(draw, info->mode, info->start, info->count);
481      }
482   }
483}
484