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