draw_pipe_validate.c revision 4f25420bdd834e81a3e22733304efc5261c2998a
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/* Authors:  Keith Whitwell <keith@tungstengraphics.com>
29 */
30
31#include "util/u_memory.h"
32#include "pipe/p_defines.h"
33#include "draw_private.h"
34#include "draw_pipe.h"
35#include "draw_context.h"
36
37static boolean points( unsigned prim )
38{
39   return (prim == PIPE_PRIM_POINTS);
40}
41
42static boolean lines( unsigned prim )
43{
44   return (prim == PIPE_PRIM_LINES ||
45           prim == PIPE_PRIM_LINE_STRIP ||
46           prim == PIPE_PRIM_LINE_LOOP);
47}
48
49static boolean triangles( unsigned prim )
50{
51   return prim >= PIPE_PRIM_TRIANGLES;
52}
53
54/**
55 * Check if we need any special pipeline stages, or whether
56 * prims/verts can go through untouched.  Don't test for bypass
57 * clipping or vs modes, this function is just about the primitive
58 * pipeline stages.
59 */
60boolean
61draw_need_pipeline(const struct draw_context *draw,
62                   const struct pipe_rasterizer_state *rasterizer,
63                   unsigned int prim )
64{
65   /* Don't have to worry about triangles turning into lines/points
66    * and triggering the pipeline, because we have to trigger the
67    * pipeline *anyway* if unfilled mode is active.
68    */
69   if (lines(prim))
70   {
71      /* line stipple */
72      if (rasterizer->line_stipple_enable && draw->pipeline.line_stipple)
73         return TRUE;
74
75      /* wide lines */
76      if (rasterizer->line_width > draw->pipeline.wide_line_threshold)
77         return TRUE;
78
79      /* AA lines */
80      if (rasterizer->line_smooth && draw->pipeline.aaline)
81         return TRUE;
82   }
83
84   if (points(prim))
85   {
86      /* large points */
87      if (rasterizer->point_size > draw->pipeline.wide_point_threshold)
88         return TRUE;
89
90      /* AA points */
91      if (rasterizer->point_smooth && draw->pipeline.aapoint)
92         return TRUE;
93
94      /* point sprites */
95      if (rasterizer->point_sprite && draw->pipeline.point_sprite)
96         return TRUE;
97   }
98
99
100   if (triangles(prim))
101   {
102      /* polygon stipple */
103      if (rasterizer->poly_stipple_enable && draw->pipeline.pstipple)
104         return TRUE;
105
106      /* unfilled polygons */
107      if (rasterizer->fill_cw != PIPE_POLYGON_MODE_FILL ||
108          rasterizer->fill_ccw != PIPE_POLYGON_MODE_FILL)
109         return TRUE;
110
111      /* polygon offset */
112      if (rasterizer->offset_cw || rasterizer->offset_ccw)
113         return TRUE;
114
115      /* two-side lighting */
116      if (rasterizer->light_twoside)
117         return TRUE;
118   }
119
120   /* polygon cull - this is difficult - hardware can cull just fine
121    * most of the time (though sometimes CULL_NEITHER is unsupported.
122    *
123    * Generally this isn't a reason to require the pipeline, though.
124    *
125   if (rasterizer->cull_mode)
126      return TRUE;
127    */
128
129   return FALSE;
130}
131
132
133
134/**
135 * Rebuild the rendering pipeline.
136 */
137static struct draw_stage *validate_pipeline( struct draw_stage *stage )
138{
139   struct draw_context *draw = stage->draw;
140   struct draw_stage *next = draw->pipeline.rasterize;
141   int need_det = 0;
142   int precalc_flat = 0;
143   boolean wide_lines, wide_points;
144
145   /* Set the validate's next stage to the rasterize stage, so that it
146    * can be found later if needed for flushing.
147    */
148   stage->next = next;
149
150   /* drawing wide lines? */
151   wide_lines = (draw->rasterizer->line_width > draw->pipeline.wide_line_threshold
152                 && !draw->rasterizer->line_smooth);
153
154   /* drawing large points? */
155   if (draw->rasterizer->point_sprite && draw->pipeline.point_sprite)
156      wide_points = TRUE;
157   else if (draw->rasterizer->point_smooth && draw->pipeline.aapoint)
158      wide_points = FALSE;
159   else if (draw->rasterizer->point_size > draw->pipeline.wide_point_threshold)
160      wide_points = TRUE;
161   else
162      wide_points = FALSE;
163
164   /*
165    * NOTE: we build up the pipeline in end-to-start order.
166    *
167    * TODO: make the current primitive part of the state and build
168    * shorter pipelines for lines & points.
169    */
170
171   if (draw->rasterizer->line_smooth && draw->pipeline.aaline) {
172      draw->pipeline.aaline->next = next;
173      next = draw->pipeline.aaline;
174   }
175
176   if (draw->rasterizer->point_smooth && draw->pipeline.aapoint) {
177      draw->pipeline.aapoint->next = next;
178      next = draw->pipeline.aapoint;
179   }
180
181   if (wide_lines) {
182      draw->pipeline.wide_line->next = next;
183      next = draw->pipeline.wide_line;
184      precalc_flat = 1;
185   }
186
187   if (wide_points || draw->rasterizer->point_sprite) {
188      draw->pipeline.wide_point->next = next;
189      next = draw->pipeline.wide_point;
190   }
191
192   if (draw->rasterizer->line_stipple_enable && draw->pipeline.line_stipple) {
193      draw->pipeline.stipple->next = next;
194      next = draw->pipeline.stipple;
195      precalc_flat = 1;		/* only needed for lines really */
196   }
197
198   if (draw->rasterizer->poly_stipple_enable
199       && draw->pipeline.pstipple) {
200      draw->pipeline.pstipple->next = next;
201      next = draw->pipeline.pstipple;
202   }
203
204   if (draw->rasterizer->fill_cw != PIPE_POLYGON_MODE_FILL ||
205       draw->rasterizer->fill_ccw != PIPE_POLYGON_MODE_FILL) {
206      draw->pipeline.unfilled->next = next;
207      next = draw->pipeline.unfilled;
208      precalc_flat = 1;		/* only needed for triangles really */
209      need_det = 1;
210   }
211
212   if (draw->rasterizer->flatshade && precalc_flat) {
213      draw->pipeline.flatshade->next = next;
214      next = draw->pipeline.flatshade;
215   }
216
217   if (draw->rasterizer->offset_cw ||
218       draw->rasterizer->offset_ccw) {
219      draw->pipeline.offset->next = next;
220      next = draw->pipeline.offset;
221      need_det = 1;
222   }
223
224   if (draw->rasterizer->light_twoside) {
225      draw->pipeline.twoside->next = next;
226      next = draw->pipeline.twoside;
227      need_det = 1;
228   }
229
230   /* Always run the cull stage as we calculate determinant there
231    * also.
232    *
233    * This can actually be a win as culling out the triangles can lead
234    * to less work emitting vertices, smaller vertex buffers, etc.
235    * It's difficult to say whether this will be true in general.
236    */
237   if (need_det || draw->rasterizer->cull_mode) {
238      draw->pipeline.cull->next = next;
239      next = draw->pipeline.cull;
240   }
241
242   /* Clip stage
243    */
244   if (!draw->bypass_clipping)
245   {
246      draw->pipeline.clip->next = next;
247      next = draw->pipeline.clip;
248   }
249
250
251   draw->pipeline.first = next;
252   return next;
253}
254
255static void validate_tri( struct draw_stage *stage,
256			  struct prim_header *header )
257{
258   struct draw_stage *pipeline = validate_pipeline( stage );
259   pipeline->tri( pipeline, header );
260}
261
262static void validate_line( struct draw_stage *stage,
263			   struct prim_header *header )
264{
265   struct draw_stage *pipeline = validate_pipeline( stage );
266   pipeline->line( pipeline, header );
267}
268
269static void validate_point( struct draw_stage *stage,
270			    struct prim_header *header )
271{
272   struct draw_stage *pipeline = validate_pipeline( stage );
273   pipeline->point( pipeline, header );
274}
275
276static void validate_reset_stipple_counter( struct draw_stage *stage )
277{
278   struct draw_stage *pipeline = validate_pipeline( stage );
279   pipeline->reset_stipple_counter( pipeline );
280}
281
282static void validate_flush( struct draw_stage *stage,
283			    unsigned flags )
284{
285   /* May need to pass a backend flush on to the rasterize stage.
286    */
287   if (stage->next)
288      stage->next->flush( stage->next, flags );
289}
290
291
292static void validate_destroy( struct draw_stage *stage )
293{
294   FREE( stage );
295}
296
297
298/**
299 * Create validate pipeline stage.
300 */
301struct draw_stage *draw_validate_stage( struct draw_context *draw )
302{
303   struct draw_stage *stage = CALLOC_STRUCT(draw_stage);
304   if (stage == NULL)
305      return NULL;
306
307   stage->draw = draw;
308   stage->next = NULL;
309   stage->point = validate_point;
310   stage->line = validate_line;
311   stage->tri = validate_tri;
312   stage->flush = validate_flush;
313   stage->reset_stipple_counter = validate_reset_stipple_counter;
314   stage->destroy = validate_destroy;
315
316   return stage;
317}
318