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