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  * Authors:
30  *   Keith Whitwell <keithw@vmware.com>
31  */
32
33#include "draw/draw_private.h"
34#include "draw/draw_pipe.h"
35#include "util/u_debug.h"
36#include "util/u_math.h"
37
38
39boolean
40draw_pipeline_init(struct draw_context *draw)
41{
42   /* create pipeline stages */
43   draw->pipeline.wide_line  = draw_wide_line_stage(draw);
44   draw->pipeline.wide_point = draw_wide_point_stage(draw);
45   draw->pipeline.stipple   = draw_stipple_stage(draw);
46   draw->pipeline.unfilled  = draw_unfilled_stage(draw);
47   draw->pipeline.twoside   = draw_twoside_stage(draw);
48   draw->pipeline.offset    = draw_offset_stage(draw);
49   draw->pipeline.clip      = draw_clip_stage(draw);
50   draw->pipeline.flatshade = draw_flatshade_stage(draw);
51   draw->pipeline.cull      = draw_cull_stage(draw);
52   draw->pipeline.user_cull = draw_user_cull_stage(draw);
53   draw->pipeline.validate  = draw_validate_stage(draw);
54   draw->pipeline.first     = draw->pipeline.validate;
55
56   if (!draw->pipeline.wide_line ||
57       !draw->pipeline.wide_point ||
58       !draw->pipeline.stipple ||
59       !draw->pipeline.unfilled ||
60       !draw->pipeline.twoside ||
61       !draw->pipeline.offset ||
62       !draw->pipeline.clip ||
63       !draw->pipeline.flatshade ||
64       !draw->pipeline.cull ||
65       !draw->pipeline.user_cull ||
66       !draw->pipeline.validate)
67      return FALSE;
68
69   /* these defaults are oriented toward the needs of softpipe */
70   draw->pipeline.wide_point_threshold = 1000000.0f; /* infinity */
71   draw->pipeline.wide_line_threshold = 1.0f;
72   draw->pipeline.wide_point_sprites = FALSE;
73   draw->pipeline.line_stipple = TRUE;
74   draw->pipeline.point_sprite = TRUE;
75
76   return TRUE;
77}
78
79
80void
81draw_pipeline_destroy(struct draw_context *draw)
82{
83   if (draw->pipeline.wide_line)
84      draw->pipeline.wide_line->destroy(draw->pipeline.wide_line);
85   if (draw->pipeline.wide_point)
86      draw->pipeline.wide_point->destroy(draw->pipeline.wide_point);
87   if (draw->pipeline.stipple)
88      draw->pipeline.stipple->destroy(draw->pipeline.stipple);
89   if (draw->pipeline.unfilled)
90      draw->pipeline.unfilled->destroy(draw->pipeline.unfilled);
91   if (draw->pipeline.twoside)
92      draw->pipeline.twoside->destroy(draw->pipeline.twoside);
93   if (draw->pipeline.offset)
94      draw->pipeline.offset->destroy(draw->pipeline.offset);
95   if (draw->pipeline.clip)
96      draw->pipeline.clip->destroy(draw->pipeline.clip);
97   if (draw->pipeline.flatshade)
98      draw->pipeline.flatshade->destroy(draw->pipeline.flatshade);
99   if (draw->pipeline.cull)
100      draw->pipeline.cull->destroy(draw->pipeline.cull);
101   if (draw->pipeline.user_cull)
102      draw->pipeline.user_cull->destroy(draw->pipeline.user_cull);
103   if (draw->pipeline.validate)
104      draw->pipeline.validate->destroy(draw->pipeline.validate);
105   if (draw->pipeline.aaline)
106      draw->pipeline.aaline->destroy(draw->pipeline.aaline);
107   if (draw->pipeline.aapoint)
108      draw->pipeline.aapoint->destroy(draw->pipeline.aapoint);
109   if (draw->pipeline.pstipple)
110      draw->pipeline.pstipple->destroy(draw->pipeline.pstipple);
111   if (draw->pipeline.rasterize)
112      draw->pipeline.rasterize->destroy(draw->pipeline.rasterize);
113}
114
115
116/**
117 * Build primitive to render a point with vertex at v0.
118 */
119static void
120do_point(struct draw_context *draw,
121         const char *v0)
122{
123   struct prim_header prim;
124
125   prim.flags = 0;
126   prim.pad = 0;
127   prim.v[0] = (struct vertex_header *)v0;
128
129   draw->pipeline.first->point(draw->pipeline.first, &prim);
130}
131
132
133/**
134 * Build primitive to render a line with vertices at v0, v1.
135 * \param flags  bitmask of DRAW_PIPE_EDGE_x, DRAW_PIPE_RESET_STIPPLE
136 */
137static void
138do_line(struct draw_context *draw,
139        ushort flags,
140        const char *v0,
141        const char *v1)
142{
143   struct prim_header prim;
144
145   prim.flags = flags;
146   prim.pad = 0;
147   prim.v[0] = (struct vertex_header *)v0;
148   prim.v[1] = (struct vertex_header *)v1;
149
150   draw->pipeline.first->line(draw->pipeline.first, &prim);
151}
152
153
154/**
155 * Build primitive to render a triangle with vertices at v0, v1, v2.
156 * \param flags  bitmask of DRAW_PIPE_EDGE_x, DRAW_PIPE_RESET_STIPPLE
157 */
158static void
159do_triangle(struct draw_context *draw,
160            ushort flags,
161            char *v0,
162            char *v1,
163            char *v2)
164{
165   struct prim_header prim;
166
167   prim.v[0] = (struct vertex_header *)v0;
168   prim.v[1] = (struct vertex_header *)v1;
169   prim.v[2] = (struct vertex_header *)v2;
170   prim.flags = flags;
171   prim.pad = 0;
172
173   draw->pipeline.first->tri(draw->pipeline.first, &prim);
174}
175
176
177/*
178 * Set up macros for draw_pt_decompose.h template code.
179 * This code uses vertex indexes / elements.
180 */
181
182#define TRIANGLE(flags,i0,i1,i2)                                 \
183   do {                                                          \
184      do_triangle(draw,                                          \
185                  flags,                                         \
186                  verts + stride * (i0),                         \
187                  verts + stride * (i1),                         \
188                  verts + stride * (i2));                        \
189   } while (0)
190
191#define LINE(flags,i0,i1)                                         \
192   do {                                                           \
193      do_line(draw,                                               \
194              flags,                                              \
195              verts + stride * (i0),                              \
196              verts + stride * (i1));                             \
197   } while (0)
198
199#define POINT(i0)                              \
200   do {                                        \
201      do_point(draw, verts + stride * (i0));   \
202   } while (0)
203
204#define GET_ELT(idx) (MIN2(elts[idx], max_index))
205
206#define FUNC pipe_run_elts
207#define FUNC_VARS                               \
208    struct draw_context *draw,                  \
209    enum pipe_prim_type prim,                   \
210    unsigned prim_flags,                        \
211    struct vertex_header *vertices,             \
212    unsigned stride,                            \
213    const ushort *elts,                         \
214    unsigned count,                             \
215    unsigned max_index
216
217#include "draw_pt_decompose.h"
218
219
220
221/**
222 * Code to run the pipeline on a fairly arbitrary collection of vertices.
223 * For drawing indexed primitives.
224 *
225 * Vertex headers must be pre-initialized with the
226 * UNDEFINED_VERTEX_ID, this code will cause that id to become
227 * overwritten, so it may have to be reset if there is the intention
228 * to reuse the vertices.
229 *
230 * This code provides a callback to reset the vertex id's which the
231 * draw_vbuf.c code uses when it has to perform a flush.
232 */
233void
234draw_pipeline_run(struct draw_context *draw,
235                  const struct draw_vertex_info *vert_info,
236                  const struct draw_prim_info *prim_info)
237{
238   draw->pipeline.verts = (char *)vert_info->verts;
239   draw->pipeline.vertex_stride = vert_info->stride;
240   draw->pipeline.vertex_count = vert_info->count;
241
242   unsigned i, start;
243   for (start = i = 0;
244        i < prim_info->primitive_count;
245        start += prim_info->primitive_lengths[i], i++) {
246      const unsigned count = prim_info->primitive_lengths[i];
247
248#if DEBUG
249      /* Warn if one of the element indexes go outside the vertex buffer */
250      {
251         unsigned max_index = 0x0;
252         /* find the largest element index */
253         for (unsigned i = 0; i < count; i++) {
254            unsigned int index = prim_info->elts[start + i];
255            if (index > max_index)
256               max_index = index;
257         }
258         if (max_index >= vert_info->count) {
259            debug_printf("%s: max_index (%u) outside vertex buffer (%u)\n",
260                         __FUNCTION__,
261                         max_index,
262                         vert_info->count);
263         }
264      }
265#endif
266
267      pipe_run_elts(draw,
268                    prim_info->prim,
269                    prim_info->flags,
270                    vert_info->verts,
271                    vert_info->stride,
272                    prim_info->elts + start,
273                    count,
274                    vert_info->count - 1);
275   }
276
277   draw->pipeline.verts = NULL;
278   draw->pipeline.vertex_count = 0;
279}
280
281
282/*
283 * Set up macros for draw_pt_decompose.h template code.
284 * This code is for non-indexed (aka linear) rendering (no elts).
285 */
286
287#define TRIANGLE(flags,i0,i1,i2)       \
288   do_triangle(draw, flags,            \
289                verts + stride * (i0), \
290                verts + stride * (i1), \
291                verts + stride * (i2))
292
293#define LINE(flags,i0,i1)              \
294   do_line(draw, flags,                \
295            verts + stride * (i0),     \
296            verts + stride * (i1))
297
298#define POINT(i0)                      \
299   do_point(draw, verts + stride * (i0))
300
301
302#define GET_ELT(idx) (idx)
303
304#define FUNC pipe_run_linear
305#define FUNC_VARS                      \
306    struct draw_context *draw,         \
307    enum pipe_prim_type prim,          \
308    unsigned prim_flags,               \
309    struct vertex_header *vertices,    \
310    unsigned stride,                   \
311    unsigned count
312
313#include "draw_pt_decompose.h"
314
315
316/*
317 * For drawing non-indexed primitives.
318 */
319void
320draw_pipeline_run_linear(struct draw_context *draw,
321                         const struct draw_vertex_info *vert_info,
322                         const struct draw_prim_info *prim_info)
323{
324   unsigned i, start;
325
326   for (start = i = 0;
327        i < prim_info->primitive_count;
328        start += prim_info->primitive_lengths[i], i++) {
329      unsigned count = prim_info->primitive_lengths[i];
330      char *verts = ((char*)vert_info->verts) +
331                    (start * vert_info->stride);
332
333      draw->pipeline.verts = verts;
334      draw->pipeline.vertex_stride = vert_info->stride;
335      draw->pipeline.vertex_count = count;
336
337      assert(count <= vert_info->count);
338
339      pipe_run_linear(draw,
340                      prim_info->prim,
341                      prim_info->flags,
342                      (struct vertex_header*)verts,
343                      vert_info->stride,
344                      count);
345   }
346
347   draw->pipeline.verts = NULL;
348   draw->pipeline.vertex_count = 0;
349}
350
351
352void
353draw_pipeline_flush(struct draw_context *draw,
354                    unsigned flags)
355{
356   draw->pipeline.first->flush(draw->pipeline.first, flags);
357   if (flags & DRAW_FLUSH_STATE_CHANGE)
358      draw->pipeline.first = draw->pipeline.validate;
359}
360