gallium: refactor/replace p_util.h with util/u_memory.h and util/u_math.h
[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
37 static boolean points( unsigned prim )
38 {
39 return (prim == PIPE_PRIM_POINTS);
40 }
41
42 static 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
49 static 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 */
60 boolean
61 draw_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 */
137 static 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
255 static 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
262 static 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
269 static 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
276 static 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
282 static 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
292 static void validate_destroy( struct draw_stage *stage )
293 {
294 FREE( stage );
295 }
296
297
298 /**
299 * Create validate pipeline stage.
300 */
301 struct 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 }