draw_pt_fetch_shade_pipeline.c revision 543b9566bdaa48fea2df1866fa1310c1cdbcde27
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#include "util/u_math.h" 29#include "util/u_memory.h" 30#include "draw/draw_context.h" 31#include "draw/draw_vbuf.h" 32#include "draw/draw_vertex.h" 33#include "draw/draw_pt.h" 34#include "draw/draw_vs.h" 35#include "translate/translate.h" 36 37 38struct fetch_pipeline_middle_end { 39 struct draw_pt_middle_end base; 40 struct draw_context *draw; 41 42 struct pt_emit *emit; 43 struct pt_fetch *fetch; 44 struct pt_post_vs *post_vs; 45 46 unsigned vertex_data_offset; 47 unsigned vertex_size; 48 unsigned prim; 49 unsigned opt; 50}; 51 52 53static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, 54 unsigned prim, 55 unsigned opt, 56 unsigned *max_vertices ) 57{ 58 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 59 struct draw_context *draw = fpme->draw; 60 struct draw_vertex_shader *vs = draw->vs.vertex_shader; 61 unsigned i; 62 boolean instance_id_index = ~0; 63 64 /* Add one to num_outputs because the pipeline occasionally tags on 65 * an additional texcoord, eg for AA lines. 66 */ 67 unsigned nr = MAX2( vs->info.num_inputs, 68 vs->info.num_outputs + 1 ); 69 70 /* Scan for instanceID system value. 71 */ 72 for (i = 0; i < vs->info.num_inputs; i++) { 73 if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) { 74 instance_id_index = i; 75 break; 76 } 77 } 78 79 fpme->prim = prim; 80 fpme->opt = opt; 81 82 /* Always leave room for the vertex header whether we need it or 83 * not. It's hard to get rid of it in particular because of the 84 * viewport code in draw_pt_post_vs.c. 85 */ 86 fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float); 87 88 89 90 draw_pt_fetch_prepare( fpme->fetch, 91 vs->info.num_inputs, 92 fpme->vertex_size, 93 instance_id_index ); 94 /* XXX: it's not really gl rasterization rules we care about here, 95 * but gl vs dx9 clip spaces. 96 */ 97 draw_pt_post_vs_prepare( fpme->post_vs, 98 (boolean)draw->bypass_clipping, 99 (boolean)(draw->identity_viewport || 100 draw->rasterizer->bypass_vs_clip_and_viewport), 101 (boolean)draw->rasterizer->gl_rasterization_rules, 102 (draw->vs.edgeflag_output ? true : false) ); 103 104 if (!(opt & PT_PIPELINE)) { 105 draw_pt_emit_prepare( fpme->emit, 106 prim, 107 max_vertices ); 108 109 *max_vertices = MAX2( *max_vertices, 110 DRAW_PIPE_MAX_VERTICES ); 111 } 112 else { 113 *max_vertices = DRAW_PIPE_MAX_VERTICES; 114 } 115 116 /* return even number */ 117 *max_vertices = *max_vertices & ~1; 118 119 /* No need to prepare the shader. 120 */ 121 vs->prepare(vs, draw); 122} 123 124 125 126static void fetch_pipeline_run( struct draw_pt_middle_end *middle, 127 const unsigned *fetch_elts, 128 unsigned fetch_count, 129 const ushort *draw_elts, 130 unsigned draw_count ) 131{ 132 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 133 struct draw_context *draw = fpme->draw; 134 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 135 unsigned opt = fpme->opt; 136 unsigned alloc_count = align( fetch_count, 4 ); 137 138 struct vertex_header *pipeline_verts = 139 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 140 141 if (!pipeline_verts) { 142 /* Not much we can do here - just skip the rendering. 143 */ 144 assert(0); 145 return; 146 } 147 148 /* Fetch into our vertex buffer 149 */ 150 draw_pt_fetch_run( fpme->fetch, 151 fetch_elts, 152 fetch_count, 153 (char *)pipeline_verts ); 154 155 /* Run the shader, note that this overwrites the data[] parts of 156 * the pipeline verts. If there is no shader, eg if 157 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 158 * already in the correct place. 159 */ 160 if (opt & PT_SHADE) 161 { 162 shader->run_linear(shader, 163 (const float (*)[4])pipeline_verts->data, 164 ( float (*)[4])pipeline_verts->data, 165 (const float (*)[4])draw->pt.user.constants, 166 fetch_count, 167 fpme->vertex_size, 168 fpme->vertex_size); 169 } 170 171 if (draw_pt_post_vs_run( fpme->post_vs, 172 pipeline_verts, 173 fetch_count, 174 fpme->vertex_size )) 175 { 176 opt |= PT_PIPELINE; 177 } 178 179 /* Do we need to run the pipeline? 180 */ 181 if (opt & PT_PIPELINE) { 182 draw_pipeline_run( fpme->draw, 183 fpme->prim, 184 pipeline_verts, 185 fetch_count, 186 fpme->vertex_size, 187 draw_elts, 188 draw_count ); 189 } 190 else { 191 draw_pt_emit( fpme->emit, 192 (const float (*)[4])pipeline_verts->data, 193 fetch_count, 194 fpme->vertex_size, 195 draw_elts, 196 draw_count ); 197 } 198 199 200 FREE(pipeline_verts); 201} 202 203 204static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, 205 unsigned start, 206 unsigned count) 207{ 208 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 209 struct draw_context *draw = fpme->draw; 210 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 211 unsigned opt = fpme->opt; 212 unsigned alloc_count = align( count, 4 ); 213 214 struct vertex_header *pipeline_verts = 215 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 216 217 if (!pipeline_verts) { 218 /* Not much we can do here - just skip the rendering. 219 */ 220 assert(0); 221 return; 222 } 223 224 /* Fetch into our vertex buffer 225 */ 226 draw_pt_fetch_run_linear( fpme->fetch, 227 start, 228 count, 229 (char *)pipeline_verts ); 230 231 /* Run the shader, note that this overwrites the data[] parts of 232 * the pipeline verts. If there is no shader, ie if 233 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 234 * already in the correct place. 235 */ 236 if (opt & PT_SHADE) 237 { 238 shader->run_linear(shader, 239 (const float (*)[4])pipeline_verts->data, 240 ( float (*)[4])pipeline_verts->data, 241 (const float (*)[4])draw->pt.user.constants, 242 count, 243 fpme->vertex_size, 244 fpme->vertex_size); 245 } 246 247 if (draw_pt_post_vs_run( fpme->post_vs, 248 pipeline_verts, 249 count, 250 fpme->vertex_size )) 251 { 252 opt |= PT_PIPELINE; 253 } 254 255 /* Do we need to run the pipeline? 256 */ 257 if (opt & PT_PIPELINE) { 258 draw_pipeline_run_linear( fpme->draw, 259 fpme->prim, 260 pipeline_verts, 261 count, 262 fpme->vertex_size); 263 } 264 else { 265 draw_pt_emit_linear( fpme->emit, 266 (const float (*)[4])pipeline_verts->data, 267 fpme->vertex_size, 268 count ); 269 } 270 271 FREE(pipeline_verts); 272} 273 274 275 276static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle, 277 unsigned start, 278 unsigned count, 279 const ushort *draw_elts, 280 unsigned draw_count ) 281{ 282 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 283 struct draw_context *draw = fpme->draw; 284 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 285 unsigned opt = fpme->opt; 286 unsigned alloc_count = align( count, 4 ); 287 288 struct vertex_header *pipeline_verts = 289 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 290 291 if (!pipeline_verts) 292 return FALSE; 293 294 /* Fetch into our vertex buffer 295 */ 296 draw_pt_fetch_run_linear( fpme->fetch, 297 start, 298 count, 299 (char *)pipeline_verts ); 300 301 /* Run the shader, note that this overwrites the data[] parts of 302 * the pipeline verts. If there is no shader, ie if 303 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 304 * already in the correct place. 305 */ 306 if (opt & PT_SHADE) 307 { 308 shader->run_linear(shader, 309 (const float (*)[4])pipeline_verts->data, 310 ( float (*)[4])pipeline_verts->data, 311 (const float (*)[4])draw->pt.user.constants, 312 count, 313 fpme->vertex_size, 314 fpme->vertex_size); 315 } 316 317 if (draw_pt_post_vs_run( fpme->post_vs, 318 pipeline_verts, 319 count, 320 fpme->vertex_size )) 321 { 322 opt |= PT_PIPELINE; 323 } 324 325 /* Do we need to run the pipeline? 326 */ 327 if (opt & PT_PIPELINE) { 328 draw_pipeline_run( fpme->draw, 329 fpme->prim, 330 pipeline_verts, 331 count, 332 fpme->vertex_size, 333 draw_elts, 334 draw_count ); 335 } 336 else { 337 draw_pt_emit( fpme->emit, 338 (const float (*)[4])pipeline_verts->data, 339 count, 340 fpme->vertex_size, 341 draw_elts, 342 draw_count ); 343 } 344 345 FREE(pipeline_verts); 346 return TRUE; 347} 348 349 350 351static void fetch_pipeline_finish( struct draw_pt_middle_end *middle ) 352{ 353 /* nothing to do */ 354} 355 356static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) 357{ 358 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 359 360 if (fpme->fetch) 361 draw_pt_fetch_destroy( fpme->fetch ); 362 363 if (fpme->emit) 364 draw_pt_emit_destroy( fpme->emit ); 365 366 if (fpme->post_vs) 367 draw_pt_post_vs_destroy( fpme->post_vs ); 368 369 FREE(middle); 370} 371 372 373struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw ) 374{ 375 struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end ); 376 if (!fpme) 377 goto fail; 378 379 fpme->base.prepare = fetch_pipeline_prepare; 380 fpme->base.run = fetch_pipeline_run; 381 fpme->base.run_linear = fetch_pipeline_linear_run; 382 fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts; 383 fpme->base.finish = fetch_pipeline_finish; 384 fpme->base.destroy = fetch_pipeline_destroy; 385 386 fpme->draw = draw; 387 388 fpme->fetch = draw_pt_fetch_create( draw ); 389 if (!fpme->fetch) 390 goto fail; 391 392 fpme->post_vs = draw_pt_post_vs_create( draw ); 393 if (!fpme->post_vs) 394 goto fail; 395 396 fpme->emit = draw_pt_emit_create( draw ); 397 if (!fpme->emit) 398 goto fail; 399 400 return &fpme->base; 401 402 fail: 403 if (fpme) 404 fetch_pipeline_destroy( &fpme->base ); 405 406 return NULL; 407} 408