draw_pipe_validate.c revision a7ea4d11fb5a2a39daaad8752706291ac93013f7
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 38static boolean points( unsigned prim ) 39{ 40 return (prim == PIPE_PRIM_POINTS); 41} 42 43static 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 50static 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 */ 63boolean 64draw_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 /* sprite points */ 104 if (rasterizer->point_quad_rasterization 105 && draw->pipeline.wide_point_sprites) 106 return TRUE; 107 108 /* AA points */ 109 if (rasterizer->point_smooth && draw->pipeline.aapoint) 110 return TRUE; 111 112 /* point sprites */ 113 if (rasterizer->sprite_coord_enable && draw->pipeline.point_sprite) 114 return TRUE; 115 } 116 117 118 if (triangles(prim)) 119 { 120 /* polygon stipple */ 121 if (rasterizer->poly_stipple_enable && draw->pipeline.pstipple) 122 return TRUE; 123 124 /* unfilled polygons */ 125 if (rasterizer->fill_front != PIPE_POLYGON_MODE_FILL || 126 rasterizer->fill_back != PIPE_POLYGON_MODE_FILL) 127 return TRUE; 128 129 /* polygon offset */ 130 if (rasterizer->offset_point || 131 rasterizer->offset_line || 132 rasterizer->offset_tri) 133 return TRUE; 134 135 /* two-side lighting */ 136 if (rasterizer->light_twoside) 137 return TRUE; 138 } 139 140 /* polygon cull - this is difficult - hardware can cull just fine 141 * most of the time (though sometimes CULL_NEITHER is unsupported. 142 * 143 * Generally this isn't a reason to require the pipeline, though. 144 * 145 if (rasterizer->cull_mode) 146 return TRUE; 147 */ 148 149 return FALSE; 150} 151 152 153 154/** 155 * Rebuild the rendering pipeline. 156 */ 157static struct draw_stage *validate_pipeline( struct draw_stage *stage ) 158{ 159 struct draw_context *draw = stage->draw; 160 struct draw_stage *next = draw->pipeline.rasterize; 161 boolean need_det = FALSE; 162 boolean precalc_flat = FALSE; 163 boolean wide_lines, wide_points; 164 const struct pipe_rasterizer_state *rast = draw->rasterizer; 165 166 /* Set the validate's next stage to the rasterize stage, so that it 167 * can be found later if needed for flushing. 168 */ 169 stage->next = next; 170 171 /* drawing wide lines? */ 172 wide_lines = (rast->line_width > draw->pipeline.wide_line_threshold 173 && !rast->line_smooth); 174 175 /* drawing large/sprite points (but not AA points)? */ 176 if (rast->sprite_coord_enable && draw->pipeline.point_sprite) 177 wide_points = TRUE; 178 else if (rast->point_smooth && draw->pipeline.aapoint) 179 wide_points = FALSE; 180 else if (rast->point_size > draw->pipeline.wide_point_threshold) 181 wide_points = TRUE; 182 else if (rast->point_quad_rasterization && draw->pipeline.wide_point_sprites) 183 wide_points = TRUE; 184 else 185 wide_points = FALSE; 186 187 /* 188 * NOTE: we build up the pipeline in end-to-start order. 189 * 190 * TODO: make the current primitive part of the state and build 191 * shorter pipelines for lines & points. 192 */ 193 194 if (rast->line_smooth && draw->pipeline.aaline) { 195 draw->pipeline.aaline->next = next; 196 next = draw->pipeline.aaline; 197 } 198 199 if (rast->point_smooth && draw->pipeline.aapoint) { 200 draw->pipeline.aapoint->next = next; 201 next = draw->pipeline.aapoint; 202 } 203 204 if (wide_lines) { 205 draw->pipeline.wide_line->next = next; 206 next = draw->pipeline.wide_line; 207 precalc_flat = TRUE; 208 } 209 210 if (wide_points) { 211 draw->pipeline.wide_point->next = next; 212 next = draw->pipeline.wide_point; 213 } 214 215 if (rast->line_stipple_enable && draw->pipeline.line_stipple) { 216 draw->pipeline.stipple->next = next; 217 next = draw->pipeline.stipple; 218 precalc_flat = TRUE; /* only needed for lines really */ 219 } 220 221 if (rast->poly_stipple_enable 222 && draw->pipeline.pstipple) { 223 draw->pipeline.pstipple->next = next; 224 next = draw->pipeline.pstipple; 225 } 226 227 if (rast->fill_front != PIPE_POLYGON_MODE_FILL || 228 rast->fill_back != PIPE_POLYGON_MODE_FILL) { 229 draw->pipeline.unfilled->next = next; 230 next = draw->pipeline.unfilled; 231 precalc_flat = TRUE; /* only needed for triangles really */ 232 need_det = TRUE; 233 } 234 235 if (rast->flatshade && precalc_flat) { 236 draw->pipeline.flatshade->next = next; 237 next = draw->pipeline.flatshade; 238 } 239 240 if (rast->offset_point || 241 rast->offset_line || 242 rast->offset_tri) { 243 draw->pipeline.offset->next = next; 244 next = draw->pipeline.offset; 245 need_det = TRUE; 246 } 247 248 if (rast->light_twoside) { 249 draw->pipeline.twoside->next = next; 250 next = draw->pipeline.twoside; 251 need_det = TRUE; 252 } 253 254 /* Always run the cull stage as we calculate determinant there 255 * also. 256 * 257 * This can actually be a win as culling out the triangles can lead 258 * to less work emitting vertices, smaller vertex buffers, etc. 259 * It's difficult to say whether this will be true in general. 260 */ 261 if (need_det || rast->cull_face != PIPE_FACE_NONE) { 262 draw->pipeline.cull->next = next; 263 next = draw->pipeline.cull; 264 } 265 266 /* Clip stage 267 */ 268 if (draw->clip_xy || draw->clip_z || draw->clip_user) 269 { 270 draw->pipeline.clip->next = next; 271 next = draw->pipeline.clip; 272 } 273 274 275 draw->pipeline.first = next; 276 277 if (0) { 278 debug_printf("draw pipeline:\n"); 279 for (next = draw->pipeline.first; next ; next = next->next ) 280 debug_printf(" %s\n", next->name); 281 debug_printf("\n"); 282 } 283 284 return draw->pipeline.first; 285} 286 287static void validate_tri( struct draw_stage *stage, 288 struct prim_header *header ) 289{ 290 struct draw_stage *pipeline = validate_pipeline( stage ); 291 pipeline->tri( pipeline, header ); 292} 293 294static void validate_line( struct draw_stage *stage, 295 struct prim_header *header ) 296{ 297 struct draw_stage *pipeline = validate_pipeline( stage ); 298 pipeline->line( pipeline, header ); 299} 300 301static void validate_point( struct draw_stage *stage, 302 struct prim_header *header ) 303{ 304 struct draw_stage *pipeline = validate_pipeline( stage ); 305 pipeline->point( pipeline, header ); 306} 307 308static void validate_reset_stipple_counter( struct draw_stage *stage ) 309{ 310 struct draw_stage *pipeline = validate_pipeline( stage ); 311 pipeline->reset_stipple_counter( pipeline ); 312} 313 314static void validate_flush( struct draw_stage *stage, 315 unsigned flags ) 316{ 317 /* May need to pass a backend flush on to the rasterize stage. 318 */ 319 if (stage->next) 320 stage->next->flush( stage->next, flags ); 321} 322 323 324static void validate_destroy( struct draw_stage *stage ) 325{ 326 FREE( stage ); 327} 328 329 330/** 331 * Create validate pipeline stage. 332 */ 333struct draw_stage *draw_validate_stage( struct draw_context *draw ) 334{ 335 struct draw_stage *stage = CALLOC_STRUCT(draw_stage); 336 if (stage == NULL) 337 return NULL; 338 339 stage->draw = draw; 340 stage->name = "validate"; 341 stage->next = NULL; 342 stage->point = validate_point; 343 stage->line = validate_line; 344 stage->tri = validate_tri; 345 stage->flush = validate_flush; 346 stage->reset_stipple_counter = validate_reset_stipple_counter; 347 stage->destroy = validate_destroy; 348 349 return stage; 350} 351