draw_pt.c revision 4a79545bdfb9e948329a761ef350eb83a3d87496
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@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 45DEBUG_GET_ONCE_BOOL_OPTION(draw_fse, "DRAW_FSE", FALSE) 46DEBUG_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 */ 54static boolean 55draw_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.front.vsplit; 110 111 frontend->prepare( frontend, prim, middle, opt ); 112 113 frontend->run(frontend, start, count); 114 115 frontend->finish( frontend ); 116 117 return TRUE; 118} 119 120 121boolean draw_pt_init( struct draw_context *draw ) 122{ 123 draw->pt.test_fse = debug_get_option_draw_fse(); 124 draw->pt.no_fse = debug_get_option_draw_no_fse(); 125 126 draw->pt.front.vsplit = draw_pt_vsplit(draw); 127 if (!draw->pt.front.vsplit) 128 return FALSE; 129 130 draw->pt.middle.fetch_emit = draw_pt_fetch_emit( draw ); 131 if (!draw->pt.middle.fetch_emit) 132 return FALSE; 133 134 draw->pt.middle.fetch_shade_emit = draw_pt_middle_fse( draw ); 135 if (!draw->pt.middle.fetch_shade_emit) 136 return FALSE; 137 138 draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit( draw ); 139 if (!draw->pt.middle.general) 140 return FALSE; 141 142#if HAVE_LLVM 143 if (draw->llvm) 144 draw->pt.middle.llvm = draw_pt_fetch_pipeline_or_emit_llvm( draw ); 145#endif 146 147 return TRUE; 148} 149 150 151void draw_pt_destroy( struct draw_context *draw ) 152{ 153 if (draw->pt.middle.llvm) { 154 draw->pt.middle.llvm->destroy( draw->pt.middle.llvm ); 155 draw->pt.middle.llvm = NULL; 156 } 157 158 if (draw->pt.middle.general) { 159 draw->pt.middle.general->destroy( draw->pt.middle.general ); 160 draw->pt.middle.general = NULL; 161 } 162 163 if (draw->pt.middle.fetch_emit) { 164 draw->pt.middle.fetch_emit->destroy( draw->pt.middle.fetch_emit ); 165 draw->pt.middle.fetch_emit = NULL; 166 } 167 168 if (draw->pt.middle.fetch_shade_emit) { 169 draw->pt.middle.fetch_shade_emit->destroy( draw->pt.middle.fetch_shade_emit ); 170 draw->pt.middle.fetch_shade_emit = NULL; 171 } 172 173 if (draw->pt.front.vsplit) { 174 draw->pt.front.vsplit->destroy( draw->pt.front.vsplit ); 175 draw->pt.front.vsplit = NULL; 176 } 177} 178 179 180/** 181 * Debug- print the first 'count' vertices. 182 */ 183static void 184draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count) 185{ 186 uint i; 187 188 debug_printf("Draw arrays(prim = %u, start = %u, count = %u)\n", 189 prim, start, count); 190 191 for (i = 0; i < count; i++) { 192 uint ii = 0; 193 uint j; 194 195 if (draw->pt.user.eltSize) { 196 const char *elts; 197 198 /* indexed arrays */ 199 elts = (const char *) draw->pt.user.elts; 200 elts += draw->pt.index_buffer.offset; 201 202 switch (draw->pt.user.eltSize) { 203 case 1: 204 { 205 const ubyte *elem = (const ubyte *) elts; 206 ii = elem[start + i]; 207 } 208 break; 209 case 2: 210 { 211 const ushort *elem = (const ushort *) elts; 212 ii = elem[start + i]; 213 } 214 break; 215 case 4: 216 { 217 const uint *elem = (const uint *) elts; 218 ii = elem[start + i]; 219 } 220 break; 221 default: 222 assert(0); 223 return; 224 } 225 ii += draw->pt.user.eltBias; 226 debug_printf("Element[%u + %u] + %i -> Vertex %u:\n", start, i, 227 draw->pt.user.eltBias, ii); 228 } 229 else { 230 /* non-indexed arrays */ 231 ii = start + i; 232 debug_printf("Vertex %u:\n", ii); 233 } 234 235 for (j = 0; j < draw->pt.nr_vertex_elements; j++) { 236 uint buf = draw->pt.vertex_element[j].vertex_buffer_index; 237 ubyte *ptr = (ubyte *) draw->pt.user.vbuffer[buf]; 238 239 if (draw->pt.vertex_element[j].instance_divisor) { 240 ii = draw->instance_id / draw->pt.vertex_element[j].instance_divisor; 241 } 242 243 ptr += draw->pt.vertex_buffer[buf].buffer_offset; 244 ptr += draw->pt.vertex_buffer[buf].stride * ii; 245 ptr += draw->pt.vertex_element[j].src_offset; 246 247 debug_printf(" Attr %u: ", j); 248 switch (draw->pt.vertex_element[j].src_format) { 249 case PIPE_FORMAT_R32_FLOAT: 250 { 251 float *v = (float *) ptr; 252 debug_printf("R %f @ %p\n", v[0], (void *) v); 253 } 254 break; 255 case PIPE_FORMAT_R32G32_FLOAT: 256 { 257 float *v = (float *) ptr; 258 debug_printf("RG %f %f @ %p\n", v[0], v[1], (void *) v); 259 } 260 break; 261 case PIPE_FORMAT_R32G32B32_FLOAT: 262 { 263 float *v = (float *) ptr; 264 debug_printf("RGB %f %f %f @ %p\n", v[0], v[1], v[2], (void *) v); 265 } 266 break; 267 case PIPE_FORMAT_R32G32B32A32_FLOAT: 268 { 269 float *v = (float *) ptr; 270 debug_printf("RGBA %f %f %f %f @ %p\n", v[0], v[1], v[2], v[3], 271 (void *) v); 272 } 273 break; 274 case PIPE_FORMAT_B8G8R8A8_UNORM: 275 { 276 ubyte *u = (ubyte *) ptr; 277 debug_printf("BGRA %d %d %d %d @ %p\n", u[0], u[1], u[2], u[3], 278 (void *) u); 279 } 280 break; 281 default: 282 debug_printf("other format %s (fix me)\n", 283 util_format_name(draw->pt.vertex_element[j].src_format)); 284 } 285 } 286 } 287} 288 289 290/** Helper code for below */ 291#define PRIM_RESTART_LOOP(elements) \ 292 do { \ 293 for (i = start; i < end; i++) { \ 294 if (elements[i] == info->restart_index) { \ 295 if (cur_count > 0) { \ 296 /* draw elts up to prev pos */ \ 297 draw_pt_arrays(draw, prim, cur_start, cur_count); \ 298 } \ 299 /* begin new prim at next elt */ \ 300 cur_start = i + 1; \ 301 cur_count = 0; \ 302 } \ 303 else { \ 304 cur_count++; \ 305 } \ 306 } \ 307 if (cur_count > 0) { \ 308 draw_pt_arrays(draw, prim, cur_start, cur_count); \ 309 } \ 310 } while (0) 311 312 313/** 314 * For drawing prims with primitive restart enabled. 315 * Scan for restart indexes and draw the runs of elements/vertices between 316 * the restarts. 317 */ 318static void 319draw_pt_arrays_restart(struct draw_context *draw, 320 const struct pipe_draw_info *info) 321{ 322 const unsigned prim = info->mode; 323 const unsigned start = info->start; 324 const unsigned count = info->count; 325 const unsigned end = start + count; 326 unsigned i, cur_start, cur_count; 327 328 assert(info->primitive_restart); 329 330 if (draw->pt.user.elts) { 331 /* indexed prims (draw_elements) */ 332 cur_start = start; 333 cur_count = 0; 334 335 switch (draw->pt.user.eltSize) { 336 case 1: 337 { 338 const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts; 339 PRIM_RESTART_LOOP(elt_ub); 340 } 341 break; 342 case 2: 343 { 344 const ushort *elt_us = (const ushort *) draw->pt.user.elts; 345 PRIM_RESTART_LOOP(elt_us); 346 } 347 break; 348 case 4: 349 { 350 const uint *elt_ui = (const uint *) draw->pt.user.elts; 351 PRIM_RESTART_LOOP(elt_ui); 352 } 353 break; 354 default: 355 assert(0 && "bad eltSize in draw_arrays()"); 356 } 357 } 358 else { 359 /* Non-indexed prims (draw_arrays). 360 * Primitive restart should have been handled in the state tracker. 361 */ 362 draw_pt_arrays(draw, prim, start, count); 363 } 364} 365 366 367 368/** 369 * Non-instanced drawing. 370 * \sa draw_arrays_instanced 371 */ 372void 373draw_arrays(struct draw_context *draw, unsigned prim, 374 unsigned start, unsigned count) 375{ 376 draw_arrays_instanced(draw, prim, start, count, 0, 1); 377} 378 379 380/** 381 * Instanced drawing. 382 * \sa draw_vbo 383 */ 384void 385draw_arrays_instanced(struct draw_context *draw, 386 unsigned mode, 387 unsigned start, 388 unsigned count, 389 unsigned startInstance, 390 unsigned instanceCount) 391{ 392 struct pipe_draw_info info; 393 394 util_draw_init_info(&info); 395 396 info.mode = mode; 397 info.start = start; 398 info.count = count; 399 info.start_instance = startInstance; 400 info.instance_count = instanceCount; 401 402 info.indexed = (draw->pt.user.elts != NULL); 403 if (!info.indexed) { 404 info.min_index = start; 405 info.max_index = start + count - 1; 406 } 407 408 draw_vbo(draw, &info); 409} 410 411 412/** 413 * Draw vertex arrays. 414 * This is the main entrypoint into the drawing module. If drawing an indexed 415 * primitive, the draw_set_index_buffer() and draw_set_mapped_index_buffer() 416 * functions should have already been called to specify the element/index 417 * buffer information. 418 */ 419void 420draw_vbo(struct draw_context *draw, 421 const struct pipe_draw_info *info) 422{ 423 unsigned instance; 424 unsigned index_limit; 425 426 assert(info->instance_count > 0); 427 if (info->indexed) 428 assert(draw->pt.user.elts); 429 430 draw->pt.user.eltSize = 431 (info->indexed) ? draw->pt.index_buffer.index_size : 0; 432 433 draw->pt.user.eltBias = info->index_bias; 434 draw->pt.user.min_index = info->min_index; 435 draw->pt.user.max_index = info->max_index; 436 437 if (0) 438 debug_printf("draw_vbo(mode=%u start=%u count=%u):\n", 439 info->mode, info->start, info->count); 440 441 if (0) 442 tgsi_dump(draw->vs.vertex_shader->state.tokens, 0); 443 444 if (0) { 445 unsigned int i; 446 debug_printf("Elements:\n"); 447 for (i = 0; i < draw->pt.nr_vertex_elements; i++) { 448 debug_printf(" %u: src_offset=%u inst_div=%u vbuf=%u format=%s\n", 449 i, 450 draw->pt.vertex_element[i].src_offset, 451 draw->pt.vertex_element[i].instance_divisor, 452 draw->pt.vertex_element[i].vertex_buffer_index, 453 util_format_name(draw->pt.vertex_element[i].src_format)); 454 } 455 debug_printf("Buffers:\n"); 456 for (i = 0; i < draw->pt.nr_vertex_buffers; i++) { 457 debug_printf(" %u: stride=%u offset=%u ptr=%p\n", 458 i, 459 draw->pt.vertex_buffer[i].stride, 460 draw->pt.vertex_buffer[i].buffer_offset, 461 draw->pt.user.vbuffer[i]); 462 } 463 } 464 465 if (0) 466 draw_print_arrays(draw, info->mode, info->start, MIN2(info->count, 20)); 467 468 index_limit = util_draw_max_index(draw->pt.vertex_buffer, 469 draw->pt.nr_vertex_buffers, 470 draw->pt.vertex_element, 471 draw->pt.nr_vertex_elements, 472 info); 473 474 if (index_limit == 0) { 475 /* one of the buffers is too small to do any valid drawing */ 476 debug_warning("draw: VBO too small to draw anything\n"); 477 return; 478 } 479 480 draw->pt.max_index = index_limit - 1; 481 482 483 /* 484 * TODO: We could use draw->pt.max_index to further narrow 485 * the min_index/max_index hints given by the state tracker. 486 */ 487 488 for (instance = 0; instance < info->instance_count; instance++) { 489 draw->instance_id = instance + info->start_instance; 490 491 if (info->primitive_restart) { 492 draw_pt_arrays_restart(draw, info); 493 } 494 else { 495 draw_pt_arrays(draw, info->mode, info->start, info->count); 496 } 497 } 498} 499