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 /* 29 * Authors: 30 * Keith Whitwell <keith (at) tungstengraphics.com> 31 */ 32 33 #include "draw/draw_context.h" 34 #include "draw/draw_gs.h" 35 #include "draw/draw_private.h" 36 #include "draw/draw_pt.h" 37 #include "draw/draw_vs.h" 38 #include "tgsi/tgsi_dump.h" 39 #include "util/u_math.h" 40 #include "util/u_prim.h" 41 #include "util/u_format.h" 42 #include "util/u_draw.h" 43 44 45 DEBUG_GET_ONCE_BOOL_OPTION(draw_fse, "DRAW_FSE", FALSE) 46 DEBUG_GET_ONCE_BOOL_OPTION(draw_no_fse, "DRAW_NO_FSE", FALSE) 47 48 /* Overall we split things into: 49 * - frontend -- prepare fetch_elts, draw_elts - eg vsplit 50 * - middle -- fetch, shade, cliptest, viewport 51 * - pipeline -- the prim pipeline: clipping, wide lines, etc 52 * - backend -- the vbuf_render provided by the driver. 53 */ 54 static boolean 55 draw_pt_arrays(struct draw_context *draw, 56 unsigned prim, 57 unsigned start, 58 unsigned count) 59 { 60 struct draw_pt_front_end *frontend = NULL; 61 struct draw_pt_middle_end *middle = NULL; 62 unsigned opt = 0; 63 64 /* Sanitize primitive length: 65 */ 66 { 67 unsigned first, incr; 68 draw_pt_split_prim(prim, &first, &incr); 69 count = draw_pt_trim_count(count, first, incr); 70 if (count < first) 71 return TRUE; 72 } 73 74 if (!draw->force_passthrough) { 75 unsigned gs_out_prim = (draw->gs.geometry_shader ? 76 draw->gs.geometry_shader->output_primitive : 77 prim); 78 79 if (!draw->render) { 80 opt |= PT_PIPELINE; 81 } 82 83 if (draw_need_pipeline(draw, 84 draw->rasterizer, 85 gs_out_prim)) { 86 opt |= PT_PIPELINE; 87 } 88 89 if ((draw->clip_xy || 90 draw->clip_z || 91 draw->clip_user) && !draw->pt.test_fse) { 92 opt |= PT_CLIPTEST; 93 } 94 95 opt |= PT_SHADE; 96 } 97 98 if (draw->pt.middle.llvm) { 99 middle = draw->pt.middle.llvm; 100 } else { 101 if (opt == 0) 102 middle = draw->pt.middle.fetch_emit; 103 else if (opt == PT_SHADE && !draw->pt.no_fse) 104 middle = draw->pt.middle.fetch_shade_emit; 105 else 106 middle = draw->pt.middle.general; 107 } 108 109 frontend = draw->pt.frontend; 110 111 if (frontend ) { 112 if (draw->pt.prim != prim || draw->pt.opt != opt) { 113 /* In certain conditions switching primitives requires us to flush 114 * and validate the different stages. One example is when smooth 115 * lines are active but first drawn with triangles and then with 116 * lines. 117 */ 118 draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE ); 119 frontend = NULL; 120 } else if (draw->pt.eltSize != draw->pt.user.eltSize) { 121 /* Flush draw state if eltSize changed. 122 * This could be improved so only the frontend is flushed since it 123 * converts all indices to ushorts and the fetch part of the middle 124 * always perpares both linear and indexed. 125 */ 126 frontend->flush( frontend, DRAW_FLUSH_STATE_CHANGE ); 127 frontend = NULL; 128 } 129 } 130 131 if (!frontend) { 132 frontend = draw->pt.front.vsplit; 133 134 frontend->prepare( frontend, prim, middle, opt ); 135 136 draw->pt.frontend = frontend; 137 draw->pt.eltSize = draw->pt.user.eltSize; 138 draw->pt.prim = prim; 139 draw->pt.opt = opt; 140 } 141 142 frontend->run( frontend, start, count ); 143 144 return TRUE; 145 } 146 147 void draw_pt_flush( struct draw_context *draw, unsigned flags ) 148 { 149 if (draw->pt.frontend) { 150 draw->pt.frontend->flush( draw->pt.frontend, flags ); 151 152 /* don't prepare if we only are flushing the backend */ 153 if (!(flags & DRAW_FLUSH_BACKEND)) 154 draw->pt.frontend = NULL; 155 } 156 } 157 158 159 160 boolean draw_pt_init( struct draw_context *draw ) 161 { 162 draw->pt.test_fse = debug_get_option_draw_fse(); 163 draw->pt.no_fse = debug_get_option_draw_no_fse(); 164 165 draw->pt.front.vsplit = draw_pt_vsplit(draw); 166 if (!draw->pt.front.vsplit) 167 return FALSE; 168 169 draw->pt.middle.fetch_emit = draw_pt_fetch_emit( draw ); 170 if (!draw->pt.middle.fetch_emit) 171 return FALSE; 172 173 draw->pt.middle.fetch_shade_emit = draw_pt_middle_fse( draw ); 174 if (!draw->pt.middle.fetch_shade_emit) 175 return FALSE; 176 177 draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit( draw ); 178 if (!draw->pt.middle.general) 179 return FALSE; 180 181 #if HAVE_LLVM 182 if (draw->llvm) 183 draw->pt.middle.llvm = draw_pt_fetch_pipeline_or_emit_llvm( draw ); 184 #endif 185 186 return TRUE; 187 } 188 189 190 void draw_pt_destroy( struct draw_context *draw ) 191 { 192 if (draw->pt.middle.llvm) { 193 draw->pt.middle.llvm->destroy( draw->pt.middle.llvm ); 194 draw->pt.middle.llvm = NULL; 195 } 196 197 if (draw->pt.middle.general) { 198 draw->pt.middle.general->destroy( draw->pt.middle.general ); 199 draw->pt.middle.general = NULL; 200 } 201 202 if (draw->pt.middle.fetch_emit) { 203 draw->pt.middle.fetch_emit->destroy( draw->pt.middle.fetch_emit ); 204 draw->pt.middle.fetch_emit = NULL; 205 } 206 207 if (draw->pt.middle.fetch_shade_emit) { 208 draw->pt.middle.fetch_shade_emit->destroy( draw->pt.middle.fetch_shade_emit ); 209 draw->pt.middle.fetch_shade_emit = NULL; 210 } 211 212 if (draw->pt.front.vsplit) { 213 draw->pt.front.vsplit->destroy( draw->pt.front.vsplit ); 214 draw->pt.front.vsplit = NULL; 215 } 216 } 217 218 219 /** 220 * Debug- print the first 'count' vertices. 221 */ 222 static void 223 draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count) 224 { 225 uint i; 226 227 debug_printf("Draw arrays(prim = %u, start = %u, count = %u)\n", 228 prim, start, count); 229 230 for (i = 0; i < count; i++) { 231 uint ii = 0; 232 uint j; 233 234 if (draw->pt.user.eltSize) { 235 /* indexed arrays */ 236 237 switch (draw->pt.user.eltSize) { 238 case 1: 239 { 240 const ubyte *elem = (const ubyte *) draw->pt.user.elts; 241 ii = elem[start + i]; 242 } 243 break; 244 case 2: 245 { 246 const ushort *elem = (const ushort *) draw->pt.user.elts; 247 ii = elem[start + i]; 248 } 249 break; 250 case 4: 251 { 252 const uint *elem = (const uint *) draw->pt.user.elts; 253 ii = elem[start + i]; 254 } 255 break; 256 default: 257 assert(0); 258 return; 259 } 260 ii += draw->pt.user.eltBias; 261 debug_printf("Element[%u + %u] + %i -> Vertex %u:\n", start, i, 262 draw->pt.user.eltBias, ii); 263 } 264 else { 265 /* non-indexed arrays */ 266 ii = start + i; 267 debug_printf("Vertex %u:\n", ii); 268 } 269 270 for (j = 0; j < draw->pt.nr_vertex_elements; j++) { 271 uint buf = draw->pt.vertex_element[j].vertex_buffer_index; 272 ubyte *ptr = (ubyte *) draw->pt.user.vbuffer[buf]; 273 274 if (draw->pt.vertex_element[j].instance_divisor) { 275 ii = draw->instance_id / draw->pt.vertex_element[j].instance_divisor; 276 } 277 278 ptr += draw->pt.vertex_buffer[buf].buffer_offset; 279 ptr += draw->pt.vertex_buffer[buf].stride * ii; 280 ptr += draw->pt.vertex_element[j].src_offset; 281 282 debug_printf(" Attr %u: ", j); 283 switch (draw->pt.vertex_element[j].src_format) { 284 case PIPE_FORMAT_R32_FLOAT: 285 { 286 float *v = (float *) ptr; 287 debug_printf("R %f @ %p\n", v[0], (void *) v); 288 } 289 break; 290 case PIPE_FORMAT_R32G32_FLOAT: 291 { 292 float *v = (float *) ptr; 293 debug_printf("RG %f %f @ %p\n", v[0], v[1], (void *) v); 294 } 295 break; 296 case PIPE_FORMAT_R32G32B32_FLOAT: 297 { 298 float *v = (float *) ptr; 299 debug_printf("RGB %f %f %f @ %p\n", v[0], v[1], v[2], (void *) v); 300 } 301 break; 302 case PIPE_FORMAT_R32G32B32A32_FLOAT: 303 { 304 float *v = (float *) ptr; 305 debug_printf("RGBA %f %f %f %f @ %p\n", v[0], v[1], v[2], v[3], 306 (void *) v); 307 } 308 break; 309 case PIPE_FORMAT_B8G8R8A8_UNORM: 310 { 311 ubyte *u = (ubyte *) ptr; 312 debug_printf("BGRA %d %d %d %d @ %p\n", u[0], u[1], u[2], u[3], 313 (void *) u); 314 } 315 break; 316 default: 317 debug_printf("other format %s (fix me)\n", 318 util_format_name(draw->pt.vertex_element[j].src_format)); 319 } 320 } 321 } 322 } 323 324 325 /** Helper code for below */ 326 #define PRIM_RESTART_LOOP(elements) \ 327 do { \ 328 for (i = start; i < end; i++) { \ 329 if (elements[i] == info->restart_index) { \ 330 if (cur_count > 0) { \ 331 /* draw elts up to prev pos */ \ 332 draw_pt_arrays(draw, prim, cur_start, cur_count); \ 333 } \ 334 /* begin new prim at next elt */ \ 335 cur_start = i + 1; \ 336 cur_count = 0; \ 337 } \ 338 else { \ 339 cur_count++; \ 340 } \ 341 } \ 342 if (cur_count > 0) { \ 343 draw_pt_arrays(draw, prim, cur_start, cur_count); \ 344 } \ 345 } while (0) 346 347 348 /** 349 * For drawing prims with primitive restart enabled. 350 * Scan for restart indexes and draw the runs of elements/vertices between 351 * the restarts. 352 */ 353 static void 354 draw_pt_arrays_restart(struct draw_context *draw, 355 const struct pipe_draw_info *info) 356 { 357 const unsigned prim = info->mode; 358 const unsigned start = info->start; 359 const unsigned count = info->count; 360 const unsigned end = start + count; 361 unsigned i, cur_start, cur_count; 362 363 assert(info->primitive_restart); 364 365 if (draw->pt.user.eltSize) { 366 /* indexed prims (draw_elements) */ 367 cur_start = start; 368 cur_count = 0; 369 370 switch (draw->pt.user.eltSize) { 371 case 1: 372 { 373 const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts; 374 PRIM_RESTART_LOOP(elt_ub); 375 } 376 break; 377 case 2: 378 { 379 const ushort *elt_us = (const ushort *) draw->pt.user.elts; 380 PRIM_RESTART_LOOP(elt_us); 381 } 382 break; 383 case 4: 384 { 385 const uint *elt_ui = (const uint *) draw->pt.user.elts; 386 PRIM_RESTART_LOOP(elt_ui); 387 } 388 break; 389 default: 390 assert(0 && "bad eltSize in draw_arrays()"); 391 } 392 } 393 else { 394 /* Non-indexed prims (draw_arrays). 395 * Primitive restart should have been handled in the state tracker. 396 */ 397 draw_pt_arrays(draw, prim, start, count); 398 } 399 } 400 401 402 403 /** 404 * Non-instanced drawing. 405 * \sa draw_arrays_instanced 406 */ 407 void 408 draw_arrays(struct draw_context *draw, unsigned prim, 409 unsigned start, unsigned count) 410 { 411 draw_arrays_instanced(draw, prim, start, count, 0, 1); 412 } 413 414 415 /** 416 * Instanced drawing. 417 * \sa draw_vbo 418 */ 419 void 420 draw_arrays_instanced(struct draw_context *draw, 421 unsigned mode, 422 unsigned start, 423 unsigned count, 424 unsigned startInstance, 425 unsigned instanceCount) 426 { 427 struct pipe_draw_info info; 428 429 util_draw_init_info(&info); 430 431 info.mode = mode; 432 info.start = start; 433 info.count = count; 434 info.start_instance = startInstance; 435 info.instance_count = instanceCount; 436 info.min_index = start; 437 info.max_index = start + count - 1; 438 439 draw_vbo(draw, &info); 440 } 441 442 443 /** 444 * Draw vertex arrays. 445 * This is the main entrypoint into the drawing module. If drawing an indexed 446 * primitive, the draw_set_index_buffer() and draw_set_mapped_index_buffer() 447 * functions should have already been called to specify the element/index 448 * buffer information. 449 */ 450 void 451 draw_vbo(struct draw_context *draw, 452 const struct pipe_draw_info *info) 453 { 454 unsigned instance; 455 unsigned index_limit; 456 457 assert(info->instance_count > 0); 458 if (info->indexed) 459 assert(draw->pt.user.elts); 460 461 draw->pt.user.eltBias = info->index_bias; 462 draw->pt.user.min_index = info->min_index; 463 draw->pt.user.max_index = info->max_index; 464 draw->pt.user.eltSize = info->indexed ? draw->pt.user.eltSizeIB : 0; 465 466 if (0) 467 debug_printf("draw_vbo(mode=%u start=%u count=%u):\n", 468 info->mode, info->start, info->count); 469 470 if (0) 471 tgsi_dump(draw->vs.vertex_shader->state.tokens, 0); 472 473 if (0) { 474 unsigned int i; 475 debug_printf("Elements:\n"); 476 for (i = 0; i < draw->pt.nr_vertex_elements; i++) { 477 debug_printf(" %u: src_offset=%u inst_div=%u vbuf=%u format=%s\n", 478 i, 479 draw->pt.vertex_element[i].src_offset, 480 draw->pt.vertex_element[i].instance_divisor, 481 draw->pt.vertex_element[i].vertex_buffer_index, 482 util_format_name(draw->pt.vertex_element[i].src_format)); 483 } 484 debug_printf("Buffers:\n"); 485 for (i = 0; i < draw->pt.nr_vertex_buffers; i++) { 486 debug_printf(" %u: stride=%u offset=%u ptr=%p\n", 487 i, 488 draw->pt.vertex_buffer[i].stride, 489 draw->pt.vertex_buffer[i].buffer_offset, 490 draw->pt.user.vbuffer[i]); 491 } 492 } 493 494 if (0) 495 draw_print_arrays(draw, info->mode, info->start, MIN2(info->count, 20)); 496 497 index_limit = util_draw_max_index(draw->pt.vertex_buffer, 498 draw->pt.vertex_element, 499 draw->pt.nr_vertex_elements, 500 info); 501 502 if (index_limit == 0) { 503 /* one of the buffers is too small to do any valid drawing */ 504 debug_warning("draw: VBO too small to draw anything\n"); 505 return; 506 } 507 508 draw->pt.max_index = index_limit - 1; 509 510 511 /* 512 * TODO: We could use draw->pt.max_index to further narrow 513 * the min_index/max_index hints given by the state tracker. 514 */ 515 516 for (instance = 0; instance < info->instance_count; instance++) { 517 draw->instance_id = instance + info->start_instance; 518 519 if (info->primitive_restart) { 520 draw_pt_arrays_restart(draw, info); 521 } 522 else { 523 draw_pt_arrays(draw, info->mode, info->start, info->count); 524 } 525 } 526 } 527