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