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