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