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 39 struct 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 54 static 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->guard_band_xy, 107 draw->identity_viewport, 108 (boolean)draw->rasterizer->gl_rasterization_rules, 109 (draw->vs.edgeflag_output ? TRUE : FALSE) ); 110 111 draw_pt_so_emit_prepare( fpme->so_emit ); 112 113 if (!(opt & PT_PIPELINE)) { 114 draw_pt_emit_prepare( fpme->emit, 115 gs_out_prim, 116 max_vertices ); 117 118 *max_vertices = MAX2( *max_vertices, 4096 ); 119 } 120 else { 121 /* limit max fetches by limiting max_vertices */ 122 *max_vertices = 4096; 123 } 124 125 /* No need to prepare the shader. 126 */ 127 vs->prepare(vs, draw); 128 } 129 130 131 static void fetch( struct pt_fetch *fetch, 132 const struct draw_fetch_info *fetch_info, 133 char *output) 134 { 135 if (fetch_info->linear) { 136 draw_pt_fetch_run_linear( fetch, 137 fetch_info->start, 138 fetch_info->count, 139 output ); 140 } 141 else { 142 draw_pt_fetch_run( fetch, 143 fetch_info->elts, 144 fetch_info->count, 145 output ); 146 } 147 } 148 149 150 static void pipeline(struct fetch_pipeline_middle_end *fpme, 151 const struct draw_vertex_info *vert_info, 152 const struct draw_prim_info *prim_info) 153 { 154 if (prim_info->linear) 155 draw_pipeline_run_linear( fpme->draw, 156 vert_info, 157 prim_info); 158 else 159 draw_pipeline_run( fpme->draw, 160 vert_info, 161 prim_info ); 162 } 163 164 static void emit(struct pt_emit *emit, 165 const struct draw_vertex_info *vert_info, 166 const struct draw_prim_info *prim_info) 167 { 168 if (prim_info->linear) { 169 draw_pt_emit_linear(emit, vert_info, prim_info); 170 } 171 else { 172 draw_pt_emit(emit, vert_info, prim_info); 173 } 174 } 175 176 177 static void draw_vertex_shader_run(struct draw_vertex_shader *vshader, 178 const void *constants[PIPE_MAX_CONSTANT_BUFFERS], 179 unsigned const_size[PIPE_MAX_CONSTANT_BUFFERS], 180 const struct draw_vertex_info *input_verts, 181 struct draw_vertex_info *output_verts ) 182 { 183 output_verts->vertex_size = input_verts->vertex_size; 184 output_verts->stride = input_verts->vertex_size; 185 output_verts->count = input_verts->count; 186 output_verts->verts = 187 (struct vertex_header *)MALLOC(output_verts->vertex_size * 188 align(output_verts->count, 4)); 189 190 vshader->run_linear(vshader, 191 (const float (*)[4])input_verts->verts->data, 192 ( float (*)[4])output_verts->verts->data, 193 constants, 194 const_size, 195 input_verts->count, 196 input_verts->vertex_size, 197 input_verts->vertex_size); 198 } 199 200 static void fetch_pipeline_generic( struct draw_pt_middle_end *middle, 201 const struct draw_fetch_info *fetch_info, 202 const struct draw_prim_info *prim_info ) 203 { 204 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 205 struct draw_context *draw = fpme->draw; 206 struct draw_vertex_shader *vshader = draw->vs.vertex_shader; 207 struct draw_geometry_shader *gshader = draw->gs.geometry_shader; 208 struct draw_prim_info gs_prim_info; 209 struct draw_vertex_info fetched_vert_info; 210 struct draw_vertex_info vs_vert_info; 211 struct draw_vertex_info gs_vert_info; 212 struct draw_vertex_info *vert_info; 213 unsigned opt = fpme->opt; 214 215 fetched_vert_info.count = fetch_info->count; 216 fetched_vert_info.vertex_size = fpme->vertex_size; 217 fetched_vert_info.stride = fpme->vertex_size; 218 fetched_vert_info.verts = 219 (struct vertex_header *)MALLOC(fpme->vertex_size * 220 align(fetch_info->count, 4)); 221 if (!fetched_vert_info.verts) { 222 assert(0); 223 return; 224 } 225 226 /* Fetch into our vertex buffer. 227 */ 228 fetch( fpme->fetch, fetch_info, (char *)fetched_vert_info.verts ); 229 230 /* Finished with fetch: 231 */ 232 fetch_info = NULL; 233 vert_info = &fetched_vert_info; 234 235 /* Run the shader, note that this overwrites the data[] parts of 236 * the pipeline verts. 237 */ 238 if (fpme->opt & PT_SHADE) { 239 draw_vertex_shader_run(vshader, 240 draw->pt.user.vs_constants, 241 draw->pt.user.vs_constants_size, 242 vert_info, 243 &vs_vert_info); 244 245 FREE(vert_info->verts); 246 vert_info = &vs_vert_info; 247 } 248 249 if ((fpme->opt & PT_SHADE) && gshader) { 250 draw_geometry_shader_run(gshader, 251 draw->pt.user.gs_constants, 252 draw->pt.user.gs_constants_size, 253 vert_info, 254 prim_info, 255 &gs_vert_info, 256 &gs_prim_info); 257 258 FREE(vert_info->verts); 259 vert_info = &gs_vert_info; 260 prim_info = &gs_prim_info; 261 } 262 263 264 /* Stream output needs to be done before clipping. 265 * 266 * XXX: Stream output surely needs to respect the prim_info->elt 267 * lists. 268 */ 269 draw_pt_so_emit( fpme->so_emit, 270 vert_info, 271 prim_info ); 272 273 if (draw_pt_post_vs_run( fpme->post_vs, 274 vert_info )) 275 { 276 opt |= PT_PIPELINE; 277 } 278 279 /* Do we need to run the pipeline? 280 */ 281 if (opt & PT_PIPELINE) { 282 pipeline( fpme, 283 vert_info, 284 prim_info ); 285 } 286 else { 287 emit( fpme->emit, 288 vert_info, 289 prim_info ); 290 } 291 FREE(vert_info->verts); 292 } 293 294 static void fetch_pipeline_run( struct draw_pt_middle_end *middle, 295 const unsigned *fetch_elts, 296 unsigned fetch_count, 297 const ushort *draw_elts, 298 unsigned draw_count, 299 unsigned prim_flags ) 300 { 301 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 302 struct draw_fetch_info fetch_info; 303 struct draw_prim_info prim_info; 304 305 fetch_info.linear = FALSE; 306 fetch_info.start = 0; 307 fetch_info.elts = fetch_elts; 308 fetch_info.count = fetch_count; 309 310 prim_info.linear = FALSE; 311 prim_info.start = 0; 312 prim_info.count = draw_count; 313 prim_info.elts = draw_elts; 314 prim_info.prim = fpme->input_prim; 315 prim_info.flags = prim_flags; 316 prim_info.primitive_count = 1; 317 prim_info.primitive_lengths = &draw_count; 318 319 fetch_pipeline_generic( middle, &fetch_info, &prim_info ); 320 } 321 322 323 static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, 324 unsigned start, 325 unsigned count, 326 unsigned prim_flags) 327 { 328 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 329 struct draw_fetch_info fetch_info; 330 struct draw_prim_info prim_info; 331 332 fetch_info.linear = TRUE; 333 fetch_info.start = start; 334 fetch_info.count = count; 335 fetch_info.elts = NULL; 336 337 prim_info.linear = TRUE; 338 prim_info.start = 0; 339 prim_info.count = count; 340 prim_info.elts = NULL; 341 prim_info.prim = fpme->input_prim; 342 prim_info.flags = prim_flags; 343 prim_info.primitive_count = 1; 344 prim_info.primitive_lengths = &count; 345 346 fetch_pipeline_generic( middle, &fetch_info, &prim_info ); 347 } 348 349 350 351 static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle, 352 unsigned start, 353 unsigned count, 354 const ushort *draw_elts, 355 unsigned draw_count, 356 unsigned prim_flags ) 357 { 358 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 359 struct draw_fetch_info fetch_info; 360 struct draw_prim_info prim_info; 361 362 fetch_info.linear = TRUE; 363 fetch_info.start = start; 364 fetch_info.count = count; 365 fetch_info.elts = NULL; 366 367 prim_info.linear = FALSE; 368 prim_info.start = 0; 369 prim_info.count = draw_count; 370 prim_info.elts = draw_elts; 371 prim_info.prim = fpme->input_prim; 372 prim_info.flags = prim_flags; 373 prim_info.primitive_count = 1; 374 prim_info.primitive_lengths = &draw_count; 375 376 fetch_pipeline_generic( middle, &fetch_info, &prim_info ); 377 378 return TRUE; 379 } 380 381 382 383 static void fetch_pipeline_finish( struct draw_pt_middle_end *middle ) 384 { 385 /* nothing to do */ 386 } 387 388 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) 389 { 390 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 391 392 if (fpme->fetch) 393 draw_pt_fetch_destroy( fpme->fetch ); 394 395 if (fpme->emit) 396 draw_pt_emit_destroy( fpme->emit ); 397 398 if (fpme->so_emit) 399 draw_pt_so_emit_destroy( fpme->so_emit ); 400 401 if (fpme->post_vs) 402 draw_pt_post_vs_destroy( fpme->post_vs ); 403 404 FREE(middle); 405 } 406 407 408 struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw ) 409 { 410 struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end ); 411 if (!fpme) 412 goto fail; 413 414 fpme->base.prepare = fetch_pipeline_prepare; 415 fpme->base.run = fetch_pipeline_run; 416 fpme->base.run_linear = fetch_pipeline_linear_run; 417 fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts; 418 fpme->base.finish = fetch_pipeline_finish; 419 fpme->base.destroy = fetch_pipeline_destroy; 420 421 fpme->draw = draw; 422 423 fpme->fetch = draw_pt_fetch_create( draw ); 424 if (!fpme->fetch) 425 goto fail; 426 427 fpme->post_vs = draw_pt_post_vs_create( draw ); 428 if (!fpme->post_vs) 429 goto fail; 430 431 fpme->emit = draw_pt_emit_create( draw ); 432 if (!fpme->emit) 433 goto fail; 434 435 fpme->so_emit = draw_pt_so_emit_create( draw ); 436 if (!fpme->so_emit) 437 goto fail; 438 439 return &fpme->base; 440 441 fail: 442 if (fpme) 443 fetch_pipeline_destroy( &fpme->base ); 444 445 return NULL; 446 } 447