1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2012-2013 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Chia-I Wu <olv (at) lunarg.com> 26 */ 27 28 #include "util/u_prim.h" 29 #include "core/intel_winsys.h" 30 31 #include "ilo_render.h" 32 #include "ilo_blit.h" 33 #include "ilo_context.h" 34 #include "ilo_cp.h" 35 #include "ilo_query.h" 36 #include "ilo_shader.h" 37 #include "ilo_state.h" 38 #include "ilo_draw.h" 39 40 static void 41 ilo_draw_set_owner(struct ilo_context *ilo) 42 { 43 ilo_cp_set_owner(ilo->cp, INTEL_RING_RENDER, &ilo->draw.cp_owner); 44 } 45 46 static uint64_t 47 query_timestamp_to_ns(const struct ilo_context *ilo, uint64_t timestamp) 48 { 49 /* see ilo_get_timestamp() */ 50 return (timestamp & 0xffffffff) * 80; 51 } 52 53 /** 54 * Process the bo and accumulate the result. The bo is emptied. 55 */ 56 static void 57 query_process_bo(const struct ilo_context *ilo, struct ilo_query *q) 58 { 59 const uint64_t *vals; 60 uint64_t tmp; 61 int i; 62 63 if (!q->used) 64 return; 65 66 vals = intel_bo_map(q->bo, false); 67 if (!vals) { 68 q->used = 0; 69 return; 70 } 71 72 switch (q->type) { 73 case PIPE_QUERY_OCCLUSION_COUNTER: 74 case PIPE_QUERY_OCCLUSION_PREDICATE: 75 case PIPE_QUERY_TIME_ELAPSED: 76 case PIPE_QUERY_PRIMITIVES_GENERATED: 77 case PIPE_QUERY_PRIMITIVES_EMITTED: 78 assert(q->stride == sizeof(*vals) * 2); 79 80 tmp = 0; 81 for (i = 0; i < q->used; i++) 82 tmp += vals[2 * i + 1] - vals[2 * i]; 83 84 if (q->type == PIPE_QUERY_TIME_ELAPSED) 85 tmp = query_timestamp_to_ns(ilo, tmp); 86 87 q->result.u64 += tmp; 88 break; 89 case PIPE_QUERY_TIMESTAMP: 90 assert(q->stride == sizeof(*vals)); 91 92 q->result.u64 = query_timestamp_to_ns(ilo, vals[q->used - 1]); 93 break; 94 case PIPE_QUERY_PIPELINE_STATISTICS: 95 assert(q->stride == sizeof(*vals) * 22); 96 97 for (i = 0; i < q->used; i++) { 98 struct pipe_query_data_pipeline_statistics *stats = 99 &q->result.pipeline_statistics; 100 const uint64_t *begin = vals + 22 * i; 101 const uint64_t *end = begin + 11; 102 103 stats->ia_vertices += end[0] - begin[0]; 104 stats->ia_primitives += end[1] - begin[1]; 105 stats->vs_invocations += end[2] - begin[2]; 106 stats->gs_invocations += end[3] - begin[3]; 107 stats->gs_primitives += end[4] - begin[4]; 108 stats->c_invocations += end[5] - begin[5]; 109 stats->c_primitives += end[6] - begin[6]; 110 stats->ps_invocations += end[7] - begin[7]; 111 stats->hs_invocations += end[8] - begin[8]; 112 stats->ds_invocations += end[9] - begin[9]; 113 stats->cs_invocations += end[10] - begin[10]; 114 } 115 break; 116 default: 117 break; 118 } 119 120 intel_bo_unmap(q->bo); 121 122 q->used = 0; 123 } 124 125 static void 126 query_begin_bo(struct ilo_context *ilo, struct ilo_query *q) 127 { 128 /* bo is full */ 129 if (q->used >= q->count) 130 query_process_bo(ilo, q); 131 132 /* write the beginning value to the bo */ 133 if (q->in_pairs) 134 ilo_render_emit_query(ilo->render, q, q->stride * q->used); 135 } 136 137 static void 138 query_end_bo(struct ilo_context *ilo, struct ilo_query *q) 139 { 140 uint32_t offset; 141 142 assert(q->used < q->count); 143 144 offset = q->stride * q->used; 145 if (q->in_pairs) 146 offset += q->stride >> 1; 147 148 q->used++; 149 150 /* write the ending value to the bo */ 151 ilo_render_emit_query(ilo->render, q, offset); 152 } 153 154 bool 155 ilo_init_draw_query(struct ilo_context *ilo, struct ilo_query *q) 156 { 157 unsigned bo_size; 158 159 switch (q->type) { 160 case PIPE_QUERY_OCCLUSION_COUNTER: 161 case PIPE_QUERY_OCCLUSION_PREDICATE: 162 case PIPE_QUERY_TIME_ELAPSED: 163 case PIPE_QUERY_PRIMITIVES_GENERATED: 164 case PIPE_QUERY_PRIMITIVES_EMITTED: 165 q->stride = sizeof(uint64_t); 166 q->in_pairs = true; 167 break; 168 case PIPE_QUERY_TIMESTAMP: 169 q->stride = sizeof(uint64_t); 170 q->in_pairs = false; 171 break; 172 case PIPE_QUERY_PIPELINE_STATISTICS: 173 q->stride = sizeof(uint64_t) * 11; 174 q->in_pairs = true; 175 break; 176 default: 177 return false; 178 break; 179 } 180 181 q->cmd_len = ilo_render_get_query_len(ilo->render, q->type); 182 183 /* double cmd_len and stride if in pairs */ 184 q->cmd_len <<= q->in_pairs; 185 q->stride <<= q->in_pairs; 186 187 bo_size = (q->stride > 4096) ? q->stride : 4096; 188 q->bo = intel_winsys_alloc_bo(ilo->winsys, "query", bo_size, false); 189 if (!q->bo) 190 return false; 191 192 q->count = bo_size / q->stride; 193 194 return true; 195 } 196 197 void 198 ilo_begin_draw_query(struct ilo_context *ilo, struct ilo_query *q) 199 { 200 ilo_draw_set_owner(ilo); 201 202 /* need to submit first */ 203 if (!ilo_builder_validate(&ilo->cp->builder, 1, &q->bo) || 204 ilo_cp_space(ilo->cp) < q->cmd_len) { 205 ilo_cp_submit(ilo->cp, "out of aperture or space"); 206 207 assert(ilo_builder_validate(&ilo->cp->builder, 1, &q->bo)); 208 assert(ilo_cp_space(ilo->cp) >= q->cmd_len); 209 210 ilo_draw_set_owner(ilo); 211 } 212 213 /* reserve the space for ending/pausing the query */ 214 ilo->draw.cp_owner.reserve += q->cmd_len >> q->in_pairs; 215 216 query_begin_bo(ilo, q); 217 218 if (q->in_pairs) 219 list_add(&q->list, &ilo->draw.queries); 220 } 221 222 void 223 ilo_end_draw_query(struct ilo_context *ilo, struct ilo_query *q) 224 { 225 ilo_draw_set_owner(ilo); 226 227 /* reclaim the reserved space */ 228 ilo->draw.cp_owner.reserve -= q->cmd_len >> q->in_pairs; 229 assert(ilo->draw.cp_owner.reserve >= 0); 230 231 query_end_bo(ilo, q); 232 233 list_delinit(&q->list); 234 } 235 236 /** 237 * Process the raw query data. 238 */ 239 void 240 ilo_process_draw_query(struct ilo_context *ilo, struct ilo_query *q) 241 { 242 query_process_bo(ilo, q); 243 } 244 245 static void 246 ilo_draw_own_cp(struct ilo_cp *cp, void *data) 247 { 248 struct ilo_context *ilo = data; 249 250 /* multiply by 2 for both resuming and pausing */ 251 if (ilo_cp_space(ilo->cp) < ilo->draw.cp_owner.reserve * 2) { 252 ilo_cp_submit(ilo->cp, "out of space"); 253 assert(ilo_cp_space(ilo->cp) >= ilo->draw.cp_owner.reserve * 2); 254 } 255 256 while (true) { 257 struct ilo_builder_snapshot snapshot; 258 struct ilo_query *q; 259 260 ilo_builder_batch_snapshot(&ilo->cp->builder, &snapshot); 261 262 /* resume queries */ 263 LIST_FOR_EACH_ENTRY(q, &ilo->draw.queries, list) 264 query_begin_bo(ilo, q); 265 266 if (!ilo_builder_validate(&ilo->cp->builder, 0, NULL)) { 267 ilo_builder_batch_restore(&ilo->cp->builder, &snapshot); 268 269 if (ilo_builder_batch_used(&ilo->cp->builder)) { 270 ilo_cp_submit(ilo->cp, "out of aperture"); 271 continue; 272 } 273 } 274 275 break; 276 } 277 278 assert(ilo_cp_space(ilo->cp) >= ilo->draw.cp_owner.reserve); 279 } 280 281 static void 282 ilo_draw_release_cp(struct ilo_cp *cp, void *data) 283 { 284 struct ilo_context *ilo = data; 285 struct ilo_query *q; 286 287 assert(ilo_cp_space(ilo->cp) >= ilo->draw.cp_owner.reserve); 288 289 /* pause queries */ 290 LIST_FOR_EACH_ENTRY(q, &ilo->draw.queries, list) 291 query_end_bo(ilo, q); 292 } 293 294 static bool 295 draw_vbo(struct ilo_context *ilo, const struct ilo_state_vector *vec) 296 { 297 bool need_flush = false; 298 bool success = true; 299 int max_len, before_space; 300 301 /* on Gen7 and Gen7.5, we need SOL_RESET to reset the SO write offsets */ 302 if (ilo_dev_gen(ilo->dev) >= ILO_GEN(7) && 303 ilo_dev_gen(ilo->dev) <= ILO_GEN(7.5) && 304 (vec->dirty & ILO_DIRTY_SO) && vec->so.enabled && 305 !vec->so.append_bitmask) { 306 ilo_cp_submit(ilo->cp, "SOL_RESET"); 307 ilo_cp_set_one_off_flags(ilo->cp, INTEL_EXEC_GEN7_SOL_RESET); 308 } 309 310 if (ilo_builder_batch_used(&ilo->cp->builder)) { 311 /* 312 * Without a better tracking mechanism, when the framebuffer changes, we 313 * have to assume that the old framebuffer may be sampled from. If that 314 * happens in the middle of a batch buffer, we need to insert manual 315 * flushes. 316 */ 317 need_flush = (vec->dirty & ILO_DIRTY_FB); 318 319 /* same to SO target changes */ 320 need_flush |= (vec->dirty & ILO_DIRTY_SO); 321 } 322 323 ilo_draw_set_owner(ilo); 324 325 /* make sure there is enough room first */ 326 max_len = ilo_render_get_draw_len(ilo->render, vec); 327 if (need_flush) 328 max_len += ilo_render_get_flush_len(ilo->render); 329 330 if (max_len > ilo_cp_space(ilo->cp)) { 331 ilo_cp_submit(ilo->cp, "out of space"); 332 need_flush = false; 333 assert(max_len <= ilo_cp_space(ilo->cp)); 334 } 335 336 /* space available before emission */ 337 before_space = ilo_cp_space(ilo->cp); 338 339 if (need_flush) 340 ilo_render_emit_flush(ilo->render); 341 342 while (true) { 343 struct ilo_builder_snapshot snapshot; 344 345 ilo_builder_batch_snapshot(&ilo->cp->builder, &snapshot); 346 347 ilo_render_emit_draw(ilo->render, vec); 348 349 if (!ilo_builder_validate(&ilo->cp->builder, 0, NULL)) { 350 ilo_builder_batch_restore(&ilo->cp->builder, &snapshot); 351 352 /* flush and try again */ 353 if (ilo_builder_batch_used(&ilo->cp->builder)) { 354 ilo_cp_submit(ilo->cp, "out of aperture"); 355 continue; 356 } 357 358 success = false; 359 } 360 361 break; 362 } 363 364 /* sanity check size estimation */ 365 assert(before_space - ilo_cp_space(ilo->cp) <= max_len); 366 367 return success; 368 } 369 370 void 371 ilo_draw_rectlist(struct ilo_context *ilo) 372 { 373 int max_len, before_space; 374 bool need_flush; 375 376 need_flush = ilo_builder_batch_used(&ilo->cp->builder); 377 378 ilo_draw_set_owner(ilo); 379 380 max_len = ilo_render_get_rectlist_len(ilo->render, ilo->blitter); 381 max_len += ilo_render_get_flush_len(ilo->render) * 2; 382 383 if (max_len > ilo_cp_space(ilo->cp)) { 384 ilo_cp_submit(ilo->cp, "out of space"); 385 need_flush = false; 386 assert(max_len <= ilo_cp_space(ilo->cp)); 387 } 388 389 before_space = ilo_cp_space(ilo->cp); 390 391 /* 392 * From the Sandy Bridge PRM, volume 2 part 1, page 313: 393 * 394 * "If other rendering operations have preceded this clear, a 395 * PIPE_CONTROL with write cache flush enabled and Z-inhibit 396 * disabled must be issued before the rectangle primitive used for 397 * the depth buffer clear operation." 398 * 399 * From the Sandy Bridge PRM, volume 2 part 1, page 314: 400 * 401 * "Depth buffer clear pass must be followed by a PIPE_CONTROL 402 * command with DEPTH_STALL bit set and Then followed by Depth 403 * FLUSH" 404 * 405 * But the pipeline has to be flushed both before and after not only 406 * because of these workarounds. We need them for reasons such as 407 * 408 * - we may sample from a texture that was rendered to 409 * - we may sample from the fb shortly after 410 * 411 * Skip checking blitter->op and do the flushes. 412 */ 413 if (need_flush) 414 ilo_render_emit_flush(ilo->render); 415 416 while (true) { 417 struct ilo_builder_snapshot snapshot; 418 419 ilo_builder_batch_snapshot(&ilo->cp->builder, &snapshot); 420 421 ilo_render_emit_rectlist(ilo->render, ilo->blitter); 422 423 if (!ilo_builder_validate(&ilo->cp->builder, 0, NULL)) { 424 ilo_builder_batch_restore(&ilo->cp->builder, &snapshot); 425 426 /* flush and try again */ 427 if (ilo_builder_batch_used(&ilo->cp->builder)) { 428 ilo_cp_submit(ilo->cp, "out of aperture"); 429 continue; 430 } 431 } 432 433 break; 434 } 435 436 ilo_render_invalidate_hw(ilo->render); 437 438 ilo_render_emit_flush(ilo->render); 439 440 /* sanity check size estimation */ 441 assert(before_space - ilo_cp_space(ilo->cp) <= max_len); 442 } 443 444 static void 445 draw_vbo_with_sw_restart(struct ilo_context *ilo, 446 const struct pipe_draw_info *info) 447 { 448 const struct ilo_ib_state *ib = &ilo->state_vector.ib; 449 const struct ilo_vma *vma; 450 union { 451 const void *ptr; 452 const uint8_t *u8; 453 const uint16_t *u16; 454 const uint32_t *u32; 455 } u; 456 457 /* we will draw with IB mapped */ 458 if (ib->state.buffer) { 459 vma = ilo_resource_get_vma(ib->state.buffer); 460 u.ptr = intel_bo_map(vma->bo, false); 461 if (u.ptr) 462 u.u8 += vma->bo_offset + ib->state.offset; 463 } else { 464 vma = NULL; 465 u.ptr = ib->state.user_buffer; 466 } 467 468 if (!u.ptr) 469 return; 470 471 #define DRAW_VBO_WITH_SW_RESTART(pipe, info, ptr) do { \ 472 const unsigned end = (info)->start + (info)->count; \ 473 struct pipe_draw_info subinfo; \ 474 unsigned i; \ 475 \ 476 subinfo = *(info); \ 477 subinfo.primitive_restart = false; \ 478 for (i = (info)->start; i < end; i++) { \ 479 if ((ptr)[i] == (info)->restart_index) { \ 480 subinfo.count = i - subinfo.start; \ 481 if (subinfo.count) \ 482 (pipe)->draw_vbo(pipe, &subinfo); \ 483 subinfo.start = i + 1; \ 484 } \ 485 } \ 486 subinfo.count = i - subinfo.start; \ 487 if (subinfo.count) \ 488 (pipe)->draw_vbo(pipe, &subinfo); \ 489 } while (0) 490 491 switch (ib->state.index_size) { 492 case 1: 493 DRAW_VBO_WITH_SW_RESTART(&ilo->base, info, u.u8); 494 break; 495 case 2: 496 DRAW_VBO_WITH_SW_RESTART(&ilo->base, info, u.u16); 497 break; 498 case 4: 499 DRAW_VBO_WITH_SW_RESTART(&ilo->base, info, u.u32); 500 break; 501 default: 502 assert(!"unsupported index size"); 503 break; 504 } 505 506 #undef DRAW_VBO_WITH_SW_RESTART 507 508 if (vma) 509 intel_bo_unmap(vma->bo); 510 } 511 512 static bool 513 draw_vbo_need_sw_restart(const struct ilo_context *ilo, 514 const struct pipe_draw_info *info) 515 { 516 /* the restart index is fixed prior to GEN7.5 */ 517 if (ilo_dev_gen(ilo->dev) < ILO_GEN(7.5)) { 518 const unsigned cut_index = 519 (ilo->state_vector.ib.state.index_size == 1) ? 0xff : 520 (ilo->state_vector.ib.state.index_size == 2) ? 0xffff : 521 (ilo->state_vector.ib.state.index_size == 4) ? 0xffffffff : 0; 522 523 if (info->restart_index < cut_index) 524 return true; 525 } 526 527 switch (info->mode) { 528 case PIPE_PRIM_POINTS: 529 case PIPE_PRIM_LINES: 530 case PIPE_PRIM_LINE_STRIP: 531 case PIPE_PRIM_TRIANGLES: 532 case PIPE_PRIM_TRIANGLE_STRIP: 533 /* these never need software fallback */ 534 return false; 535 case PIPE_PRIM_LINE_LOOP: 536 case PIPE_PRIM_POLYGON: 537 case PIPE_PRIM_QUAD_STRIP: 538 case PIPE_PRIM_QUADS: 539 case PIPE_PRIM_TRIANGLE_FAN: 540 /* these need software fallback prior to GEN7.5 */ 541 return (ilo_dev_gen(ilo->dev) < ILO_GEN(7.5)); 542 default: 543 /* the rest always needs software fallback */ 544 return true; 545 } 546 } 547 548 static void 549 ilo_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) 550 { 551 struct ilo_context *ilo = ilo_context(pipe); 552 int vs_scratch_size, gs_scratch_size, fs_scratch_size; 553 554 if (ilo_debug & ILO_DEBUG_DRAW) { 555 if (info->indexed) { 556 ilo_printf("indexed draw %s: " 557 "index start %d, count %d, vertex range [%d, %d]\n", 558 u_prim_name(info->mode), info->start, info->count, 559 info->min_index, info->max_index); 560 } 561 else { 562 ilo_printf("draw %s: vertex start %d, count %d\n", 563 u_prim_name(info->mode), info->start, info->count); 564 } 565 566 ilo_state_vector_dump_dirty(&ilo->state_vector); 567 } 568 569 if (ilo_skip_rendering(ilo)) 570 return; 571 572 if (info->primitive_restart && info->indexed && 573 draw_vbo_need_sw_restart(ilo, info)) { 574 draw_vbo_with_sw_restart(ilo, info); 575 return; 576 } 577 578 ilo_finalize_3d_states(ilo, info); 579 580 /* upload kernels */ 581 ilo_shader_cache_upload(ilo->shader_cache, &ilo->cp->builder); 582 583 /* prepare scratch spaces */ 584 ilo_shader_cache_get_max_scratch_sizes(ilo->shader_cache, 585 &vs_scratch_size, &gs_scratch_size, &fs_scratch_size); 586 ilo_render_prepare_scratch_spaces(ilo->render, 587 vs_scratch_size, gs_scratch_size, fs_scratch_size); 588 589 ilo_blit_resolve_framebuffer(ilo); 590 591 /* If draw_vbo ever fails, return immediately. */ 592 if (!draw_vbo(ilo, &ilo->state_vector)) 593 return; 594 595 /* clear dirty status */ 596 ilo->state_vector.dirty = 0x0; 597 598 /* avoid dangling pointer reference */ 599 ilo->state_vector.draw = NULL; 600 601 if (ilo_debug & ILO_DEBUG_NOCACHE) 602 ilo_render_emit_flush(ilo->render); 603 } 604 605 static void 606 ilo_texture_barrier(struct pipe_context *pipe, unsigned flags) 607 { 608 struct ilo_context *ilo = ilo_context(pipe); 609 610 if (ilo->cp->ring != INTEL_RING_RENDER) 611 return; 612 613 ilo_render_emit_flush(ilo->render); 614 615 /* don't know why */ 616 if (ilo_dev_gen(ilo->dev) >= ILO_GEN(7)) 617 ilo_cp_submit(ilo->cp, "texture barrier"); 618 } 619 620 static void 621 ilo_get_sample_position(struct pipe_context *pipe, 622 unsigned sample_count, 623 unsigned sample_index, 624 float *out_value) 625 { 626 struct ilo_context *ilo = ilo_context(pipe); 627 628 ilo_render_get_sample_position(ilo->render, 629 sample_count, sample_index, 630 &out_value[0], &out_value[1]); 631 } 632 633 void 634 ilo_init_draw(struct ilo_context *ilo) 635 { 636 ilo->draw.cp_owner.own = ilo_draw_own_cp; 637 ilo->draw.cp_owner.release = ilo_draw_release_cp; 638 ilo->draw.cp_owner.data = (void *) ilo; 639 ilo->draw.cp_owner.reserve = 0; 640 641 list_inithead(&ilo->draw.queries); 642 } 643 644 /** 645 * Initialize 3D-related functions. 646 */ 647 void 648 ilo_init_draw_functions(struct ilo_context *ilo) 649 { 650 ilo->base.draw_vbo = ilo_draw_vbo; 651 ilo->base.texture_barrier = ilo_texture_barrier; 652 ilo->base.get_sample_position = ilo_get_sample_position; 653 } 654