anv_queue.c revision 7ec681f3
1/* 2 * Copyright © 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24/** 25 * This file implements VkQueue, VkFence, and VkSemaphore 26 */ 27 28#include <errno.h> 29#include <fcntl.h> 30#include <unistd.h> 31 32#include "util/os_file.h" 33 34#include "anv_private.h" 35#include "anv_measure.h" 36#include "vk_util.h" 37 38#include "genxml/gen7_pack.h" 39 40uint64_t anv_gettime_ns(void) 41{ 42 struct timespec current; 43 clock_gettime(CLOCK_MONOTONIC, ¤t); 44 return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec; 45} 46 47uint64_t anv_get_absolute_timeout(uint64_t timeout) 48{ 49 if (timeout == 0) 50 return 0; 51 uint64_t current_time = anv_gettime_ns(); 52 uint64_t max_timeout = (uint64_t) INT64_MAX - current_time; 53 54 timeout = MIN2(max_timeout, timeout); 55 56 return (current_time + timeout); 57} 58 59static int64_t anv_get_relative_timeout(uint64_t abs_timeout) 60{ 61 uint64_t now = anv_gettime_ns(); 62 63 /* We don't want negative timeouts. 64 * 65 * DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is 66 * supposed to block indefinitely timeouts < 0. Unfortunately, 67 * this was broken for a couple of kernel releases. Since there's 68 * no way to know whether or not the kernel we're using is one of 69 * the broken ones, the best we can do is to clamp the timeout to 70 * INT64_MAX. This limits the maximum timeout from 584 years to 71 * 292 years - likely not a big deal. 72 */ 73 if (abs_timeout < now) 74 return 0; 75 76 uint64_t rel_timeout = abs_timeout - now; 77 if (rel_timeout > (uint64_t) INT64_MAX) 78 rel_timeout = INT64_MAX; 79 80 return rel_timeout; 81} 82 83static void anv_semaphore_impl_cleanup(struct anv_device *device, 84 struct anv_semaphore_impl *impl); 85 86static void 87anv_queue_submit_free(struct anv_device *device, 88 struct anv_queue_submit *submit) 89{ 90 const VkAllocationCallbacks *alloc = submit->alloc; 91 92 for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++) 93 anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]); 94 /* Execbuf does not consume the in_fence. It's our job to close it. */ 95 if (submit->in_fence != -1) { 96 assert(!device->has_thread_submit); 97 close(submit->in_fence); 98 } 99 if (submit->out_fence != -1) { 100 assert(!device->has_thread_submit); 101 close(submit->out_fence); 102 } 103 vk_free(alloc, submit->fences); 104 vk_free(alloc, submit->fence_values); 105 vk_free(alloc, submit->temporary_semaphores); 106 vk_free(alloc, submit->wait_timelines); 107 vk_free(alloc, submit->wait_timeline_values); 108 vk_free(alloc, submit->signal_timelines); 109 vk_free(alloc, submit->signal_timeline_values); 110 vk_free(alloc, submit->fence_bos); 111 vk_free(alloc, submit->cmd_buffers); 112 vk_free(alloc, submit); 113} 114 115static bool 116anv_queue_submit_ready_locked(struct anv_queue_submit *submit) 117{ 118 for (uint32_t i = 0; i < submit->wait_timeline_count; i++) { 119 if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending) 120 return false; 121 } 122 123 return true; 124} 125 126static VkResult 127anv_timeline_init(struct anv_device *device, 128 struct anv_timeline *timeline, 129 uint64_t initial_value) 130{ 131 timeline->highest_past = 132 timeline->highest_pending = initial_value; 133 list_inithead(&timeline->points); 134 list_inithead(&timeline->free_points); 135 136 return VK_SUCCESS; 137} 138 139static void 140anv_timeline_finish(struct anv_device *device, 141 struct anv_timeline *timeline) 142{ 143 list_for_each_entry_safe(struct anv_timeline_point, point, 144 &timeline->free_points, link) { 145 list_del(&point->link); 146 anv_device_release_bo(device, point->bo); 147 vk_free(&device->vk.alloc, point); 148 } 149 list_for_each_entry_safe(struct anv_timeline_point, point, 150 &timeline->points, link) { 151 list_del(&point->link); 152 anv_device_release_bo(device, point->bo); 153 vk_free(&device->vk.alloc, point); 154 } 155} 156 157static VkResult 158anv_timeline_add_point_locked(struct anv_device *device, 159 struct anv_timeline *timeline, 160 uint64_t value, 161 struct anv_timeline_point **point) 162{ 163 VkResult result = VK_SUCCESS; 164 165 if (list_is_empty(&timeline->free_points)) { 166 *point = 167 vk_zalloc(&device->vk.alloc, sizeof(**point), 168 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 169 if (!(*point)) 170 result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 171 if (result == VK_SUCCESS) { 172 result = anv_device_alloc_bo(device, "timeline-semaphore", 4096, 173 ANV_BO_ALLOC_EXTERNAL | 174 ANV_BO_ALLOC_IMPLICIT_SYNC, 175 0 /* explicit_address */, 176 &(*point)->bo); 177 if (result != VK_SUCCESS) 178 vk_free(&device->vk.alloc, *point); 179 } 180 } else { 181 *point = list_first_entry(&timeline->free_points, 182 struct anv_timeline_point, link); 183 list_del(&(*point)->link); 184 } 185 186 if (result == VK_SUCCESS) { 187 (*point)->serial = value; 188 list_addtail(&(*point)->link, &timeline->points); 189 } 190 191 return result; 192} 193 194static VkResult 195anv_timeline_gc_locked(struct anv_device *device, 196 struct anv_timeline *timeline) 197{ 198 list_for_each_entry_safe(struct anv_timeline_point, point, 199 &timeline->points, link) { 200 /* timeline->higest_pending is only incremented once submission has 201 * happened. If this point has a greater serial, it means the point 202 * hasn't been submitted yet. 203 */ 204 if (point->serial > timeline->highest_pending) 205 return VK_SUCCESS; 206 207 /* If someone is waiting on this time point, consider it busy and don't 208 * try to recycle it. There's a slim possibility that it's no longer 209 * busy by the time we look at it but we would be recycling it out from 210 * under a waiter and that can lead to weird races. 211 * 212 * We walk the list in-order so if this time point is still busy so is 213 * every following time point 214 */ 215 assert(point->waiting >= 0); 216 if (point->waiting) 217 return VK_SUCCESS; 218 219 /* Garbage collect any signaled point. */ 220 VkResult result = anv_device_bo_busy(device, point->bo); 221 if (result == VK_NOT_READY) { 222 /* We walk the list in-order so if this time point is still busy so 223 * is every following time point 224 */ 225 return VK_SUCCESS; 226 } else if (result != VK_SUCCESS) { 227 return result; 228 } 229 230 assert(timeline->highest_past < point->serial); 231 timeline->highest_past = point->serial; 232 233 list_del(&point->link); 234 list_add(&point->link, &timeline->free_points); 235 } 236 237 return VK_SUCCESS; 238} 239 240static VkResult anv_queue_submit_add_fence_bo(struct anv_queue *queue, 241 struct anv_queue_submit *submit, 242 struct anv_bo *bo, 243 bool signal); 244 245static VkResult 246anv_queue_submit_timeline_locked(struct anv_queue *queue, 247 struct anv_queue_submit *submit) 248{ 249 VkResult result; 250 251 for (uint32_t i = 0; i < submit->wait_timeline_count; i++) { 252 struct anv_timeline *timeline = submit->wait_timelines[i]; 253 uint64_t wait_value = submit->wait_timeline_values[i]; 254 255 if (timeline->highest_past >= wait_value) 256 continue; 257 258 list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) { 259 if (point->serial < wait_value) 260 continue; 261 result = anv_queue_submit_add_fence_bo(queue, submit, point->bo, false); 262 if (result != VK_SUCCESS) 263 return result; 264 break; 265 } 266 } 267 for (uint32_t i = 0; i < submit->signal_timeline_count; i++) { 268 struct anv_timeline *timeline = submit->signal_timelines[i]; 269 uint64_t signal_value = submit->signal_timeline_values[i]; 270 struct anv_timeline_point *point; 271 272 result = anv_timeline_add_point_locked(queue->device, timeline, 273 signal_value, &point); 274 if (result != VK_SUCCESS) 275 return result; 276 277 result = anv_queue_submit_add_fence_bo(queue, submit, point->bo, true); 278 if (result != VK_SUCCESS) 279 return result; 280 } 281 282 result = anv_queue_execbuf_locked(queue, submit); 283 284 if (result == VK_SUCCESS) { 285 /* Update the pending values in the timeline objects. */ 286 for (uint32_t i = 0; i < submit->signal_timeline_count; i++) { 287 struct anv_timeline *timeline = submit->signal_timelines[i]; 288 uint64_t signal_value = submit->signal_timeline_values[i]; 289 290 assert(signal_value > timeline->highest_pending); 291 timeline->highest_pending = signal_value; 292 } 293 } else { 294 /* Unblock any waiter by signaling the points, the application will get 295 * a device lost error code. 296 */ 297 for (uint32_t i = 0; i < submit->signal_timeline_count; i++) { 298 struct anv_timeline *timeline = submit->signal_timelines[i]; 299 uint64_t signal_value = submit->signal_timeline_values[i]; 300 301 assert(signal_value > timeline->highest_pending); 302 timeline->highest_past = timeline->highest_pending = signal_value; 303 } 304 } 305 306 return result; 307} 308 309static VkResult 310anv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance) 311{ 312 VkResult result = VK_SUCCESS; 313 314 /* Go through all the queued submissions and submit then until we find one 315 * that's waiting on a point that hasn't materialized yet. 316 */ 317 list_for_each_entry_safe(struct anv_queue_submit, submit, 318 &queue->queued_submits, link) { 319 if (!anv_queue_submit_ready_locked(submit)) 320 break; 321 322 (*advance)++; 323 list_del(&submit->link); 324 325 result = anv_queue_submit_timeline_locked(queue, submit); 326 327 anv_queue_submit_free(queue->device, submit); 328 329 if (result != VK_SUCCESS) 330 break; 331 } 332 333 return result; 334} 335 336static VkResult 337anv_device_submit_deferred_locked(struct anv_device *device) 338{ 339 VkResult result = VK_SUCCESS; 340 341 uint32_t advance; 342 do { 343 advance = 0; 344 for (uint32_t i = 0; i < device->queue_count; i++) { 345 struct anv_queue *queue = &device->queues[i]; 346 VkResult qres = anv_queue_submit_deferred_locked(queue, &advance); 347 if (qres != VK_SUCCESS) 348 result = qres; 349 } 350 } while (advance); 351 352 return result; 353} 354 355static void 356anv_queue_submit_signal_fences(struct anv_device *device, 357 struct anv_queue_submit *submit) 358{ 359 for (uint32_t i = 0; i < submit->fence_count; i++) { 360 if (submit->fences[i].flags & I915_EXEC_FENCE_SIGNAL) { 361 anv_gem_syncobj_timeline_signal(device, &submit->fences[i].handle, 362 &submit->fence_values[i], 1); 363 } 364 } 365} 366 367static void * 368anv_queue_task(void *_queue) 369{ 370 struct anv_queue *queue = _queue; 371 372 pthread_mutex_lock(&queue->mutex); 373 374 while (!queue->quit) { 375 while (!list_is_empty(&queue->queued_submits)) { 376 struct anv_queue_submit *submit = 377 list_first_entry(&queue->queued_submits, struct anv_queue_submit, link); 378 list_del(&submit->link); 379 380 pthread_mutex_unlock(&queue->mutex); 381 382 VkResult result = VK_ERROR_DEVICE_LOST; 383 384 /* Wait for timeline points to materialize before submitting. We need 385 * to do this because we're using threads to do the submit to i915. 386 * We could end up in a situation where the application submits to 2 387 * queues with the first submit creating the dma-fence for the 388 * second. But because the scheduling of the submission threads might 389 * wakeup the second queue thread first, this would make that execbuf 390 * fail because the dma-fence it depends on hasn't materialized yet. 391 */ 392 if (!queue->lost && submit->wait_timeline_count > 0) { 393 int ret = queue->device->info.no_hw ? 0 : 394 anv_gem_syncobj_timeline_wait( 395 queue->device, submit->wait_timeline_syncobjs, 396 submit->wait_timeline_values, submit->wait_timeline_count, 397 anv_get_absolute_timeout(UINT64_MAX) /* wait forever */, 398 true /* wait for all */, true /* wait for materialize */); 399 if (ret) { 400 result = anv_queue_set_lost(queue, "timeline timeout: %s", 401 strerror(errno)); 402 } 403 } 404 405 /* Now submit */ 406 if (!queue->lost) { 407 pthread_mutex_lock(&queue->device->mutex); 408 result = anv_queue_execbuf_locked(queue, submit); 409 pthread_mutex_unlock(&queue->device->mutex); 410 } 411 412 if (result != VK_SUCCESS) { 413 /* vkQueueSubmit or some other entry point will report the 414 * DEVICE_LOST error at some point, but until we have emptied our 415 * list of execbufs we need to wake up all potential the waiters 416 * until one of them spots the error. 417 */ 418 anv_queue_submit_signal_fences(queue->device, submit); 419 } 420 421 anv_queue_submit_free(queue->device, submit); 422 423 pthread_mutex_lock(&queue->mutex); 424 } 425 426 if (!queue->quit) 427 pthread_cond_wait(&queue->cond, &queue->mutex); 428 } 429 430 pthread_mutex_unlock(&queue->mutex); 431 432 return NULL; 433} 434 435static VkResult 436anv_queue_submit_post(struct anv_queue *queue, 437 struct anv_queue_submit **_submit, 438 bool flush_queue) 439{ 440 struct anv_queue_submit *submit = *_submit; 441 442 /* Wait before signal behavior means we might keep alive the 443 * anv_queue_submit object a bit longer, so transfer the ownership to the 444 * anv_queue. 445 */ 446 *_submit = NULL; 447 if (queue->device->has_thread_submit) { 448 pthread_mutex_lock(&queue->mutex); 449 pthread_cond_broadcast(&queue->cond); 450 list_addtail(&submit->link, &queue->queued_submits); 451 pthread_mutex_unlock(&queue->mutex); 452 return VK_SUCCESS; 453 } else { 454 pthread_mutex_lock(&queue->device->mutex); 455 list_addtail(&submit->link, &queue->queued_submits); 456 VkResult result = anv_device_submit_deferred_locked(queue->device); 457 if (flush_queue) { 458 while (result == VK_SUCCESS && !list_is_empty(&queue->queued_submits)) { 459 int ret = pthread_cond_wait(&queue->device->queue_submit, 460 &queue->device->mutex); 461 if (ret != 0) { 462 result = anv_device_set_lost(queue->device, "wait timeout"); 463 break; 464 } 465 466 result = anv_device_submit_deferred_locked(queue->device); 467 } 468 } 469 pthread_mutex_unlock(&queue->device->mutex); 470 return result; 471 } 472} 473 474VkResult 475anv_queue_init(struct anv_device *device, struct anv_queue *queue, 476 uint32_t exec_flags, 477 const VkDeviceQueueCreateInfo *pCreateInfo, 478 uint32_t index_in_family) 479{ 480 struct anv_physical_device *pdevice = device->physical; 481 VkResult result; 482 483 result = vk_queue_init(&queue->vk, &device->vk, pCreateInfo, 484 index_in_family); 485 if (result != VK_SUCCESS) 486 return result; 487 488 queue->device = device; 489 490 assert(queue->vk.queue_family_index < pdevice->queue.family_count); 491 queue->family = &pdevice->queue.families[queue->vk.queue_family_index]; 492 493 queue->exec_flags = exec_flags; 494 queue->lost = false; 495 queue->quit = false; 496 497 list_inithead(&queue->queued_submits); 498 499 /* We only need those additional thread/mutex when using a thread for 500 * submission. 501 */ 502 if (device->has_thread_submit) { 503 if (pthread_mutex_init(&queue->mutex, NULL) != 0) { 504 result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED); 505 goto fail_queue; 506 } 507 if (pthread_cond_init(&queue->cond, NULL) != 0) { 508 result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED); 509 goto fail_mutex; 510 } 511 if (pthread_create(&queue->thread, NULL, anv_queue_task, queue)) { 512 result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED); 513 goto fail_cond; 514 } 515 } 516 517 return VK_SUCCESS; 518 519 fail_cond: 520 pthread_cond_destroy(&queue->cond); 521 fail_mutex: 522 pthread_mutex_destroy(&queue->mutex); 523 fail_queue: 524 vk_queue_finish(&queue->vk); 525 526 return result; 527} 528 529void 530anv_queue_finish(struct anv_queue *queue) 531{ 532 if (queue->device->has_thread_submit) { 533 pthread_mutex_lock(&queue->mutex); 534 pthread_cond_broadcast(&queue->cond); 535 queue->quit = true; 536 pthread_mutex_unlock(&queue->mutex); 537 538 void *ret; 539 pthread_join(queue->thread, &ret); 540 541 pthread_cond_destroy(&queue->cond); 542 pthread_mutex_destroy(&queue->mutex); 543 } 544 545 vk_queue_finish(&queue->vk); 546} 547 548static VkResult 549anv_queue_submit_add_fence_bo(struct anv_queue *queue, 550 struct anv_queue_submit *submit, 551 struct anv_bo *bo, 552 bool signal) 553{ 554 if (submit->fence_bo_count >= submit->fence_bo_array_length) { 555 uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64); 556 uintptr_t *new_fence_bos = 557 vk_realloc(submit->alloc, 558 submit->fence_bos, new_len * sizeof(*submit->fence_bos), 559 8, submit->alloc_scope); 560 if (new_fence_bos == NULL) 561 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 562 563 submit->fence_bos = new_fence_bos; 564 submit->fence_bo_array_length = new_len; 565 } 566 567 /* Take advantage that anv_bo are allocated at 8 byte alignement so we can 568 * use the lowest bit to store whether this is a BO we need to signal. 569 */ 570 submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal); 571 572 return VK_SUCCESS; 573} 574 575static VkResult 576anv_queue_submit_add_syncobj(struct anv_queue *queue, 577 struct anv_queue_submit* submit, 578 uint32_t handle, uint32_t flags, 579 uint64_t value) 580{ 581 assert(flags != 0); 582 583 if (queue->device->has_thread_submit && (flags & I915_EXEC_FENCE_WAIT)) { 584 if (submit->wait_timeline_count >= submit->wait_timeline_array_length) { 585 uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64); 586 587 uint32_t *new_wait_timeline_syncobjs = 588 vk_realloc(submit->alloc, 589 submit->wait_timeline_syncobjs, 590 new_len * sizeof(*submit->wait_timeline_syncobjs), 591 8, submit->alloc_scope); 592 if (new_wait_timeline_syncobjs == NULL) 593 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 594 595 submit->wait_timeline_syncobjs = new_wait_timeline_syncobjs; 596 597 uint64_t *new_wait_timeline_values = 598 vk_realloc(submit->alloc, 599 submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values), 600 8, submit->alloc_scope); 601 if (new_wait_timeline_values == NULL) 602 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 603 604 submit->wait_timeline_values = new_wait_timeline_values; 605 submit->wait_timeline_array_length = new_len; 606 } 607 608 submit->wait_timeline_syncobjs[submit->wait_timeline_count] = handle; 609 submit->wait_timeline_values[submit->wait_timeline_count] = value; 610 611 submit->wait_timeline_count++; 612 } 613 614 if (submit->fence_count >= submit->fence_array_length) { 615 uint32_t new_len = MAX2(submit->fence_array_length * 2, 64); 616 struct drm_i915_gem_exec_fence *new_fences = 617 vk_realloc(submit->alloc, 618 submit->fences, new_len * sizeof(*submit->fences), 619 8, submit->alloc_scope); 620 if (new_fences == NULL) 621 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 622 623 submit->fences = new_fences; 624 625 uint64_t *new_fence_values = 626 vk_realloc(submit->alloc, 627 submit->fence_values, new_len * sizeof(*submit->fence_values), 628 8, submit->alloc_scope); 629 if (new_fence_values == NULL) 630 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 631 632 submit->fence_values = new_fence_values; 633 submit->fence_array_length = new_len; 634 } 635 636 submit->fences[submit->fence_count] = (struct drm_i915_gem_exec_fence) { 637 .handle = handle, 638 .flags = flags, 639 }; 640 submit->fence_values[submit->fence_count] = value; 641 submit->fence_count++; 642 643 return VK_SUCCESS; 644} 645 646static VkResult 647anv_queue_submit_add_timeline_wait(struct anv_queue *queue, 648 struct anv_queue_submit* submit, 649 struct anv_timeline *timeline, 650 uint64_t value) 651{ 652 if (submit->wait_timeline_count >= submit->wait_timeline_array_length) { 653 uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64); 654 struct anv_timeline **new_wait_timelines = 655 vk_realloc(submit->alloc, 656 submit->wait_timelines, new_len * sizeof(*submit->wait_timelines), 657 8, submit->alloc_scope); 658 if (new_wait_timelines == NULL) 659 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 660 661 submit->wait_timelines = new_wait_timelines; 662 663 uint64_t *new_wait_timeline_values = 664 vk_realloc(submit->alloc, 665 submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values), 666 8, submit->alloc_scope); 667 if (new_wait_timeline_values == NULL) 668 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 669 670 submit->wait_timeline_values = new_wait_timeline_values; 671 672 submit->wait_timeline_array_length = new_len; 673 } 674 675 submit->wait_timelines[submit->wait_timeline_count] = timeline; 676 submit->wait_timeline_values[submit->wait_timeline_count] = value; 677 678 submit->wait_timeline_count++; 679 680 return VK_SUCCESS; 681} 682 683static VkResult 684anv_queue_submit_add_timeline_signal(struct anv_queue *queue, 685 struct anv_queue_submit* submit, 686 struct anv_timeline *timeline, 687 uint64_t value) 688{ 689 assert(timeline->highest_pending < value); 690 691 if (submit->signal_timeline_count >= submit->signal_timeline_array_length) { 692 uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64); 693 struct anv_timeline **new_signal_timelines = 694 vk_realloc(submit->alloc, 695 submit->signal_timelines, new_len * sizeof(*submit->signal_timelines), 696 8, submit->alloc_scope); 697 if (new_signal_timelines == NULL) 698 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 699 700 submit->signal_timelines = new_signal_timelines; 701 702 uint64_t *new_signal_timeline_values = 703 vk_realloc(submit->alloc, 704 submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values), 705 8, submit->alloc_scope); 706 if (new_signal_timeline_values == NULL) 707 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 708 709 submit->signal_timeline_values = new_signal_timeline_values; 710 711 submit->signal_timeline_array_length = new_len; 712 } 713 714 submit->signal_timelines[submit->signal_timeline_count] = timeline; 715 submit->signal_timeline_values[submit->signal_timeline_count] = value; 716 717 submit->signal_timeline_count++; 718 719 return VK_SUCCESS; 720} 721 722static struct anv_queue_submit * 723anv_queue_submit_alloc(struct anv_device *device) 724{ 725 const VkAllocationCallbacks *alloc = &device->vk.alloc; 726 VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; 727 728 struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope); 729 if (!submit) 730 return NULL; 731 732 submit->alloc = alloc; 733 submit->alloc_scope = alloc_scope; 734 submit->in_fence = -1; 735 submit->out_fence = -1; 736 submit->perf_query_pass = -1; 737 738 return submit; 739} 740 741VkResult 742anv_queue_submit_simple_batch(struct anv_queue *queue, 743 struct anv_batch *batch) 744{ 745 if (queue->device->info.no_hw) 746 return VK_SUCCESS; 747 748 struct anv_device *device = queue->device; 749 struct anv_queue_submit *submit = anv_queue_submit_alloc(device); 750 if (!submit) 751 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 752 753 bool has_syncobj_wait = device->physical->has_syncobj_wait; 754 VkResult result; 755 uint32_t syncobj; 756 struct anv_bo *batch_bo, *sync_bo; 757 758 if (has_syncobj_wait) { 759 syncobj = anv_gem_syncobj_create(device, 0); 760 if (!syncobj) { 761 result = vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 762 goto err_free_submit; 763 } 764 765 result = anv_queue_submit_add_syncobj(queue, submit, syncobj, 766 I915_EXEC_FENCE_SIGNAL, 0); 767 } else { 768 result = anv_device_alloc_bo(device, "simple-batch-sync", 4096, 769 ANV_BO_ALLOC_EXTERNAL | 770 ANV_BO_ALLOC_IMPLICIT_SYNC, 771 0 /* explicit_address */, 772 &sync_bo); 773 if (result != VK_SUCCESS) 774 goto err_free_submit; 775 776 result = anv_queue_submit_add_fence_bo(queue, submit, sync_bo, 777 true /* signal */); 778 } 779 780 if (result != VK_SUCCESS) 781 goto err_destroy_sync_primitive; 782 783 if (batch) { 784 uint32_t size = align_u32(batch->next - batch->start, 8); 785 result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo); 786 if (result != VK_SUCCESS) 787 goto err_destroy_sync_primitive; 788 789 memcpy(batch_bo->map, batch->start, size); 790 if (!device->info.has_llc) 791 intel_flush_range(batch_bo->map, size); 792 793 submit->simple_bo = batch_bo; 794 submit->simple_bo_size = size; 795 } 796 797 result = anv_queue_submit_post(queue, &submit, true); 798 799 if (result == VK_SUCCESS) { 800 if (has_syncobj_wait) { 801 if (anv_gem_syncobj_wait(device, &syncobj, 1, 802 anv_get_absolute_timeout(INT64_MAX), true)) 803 result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m"); 804 anv_gem_syncobj_destroy(device, syncobj); 805 } else { 806 result = anv_device_wait(device, sync_bo, 807 anv_get_relative_timeout(INT64_MAX)); 808 anv_device_release_bo(device, sync_bo); 809 } 810 } 811 812 if (batch) 813 anv_bo_pool_free(&device->batch_bo_pool, batch_bo); 814 815 if (submit) 816 anv_queue_submit_free(device, submit); 817 818 return result; 819 820 err_destroy_sync_primitive: 821 if (has_syncobj_wait) 822 anv_gem_syncobj_destroy(device, syncobj); 823 else 824 anv_device_release_bo(device, sync_bo); 825 err_free_submit: 826 if (submit) 827 anv_queue_submit_free(device, submit); 828 829 return result; 830} 831 832static VkResult 833add_temporary_semaphore(struct anv_queue *queue, 834 struct anv_queue_submit *submit, 835 struct anv_semaphore_impl *impl, 836 struct anv_semaphore_impl **out_impl) 837{ 838 /* 839 * There is a requirement to reset semaphore to their permanent state after 840 * submission. From the Vulkan 1.0.53 spec: 841 * 842 * "If the import is temporary, the implementation must restore the 843 * semaphore to its prior permanent state after submitting the next 844 * semaphore wait operation." 845 * 846 * In the case we defer the actual submission to a thread because of the 847 * wait-before-submit behavior required for timeline semaphores, we need to 848 * make copies of the temporary syncobj to ensure they stay alive until we 849 * do the actual execbuffer ioctl. 850 */ 851 if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) { 852 uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8); 853 /* Make sure that if the realloc fails, we still have the old semaphore 854 * array around to properly clean things up on failure. 855 */ 856 struct anv_semaphore_impl *new_array = 857 vk_realloc(submit->alloc, 858 submit->temporary_semaphores, 859 new_len * sizeof(*submit->temporary_semaphores), 860 8, submit->alloc_scope); 861 if (new_array == NULL) 862 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 863 864 submit->temporary_semaphores = new_array; 865 submit->temporary_semaphore_array_length = new_len; 866 } 867 868 /* Copy anv_semaphore_impl into anv_queue_submit. */ 869 submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl; 870 *out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1]; 871 872 return VK_SUCCESS; 873} 874 875static VkResult 876clone_syncobj_dma_fence(struct anv_queue *queue, 877 struct anv_semaphore_impl *out, 878 const struct anv_semaphore_impl *in) 879{ 880 struct anv_device *device = queue->device; 881 882 out->syncobj = anv_gem_syncobj_create(device, 0); 883 if (!out->syncobj) 884 return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 885 886 int fd = anv_gem_syncobj_export_sync_file(device, in->syncobj); 887 if (fd < 0) { 888 anv_gem_syncobj_destroy(device, out->syncobj); 889 return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 890 } 891 892 int ret = anv_gem_syncobj_import_sync_file(device, 893 out->syncobj, 894 fd); 895 close(fd); 896 if (ret < 0) { 897 anv_gem_syncobj_destroy(device, out->syncobj); 898 return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 899 } 900 901 return VK_SUCCESS; 902} 903 904/* Clone semaphore in the following cases : 905 * 906 * - We're dealing with a temporary semaphore that needs to be reset to 907 * follow the Vulkan spec requirements. 908 * 909 * - We're dealing with a syncobj semaphore and are using threaded 910 * submission to i915. Because we might want to export the semaphore right 911 * after calling vkQueueSubmit, we need to make sure it doesn't contain a 912 * staled DMA fence. In this case we reset the original syncobj, but make 913 * a clone of the contained DMA fence into another syncobj for submission 914 * to i915. 915 * 916 * Those temporary semaphores are later freed in anv_queue_submit_free(). 917 */ 918static VkResult 919maybe_transfer_temporary_semaphore(struct anv_queue *queue, 920 struct anv_queue_submit *submit, 921 struct anv_semaphore *semaphore, 922 struct anv_semaphore_impl **out_impl) 923{ 924 struct anv_semaphore_impl *impl = &semaphore->temporary; 925 VkResult result; 926 927 if (impl->type == ANV_SEMAPHORE_TYPE_NONE) { 928 /* No temporary, use the permanent semaphore. */ 929 impl = &semaphore->permanent; 930 931 /* We need to reset syncobj before submission so that they do not 932 * contain a stale DMA fence. When using a submission thread this is 933 * problematic because the i915 EXECBUF ioctl happens after 934 * vkQueueSubmit has returned. A subsequent vkQueueSubmit() call could 935 * reset the syncobj that i915 is about to see from the submission 936 * thread. 937 * 938 * To avoid this, clone the DMA fence in the semaphore, into a another 939 * syncobj that the submission thread will destroy when it's done with 940 * it. 941 */ 942 if (queue->device->physical->has_thread_submit && 943 impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ) { 944 struct anv_semaphore_impl template = { 945 .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ, 946 }; 947 948 /* Put the fence into a new syncobj so the old one can be reset. */ 949 result = clone_syncobj_dma_fence(queue, &template, impl); 950 if (result != VK_SUCCESS) 951 return result; 952 953 /* Create a copy of the anv_semaphore structure. */ 954 result = add_temporary_semaphore(queue, submit, &template, out_impl); 955 if (result != VK_SUCCESS) { 956 anv_gem_syncobj_destroy(queue->device, template.syncobj); 957 return result; 958 } 959 960 return VK_SUCCESS; 961 } 962 963 *out_impl = impl; 964 return VK_SUCCESS; 965 } 966 967 /* BO backed timeline semaphores cannot be temporary. */ 968 assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE); 969 970 /* Copy anv_semaphore_impl into anv_queue_submit. */ 971 result = add_temporary_semaphore(queue, submit, impl, out_impl); 972 if (result != VK_SUCCESS) 973 return result; 974 975 /* Clear the incoming semaphore */ 976 impl->type = ANV_SEMAPHORE_TYPE_NONE; 977 978 return VK_SUCCESS; 979} 980 981static VkResult 982anv_queue_submit_add_in_semaphore(struct anv_queue *queue, 983 struct anv_queue_submit *submit, 984 const VkSemaphore _semaphore, 985 const uint64_t value) 986{ 987 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 988 struct anv_semaphore_impl *impl = 989 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 990 &semaphore->temporary : &semaphore->permanent; 991 VkResult result; 992 993 /* When using a binary semaphore with threaded submission, wait for the 994 * dma-fence to materialize in the syncobj. This is needed to be able to 995 * clone in maybe_transfer_temporary_semaphore(). 996 */ 997 if (queue->device->has_thread_submit && 998 impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ) { 999 uint64_t value = 0; 1000 int ret = 1001 anv_gem_syncobj_timeline_wait(queue->device, 1002 &impl->syncobj, &value, 1, 1003 anv_get_absolute_timeout(INT64_MAX), 1004 true /* wait_all */, 1005 true /* wait_materialize */); 1006 if (ret != 0) { 1007 return anv_queue_set_lost(queue, 1008 "unable to wait on syncobj to materialize"); 1009 } 1010 } 1011 1012 result = maybe_transfer_temporary_semaphore(queue, submit, semaphore, &impl); 1013 if (result != VK_SUCCESS) 1014 return result; 1015 1016 switch (impl->type) { 1017 case ANV_SEMAPHORE_TYPE_WSI_BO: 1018 /* When using a window-system buffer as a semaphore, always enable 1019 * EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or 1020 * compositor's read of the buffer and enforces that we don't start 1021 * rendering until they are finished. This is exactly the 1022 * synchronization we want with vkAcquireNextImage. 1023 */ 1024 result = anv_queue_submit_add_fence_bo(queue, submit, impl->bo, 1025 true /* signal */); 1026 if (result != VK_SUCCESS) 1027 return result; 1028 break; 1029 1030 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: 1031 result = anv_queue_submit_add_syncobj(queue, submit, 1032 impl->syncobj, 1033 I915_EXEC_FENCE_WAIT, 1034 0); 1035 if (result != VK_SUCCESS) 1036 return result; 1037 break; 1038 1039 case ANV_SEMAPHORE_TYPE_TIMELINE: 1040 if (value == 0) 1041 break; 1042 result = anv_queue_submit_add_timeline_wait(queue, submit, 1043 &impl->timeline, 1044 value); 1045 if (result != VK_SUCCESS) 1046 return result; 1047 break; 1048 1049 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 1050 if (value == 0) 1051 break; 1052 result = anv_queue_submit_add_syncobj(queue, submit, 1053 impl->syncobj, 1054 I915_EXEC_FENCE_WAIT, 1055 value); 1056 if (result != VK_SUCCESS) 1057 return result; 1058 break; 1059 1060 default: 1061 break; 1062 } 1063 1064 return VK_SUCCESS; 1065} 1066 1067static VkResult 1068anv_queue_submit_add_out_semaphore(struct anv_queue *queue, 1069 struct anv_queue_submit *submit, 1070 const VkSemaphore _semaphore, 1071 const uint64_t value) 1072{ 1073 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 1074 VkResult result; 1075 1076 /* Under most circumstances, out fences won't be temporary. However, the 1077 * spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec: 1078 * 1079 * "If the import is temporary, the implementation must restore the 1080 * semaphore to its prior permanent state after submitting the next 1081 * semaphore wait operation." 1082 * 1083 * The spec says nothing whatsoever about signal operations on temporarily 1084 * imported semaphores so it appears they are allowed. There are also CTS 1085 * tests that require this to work. 1086 */ 1087 struct anv_semaphore_impl *impl = 1088 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 1089 &semaphore->temporary : &semaphore->permanent; 1090 1091 switch (impl->type) { 1092 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: { 1093 /* 1094 * Reset the content of the syncobj so it doesn't contain a previously 1095 * signaled dma-fence, until one is added by EXECBUFFER by the 1096 * submission thread. 1097 */ 1098 anv_gem_syncobj_reset(queue->device, impl->syncobj); 1099 1100 result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj, 1101 I915_EXEC_FENCE_SIGNAL, 1102 0); 1103 if (result != VK_SUCCESS) 1104 return result; 1105 break; 1106 } 1107 1108 case ANV_SEMAPHORE_TYPE_TIMELINE: 1109 if (value == 0) 1110 break; 1111 result = anv_queue_submit_add_timeline_signal(queue, submit, 1112 &impl->timeline, 1113 value); 1114 if (result != VK_SUCCESS) 1115 return result; 1116 break; 1117 1118 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 1119 if (value == 0) 1120 break; 1121 result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj, 1122 I915_EXEC_FENCE_SIGNAL, 1123 value); 1124 if (result != VK_SUCCESS) 1125 return result; 1126 break; 1127 1128 default: 1129 break; 1130 } 1131 1132 return VK_SUCCESS; 1133} 1134 1135static VkResult 1136anv_queue_submit_add_fence(struct anv_queue *queue, 1137 struct anv_queue_submit *submit, 1138 struct anv_fence *fence) 1139{ 1140 /* Under most circumstances, out fences won't be temporary. However, the 1141 * spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec: 1142 * 1143 * "If the import is temporary, the implementation must restore the 1144 * semaphore to its prior permanent state after submitting the next 1145 * semaphore wait operation." 1146 * 1147 * The spec says nothing whatsoever about signal operations on temporarily 1148 * imported semaphores so it appears they are allowed. There are also CTS 1149 * tests that require this to work. 1150 */ 1151 struct anv_fence_impl *impl = 1152 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1153 &fence->temporary : &fence->permanent; 1154 1155 VkResult result; 1156 1157 switch (impl->type) { 1158 case ANV_FENCE_TYPE_BO: 1159 assert(!queue->device->has_thread_submit); 1160 result = anv_queue_submit_add_fence_bo(queue, submit, impl->bo.bo, 1161 true /* signal */); 1162 if (result != VK_SUCCESS) 1163 return result; 1164 break; 1165 1166 case ANV_FENCE_TYPE_SYNCOBJ: { 1167 /* 1168 * For the same reason we reset the signaled binary syncobj above, also 1169 * reset the fence's syncobj so that they don't contain a signaled 1170 * dma-fence. 1171 */ 1172 anv_gem_syncobj_reset(queue->device, impl->syncobj); 1173 1174 result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj, 1175 I915_EXEC_FENCE_SIGNAL, 1176 0); 1177 if (result != VK_SUCCESS) 1178 return result; 1179 break; 1180 } 1181 1182 default: 1183 unreachable("Invalid fence type"); 1184 } 1185 1186 return VK_SUCCESS; 1187} 1188 1189static void 1190anv_post_queue_fence_update(struct anv_device *device, struct anv_fence *fence) 1191{ 1192 if (fence->permanent.type == ANV_FENCE_TYPE_BO) { 1193 assert(!device->has_thread_submit); 1194 /* If we have permanent BO fence, the only type of temporary possible 1195 * would be BO_WSI (because BO fences are not shareable). The Vulkan spec 1196 * also requires that the fence passed to vkQueueSubmit() be : 1197 * 1198 * * unsignaled 1199 * * not be associated with any other queue command that has not yet 1200 * completed execution on that queue 1201 * 1202 * So the only acceptable type for the temporary is NONE. 1203 */ 1204 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE); 1205 1206 /* Once the execbuf has returned, we need to set the fence state to 1207 * SUBMITTED. We can't do this before calling execbuf because 1208 * anv_GetFenceStatus does take the global device lock before checking 1209 * fence->state. 1210 * 1211 * We set the fence state to SUBMITTED regardless of whether or not the 1212 * execbuf succeeds because we need to ensure that vkWaitForFences() and 1213 * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or 1214 * VK_SUCCESS) in a finite amount of time even if execbuf fails. 1215 */ 1216 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED; 1217 } 1218} 1219 1220static VkResult 1221anv_queue_submit_add_cmd_buffer(struct anv_queue *queue, 1222 struct anv_queue_submit *submit, 1223 struct anv_cmd_buffer *cmd_buffer, 1224 int perf_pass) 1225{ 1226 if (submit->cmd_buffer_count >= submit->cmd_buffer_array_length) { 1227 uint32_t new_len = MAX2(submit->cmd_buffer_array_length * 2, 4); 1228 struct anv_cmd_buffer **new_cmd_buffers = 1229 vk_realloc(submit->alloc, 1230 submit->cmd_buffers, new_len * sizeof(*submit->cmd_buffers), 1231 8, submit->alloc_scope); 1232 if (new_cmd_buffers == NULL) 1233 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 1234 1235 submit->cmd_buffers = new_cmd_buffers; 1236 submit->cmd_buffer_array_length = new_len; 1237 } 1238 1239 submit->cmd_buffers[submit->cmd_buffer_count++] = cmd_buffer; 1240 /* Only update the perf_query_pool if there is one. We can decide to batch 1241 * 2 command buffers if the second one doesn't use a query pool, but we 1242 * can't drop the already chosen one. 1243 */ 1244 if (cmd_buffer->perf_query_pool) 1245 submit->perf_query_pool = cmd_buffer->perf_query_pool; 1246 submit->perf_query_pass = perf_pass; 1247 1248 return VK_SUCCESS; 1249} 1250 1251static bool 1252anv_queue_submit_can_add_cmd_buffer(const struct anv_queue_submit *submit, 1253 const struct anv_cmd_buffer *cmd_buffer, 1254 int perf_pass) 1255{ 1256 /* If first command buffer, no problem. */ 1257 if (submit->cmd_buffer_count == 0) 1258 return true; 1259 1260 /* Can we chain the last buffer into the next one? */ 1261 if (!anv_cmd_buffer_is_chainable(submit->cmd_buffers[submit->cmd_buffer_count - 1])) 1262 return false; 1263 1264 /* A change of perf query pools between VkSubmitInfo elements means we 1265 * can't batch things up. 1266 */ 1267 if (cmd_buffer->perf_query_pool && 1268 submit->perf_query_pool && 1269 submit->perf_query_pool != cmd_buffer->perf_query_pool) 1270 return false; 1271 1272 /* A change of perf pass also prevents batching things up. 1273 */ 1274 if (submit->perf_query_pass != -1 && 1275 submit->perf_query_pass != perf_pass) 1276 return false; 1277 1278 return true; 1279} 1280 1281static bool 1282anv_queue_submit_can_add_submit(const struct anv_queue_submit *submit, 1283 uint32_t n_wait_semaphores, 1284 uint32_t n_signal_semaphores, 1285 int perf_pass) 1286{ 1287 /* We can add to an empty anv_queue_submit. */ 1288 if (submit->cmd_buffer_count == 0 && 1289 submit->fence_count == 0 && 1290 submit->wait_timeline_count == 0 && 1291 submit->signal_timeline_count == 0 && 1292 submit->fence_bo_count == 0) 1293 return true; 1294 1295 /* Different perf passes will require different EXECBUF ioctls. */ 1296 if (perf_pass != submit->perf_query_pass) 1297 return false; 1298 1299 /* If the current submit is signaling anything, we can't add anything. */ 1300 if (submit->signal_timeline_count) 1301 return false; 1302 1303 /* If a submit is waiting on anything, anything that happened before needs 1304 * to be submitted. 1305 */ 1306 if (n_wait_semaphores) 1307 return false; 1308 1309 return true; 1310} 1311 1312static VkResult 1313anv_queue_submit_post_and_alloc_new(struct anv_queue *queue, 1314 struct anv_queue_submit **submit) 1315{ 1316 VkResult result = anv_queue_submit_post(queue, submit, false); 1317 if (result != VK_SUCCESS) 1318 return result; 1319 1320 *submit = anv_queue_submit_alloc(queue->device); 1321 if (!*submit) 1322 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 1323 return VK_SUCCESS; 1324} 1325 1326VkResult anv_QueueSubmit2KHR( 1327 VkQueue _queue, 1328 uint32_t submitCount, 1329 const VkSubmitInfo2KHR* pSubmits, 1330 VkFence _fence) 1331{ 1332 ANV_FROM_HANDLE(anv_queue, queue, _queue); 1333 ANV_FROM_HANDLE(anv_fence, fence, _fence); 1334 struct anv_device *device = queue->device; 1335 1336 if (device->info.no_hw) 1337 return VK_SUCCESS; 1338 1339 /* Query for device status prior to submitting. Technically, we don't need 1340 * to do this. However, if we have a client that's submitting piles of 1341 * garbage, we would rather break as early as possible to keep the GPU 1342 * hanging contained. If we don't check here, we'll either be waiting for 1343 * the kernel to kick us or we'll have to wait until the client waits on a 1344 * fence before we actually know whether or not we've hung. 1345 */ 1346 VkResult result = anv_device_query_status(device); 1347 if (result != VK_SUCCESS) 1348 return result; 1349 1350 struct anv_queue_submit *submit = anv_queue_submit_alloc(device); 1351 if (!submit) 1352 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 1353 1354 for (uint32_t i = 0; i < submitCount; i++) { 1355 const struct wsi_memory_signal_submit_info *mem_signal_info = 1356 vk_find_struct_const(pSubmits[i].pNext, 1357 WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA); 1358 struct anv_bo *wsi_signal_bo = 1359 mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ? 1360 anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL; 1361 1362 const VkPerformanceQuerySubmitInfoKHR *perf_info = 1363 vk_find_struct_const(pSubmits[i].pNext, 1364 PERFORMANCE_QUERY_SUBMIT_INFO_KHR); 1365 const int perf_pass = perf_info ? perf_info->counterPassIndex : 0; 1366 1367 if (!anv_queue_submit_can_add_submit(submit, 1368 pSubmits[i].waitSemaphoreInfoCount, 1369 pSubmits[i].signalSemaphoreInfoCount, 1370 perf_pass)) { 1371 result = anv_queue_submit_post_and_alloc_new(queue, &submit); 1372 if (result != VK_SUCCESS) 1373 goto out; 1374 } 1375 1376 /* Wait semaphores */ 1377 for (uint32_t j = 0; j < pSubmits[i].waitSemaphoreInfoCount; j++) { 1378 result = anv_queue_submit_add_in_semaphore(queue, submit, 1379 pSubmits[i].pWaitSemaphoreInfos[j].semaphore, 1380 pSubmits[i].pWaitSemaphoreInfos[j].value); 1381 if (result != VK_SUCCESS) 1382 goto out; 1383 } 1384 1385 /* Command buffers */ 1386 for (uint32_t j = 0; j < pSubmits[i].commandBufferInfoCount; j++) { 1387 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, 1388 pSubmits[i].pCommandBufferInfos[j].commandBuffer); 1389 assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY); 1390 assert(!anv_batch_has_error(&cmd_buffer->batch)); 1391 anv_measure_submit(cmd_buffer); 1392 1393 /* If we can't add an additional command buffer to the existing 1394 * anv_queue_submit, post it and create a new one. 1395 */ 1396 if (!anv_queue_submit_can_add_cmd_buffer(submit, cmd_buffer, perf_pass)) { 1397 result = anv_queue_submit_post_and_alloc_new(queue, &submit); 1398 if (result != VK_SUCCESS) 1399 goto out; 1400 } 1401 1402 result = anv_queue_submit_add_cmd_buffer(queue, submit, 1403 cmd_buffer, perf_pass); 1404 if (result != VK_SUCCESS) 1405 goto out; 1406 } 1407 1408 /* Signal semaphores */ 1409 for (uint32_t j = 0; j < pSubmits[i].signalSemaphoreInfoCount; j++) { 1410 result = anv_queue_submit_add_out_semaphore(queue, submit, 1411 pSubmits[i].pSignalSemaphoreInfos[j].semaphore, 1412 pSubmits[i].pSignalSemaphoreInfos[j].value); 1413 if (result != VK_SUCCESS) 1414 goto out; 1415 } 1416 1417 /* WSI BO */ 1418 if (wsi_signal_bo) { 1419 result = anv_queue_submit_add_fence_bo(queue, submit, wsi_signal_bo, 1420 true /* signal */); 1421 if (result != VK_SUCCESS) 1422 goto out; 1423 } 1424 } 1425 1426 if (fence) { 1427 result = anv_queue_submit_add_fence(queue, submit, fence); 1428 if (result != VK_SUCCESS) 1429 goto out; 1430 } 1431 1432 result = anv_queue_submit_post(queue, &submit, false); 1433 if (result != VK_SUCCESS) 1434 goto out; 1435 1436 if (fence) 1437 anv_post_queue_fence_update(device, fence); 1438 1439out: 1440 if (submit) 1441 anv_queue_submit_free(device, submit); 1442 1443 if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) { 1444 /* In the case that something has gone wrong we may end up with an 1445 * inconsistent state from which it may not be trivial to recover. 1446 * For example, we might have computed address relocations and 1447 * any future attempt to re-submit this job will need to know about 1448 * this and avoid computing relocation addresses again. 1449 * 1450 * To avoid this sort of issues, we assume that if something was 1451 * wrong during submission we must already be in a really bad situation 1452 * anyway (such us being out of memory) and return 1453 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to 1454 * submit the same job again to this device. 1455 * 1456 * We skip doing this on VK_ERROR_DEVICE_LOST because 1457 * anv_device_set_lost() would have been called already by a callee of 1458 * anv_queue_submit(). 1459 */ 1460 result = anv_device_set_lost(device, "vkQueueSubmit2KHR() failed"); 1461 } 1462 1463 return result; 1464} 1465 1466VkResult anv_QueueWaitIdle( 1467 VkQueue _queue) 1468{ 1469 ANV_FROM_HANDLE(anv_queue, queue, _queue); 1470 1471 if (anv_device_is_lost(queue->device)) 1472 return VK_ERROR_DEVICE_LOST; 1473 1474 return anv_queue_submit_simple_batch(queue, NULL); 1475} 1476 1477VkResult anv_CreateFence( 1478 VkDevice _device, 1479 const VkFenceCreateInfo* pCreateInfo, 1480 const VkAllocationCallbacks* pAllocator, 1481 VkFence* pFence) 1482{ 1483 ANV_FROM_HANDLE(anv_device, device, _device); 1484 struct anv_fence *fence; 1485 1486 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO); 1487 1488 fence = vk_object_zalloc(&device->vk, pAllocator, sizeof(*fence), 1489 VK_OBJECT_TYPE_FENCE); 1490 if (fence == NULL) 1491 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1492 1493 if (device->physical->has_syncobj_wait) { 1494 fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ; 1495 1496 uint32_t create_flags = 0; 1497 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) 1498 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 1499 1500 fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags); 1501 if (!fence->permanent.syncobj) 1502 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1503 } else { 1504 fence->permanent.type = ANV_FENCE_TYPE_BO; 1505 1506 VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096, 1507 &fence->permanent.bo.bo); 1508 if (result != VK_SUCCESS) 1509 return result; 1510 1511 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) { 1512 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED; 1513 } else { 1514 fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET; 1515 } 1516 } 1517 1518 *pFence = anv_fence_to_handle(fence); 1519 1520 return VK_SUCCESS; 1521} 1522 1523static void 1524anv_fence_impl_cleanup(struct anv_device *device, 1525 struct anv_fence_impl *impl) 1526{ 1527 switch (impl->type) { 1528 case ANV_FENCE_TYPE_NONE: 1529 /* Dummy. Nothing to do */ 1530 break; 1531 1532 case ANV_FENCE_TYPE_BO: 1533 anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo); 1534 break; 1535 1536 case ANV_FENCE_TYPE_WSI_BO: 1537 anv_device_release_bo(device, impl->bo.bo); 1538 break; 1539 1540 case ANV_FENCE_TYPE_SYNCOBJ: 1541 anv_gem_syncobj_destroy(device, impl->syncobj); 1542 break; 1543 1544 case ANV_FENCE_TYPE_WSI: 1545 impl->fence_wsi->destroy(impl->fence_wsi); 1546 break; 1547 1548 default: 1549 unreachable("Invalid fence type"); 1550 } 1551 1552 impl->type = ANV_FENCE_TYPE_NONE; 1553} 1554 1555void 1556anv_fence_reset_temporary(struct anv_device *device, 1557 struct anv_fence *fence) 1558{ 1559 if (fence->temporary.type == ANV_FENCE_TYPE_NONE) 1560 return; 1561 1562 anv_fence_impl_cleanup(device, &fence->temporary); 1563} 1564 1565void anv_DestroyFence( 1566 VkDevice _device, 1567 VkFence _fence, 1568 const VkAllocationCallbacks* pAllocator) 1569{ 1570 ANV_FROM_HANDLE(anv_device, device, _device); 1571 ANV_FROM_HANDLE(anv_fence, fence, _fence); 1572 1573 if (!fence) 1574 return; 1575 1576 anv_fence_impl_cleanup(device, &fence->temporary); 1577 anv_fence_impl_cleanup(device, &fence->permanent); 1578 1579 vk_object_free(&device->vk, pAllocator, fence); 1580} 1581 1582VkResult anv_ResetFences( 1583 VkDevice _device, 1584 uint32_t fenceCount, 1585 const VkFence* pFences) 1586{ 1587 ANV_FROM_HANDLE(anv_device, device, _device); 1588 1589 for (uint32_t i = 0; i < fenceCount; i++) { 1590 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1591 1592 /* From the Vulkan 1.0.53 spec: 1593 * 1594 * "If any member of pFences currently has its payload imported with 1595 * temporary permanence, that fence’s prior permanent payload is 1596 * first restored. The remaining operations described therefore 1597 * operate on the restored payload. 1598 */ 1599 anv_fence_reset_temporary(device, fence); 1600 1601 struct anv_fence_impl *impl = &fence->permanent; 1602 1603 switch (impl->type) { 1604 case ANV_FENCE_TYPE_BO: 1605 impl->bo.state = ANV_BO_FENCE_STATE_RESET; 1606 break; 1607 1608 case ANV_FENCE_TYPE_SYNCOBJ: 1609 anv_gem_syncobj_reset(device, impl->syncobj); 1610 break; 1611 1612 default: 1613 unreachable("Invalid fence type"); 1614 } 1615 } 1616 1617 return VK_SUCCESS; 1618} 1619 1620VkResult anv_GetFenceStatus( 1621 VkDevice _device, 1622 VkFence _fence) 1623{ 1624 ANV_FROM_HANDLE(anv_device, device, _device); 1625 ANV_FROM_HANDLE(anv_fence, fence, _fence); 1626 1627 if (anv_device_is_lost(device)) 1628 return VK_ERROR_DEVICE_LOST; 1629 1630 struct anv_fence_impl *impl = 1631 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1632 &fence->temporary : &fence->permanent; 1633 1634 switch (impl->type) { 1635 case ANV_FENCE_TYPE_BO: 1636 case ANV_FENCE_TYPE_WSI_BO: 1637 switch (impl->bo.state) { 1638 case ANV_BO_FENCE_STATE_RESET: 1639 /* If it hasn't even been sent off to the GPU yet, it's not ready */ 1640 return VK_NOT_READY; 1641 1642 case ANV_BO_FENCE_STATE_SIGNALED: 1643 /* It's been signaled, return success */ 1644 return VK_SUCCESS; 1645 1646 case ANV_BO_FENCE_STATE_SUBMITTED: { 1647 VkResult result = anv_device_bo_busy(device, impl->bo.bo); 1648 if (result == VK_SUCCESS) { 1649 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED; 1650 return VK_SUCCESS; 1651 } else { 1652 return result; 1653 } 1654 } 1655 default: 1656 unreachable("Invalid fence status"); 1657 } 1658 1659 case ANV_FENCE_TYPE_SYNCOBJ: { 1660 if (device->has_thread_submit) { 1661 uint64_t binary_value = 0; 1662 int ret = anv_gem_syncobj_timeline_wait(device, &impl->syncobj, 1663 &binary_value, 1, 0, 1664 true /* wait_all */, 1665 false /* wait_materialize */); 1666 if (ret == -1) { 1667 if (errno == ETIME) { 1668 return VK_NOT_READY; 1669 } else { 1670 /* We don't know the real error. */ 1671 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m"); 1672 } 1673 } else { 1674 return VK_SUCCESS; 1675 } 1676 } else { 1677 int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, false); 1678 if (ret == -1) { 1679 if (errno == ETIME) { 1680 return VK_NOT_READY; 1681 } else { 1682 /* We don't know the real error. */ 1683 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m"); 1684 } 1685 } else { 1686 return VK_SUCCESS; 1687 } 1688 } 1689 } 1690 1691 default: 1692 unreachable("Invalid fence type"); 1693 } 1694} 1695 1696static VkResult 1697anv_wait_for_syncobj_fences(struct anv_device *device, 1698 uint32_t fenceCount, 1699 const VkFence *pFences, 1700 bool waitAll, 1701 uint64_t abs_timeout_ns) 1702{ 1703 uint32_t *syncobjs = vk_zalloc(&device->vk.alloc, 1704 sizeof(*syncobjs) * fenceCount, 8, 1705 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 1706 if (!syncobjs) 1707 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1708 1709 for (uint32_t i = 0; i < fenceCount; i++) { 1710 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1711 assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ); 1712 1713 struct anv_fence_impl *impl = 1714 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1715 &fence->temporary : &fence->permanent; 1716 1717 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ); 1718 syncobjs[i] = impl->syncobj; 1719 } 1720 1721 int ret = 0; 1722 /* The gem_syncobj_wait ioctl may return early due to an inherent 1723 * limitation in the way it computes timeouts. Loop until we've actually 1724 * passed the timeout. 1725 */ 1726 do { 1727 ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount, 1728 abs_timeout_ns, waitAll); 1729 } while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns); 1730 1731 vk_free(&device->vk.alloc, syncobjs); 1732 1733 if (ret == -1) { 1734 if (errno == ETIME) { 1735 return VK_TIMEOUT; 1736 } else { 1737 /* We don't know the real error. */ 1738 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m"); 1739 } 1740 } else { 1741 return VK_SUCCESS; 1742 } 1743} 1744 1745static VkResult 1746anv_wait_for_bo_fences(struct anv_device *device, 1747 uint32_t fenceCount, 1748 const VkFence *pFences, 1749 bool waitAll, 1750 uint64_t abs_timeout_ns) 1751{ 1752 VkResult result = VK_SUCCESS; 1753 uint32_t pending_fences = fenceCount; 1754 while (pending_fences) { 1755 pending_fences = 0; 1756 bool signaled_fences = false; 1757 for (uint32_t i = 0; i < fenceCount; i++) { 1758 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1759 1760 struct anv_fence_impl *impl = 1761 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1762 &fence->temporary : &fence->permanent; 1763 assert(impl->type == ANV_FENCE_TYPE_BO || 1764 impl->type == ANV_FENCE_TYPE_WSI_BO); 1765 1766 switch (impl->bo.state) { 1767 case ANV_BO_FENCE_STATE_RESET: 1768 /* This fence hasn't been submitted yet, we'll catch it the next 1769 * time around. Yes, this may mean we dead-loop but, short of 1770 * lots of locking and a condition variable, there's not much that 1771 * we can do about that. 1772 */ 1773 pending_fences++; 1774 continue; 1775 1776 case ANV_BO_FENCE_STATE_SIGNALED: 1777 /* This fence is not pending. If waitAll isn't set, we can return 1778 * early. Otherwise, we have to keep going. 1779 */ 1780 if (!waitAll) { 1781 result = VK_SUCCESS; 1782 goto done; 1783 } 1784 continue; 1785 1786 case ANV_BO_FENCE_STATE_SUBMITTED: 1787 /* These are the fences we really care about. Go ahead and wait 1788 * on it until we hit a timeout. 1789 */ 1790 result = anv_device_wait(device, impl->bo.bo, 1791 anv_get_relative_timeout(abs_timeout_ns)); 1792 switch (result) { 1793 case VK_SUCCESS: 1794 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED; 1795 signaled_fences = true; 1796 if (!waitAll) 1797 goto done; 1798 break; 1799 1800 case VK_TIMEOUT: 1801 goto done; 1802 1803 default: 1804 return result; 1805 } 1806 } 1807 } 1808 1809 if (pending_fences && !signaled_fences) { 1810 /* If we've hit this then someone decided to vkWaitForFences before 1811 * they've actually submitted any of them to a queue. This is a 1812 * fairly pessimal case, so it's ok to lock here and use a standard 1813 * pthreads condition variable. 1814 */ 1815 pthread_mutex_lock(&device->mutex); 1816 1817 /* It's possible that some of the fences have changed state since the 1818 * last time we checked. Now that we have the lock, check for 1819 * pending fences again and don't wait if it's changed. 1820 */ 1821 uint32_t now_pending_fences = 0; 1822 for (uint32_t i = 0; i < fenceCount; i++) { 1823 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1824 if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET) 1825 now_pending_fences++; 1826 } 1827 assert(now_pending_fences <= pending_fences); 1828 1829 if (now_pending_fences == pending_fences) { 1830 struct timespec abstime = { 1831 .tv_sec = abs_timeout_ns / NSEC_PER_SEC, 1832 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC, 1833 }; 1834 1835 ASSERTED int ret; 1836 ret = pthread_cond_timedwait(&device->queue_submit, 1837 &device->mutex, &abstime); 1838 assert(ret != EINVAL); 1839 if (anv_gettime_ns() >= abs_timeout_ns) { 1840 pthread_mutex_unlock(&device->mutex); 1841 result = VK_TIMEOUT; 1842 goto done; 1843 } 1844 } 1845 1846 pthread_mutex_unlock(&device->mutex); 1847 } 1848 } 1849 1850done: 1851 if (anv_device_is_lost(device)) 1852 return VK_ERROR_DEVICE_LOST; 1853 1854 return result; 1855} 1856 1857static VkResult 1858anv_wait_for_wsi_fence(struct anv_device *device, 1859 struct anv_fence_impl *impl, 1860 uint64_t abs_timeout) 1861{ 1862 return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout); 1863} 1864 1865static VkResult 1866anv_wait_for_fences(struct anv_device *device, 1867 uint32_t fenceCount, 1868 const VkFence *pFences, 1869 bool waitAll, 1870 uint64_t abs_timeout) 1871{ 1872 VkResult result = VK_SUCCESS; 1873 1874 if (fenceCount <= 1 || waitAll) { 1875 for (uint32_t i = 0; i < fenceCount; i++) { 1876 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1877 struct anv_fence_impl *impl = 1878 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1879 &fence->temporary : &fence->permanent; 1880 1881 switch (impl->type) { 1882 case ANV_FENCE_TYPE_BO: 1883 assert(!device->physical->has_syncobj_wait); 1884 FALLTHROUGH; 1885 case ANV_FENCE_TYPE_WSI_BO: 1886 result = anv_wait_for_bo_fences(device, 1, &pFences[i], 1887 true, abs_timeout); 1888 break; 1889 case ANV_FENCE_TYPE_SYNCOBJ: 1890 result = anv_wait_for_syncobj_fences(device, 1, &pFences[i], 1891 true, abs_timeout); 1892 break; 1893 case ANV_FENCE_TYPE_WSI: 1894 result = anv_wait_for_wsi_fence(device, impl, abs_timeout); 1895 break; 1896 case ANV_FENCE_TYPE_NONE: 1897 result = VK_SUCCESS; 1898 break; 1899 } 1900 if (result != VK_SUCCESS) 1901 return result; 1902 } 1903 } else { 1904 do { 1905 for (uint32_t i = 0; i < fenceCount; i++) { 1906 if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS) 1907 return VK_SUCCESS; 1908 } 1909 } while (anv_gettime_ns() < abs_timeout); 1910 result = VK_TIMEOUT; 1911 } 1912 return result; 1913} 1914 1915static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences) 1916{ 1917 for (uint32_t i = 0; i < fenceCount; ++i) { 1918 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1919 struct anv_fence_impl *impl = 1920 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1921 &fence->temporary : &fence->permanent; 1922 if (impl->type != ANV_FENCE_TYPE_SYNCOBJ) 1923 return false; 1924 } 1925 return true; 1926} 1927 1928static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences) 1929{ 1930 for (uint32_t i = 0; i < fenceCount; ++i) { 1931 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 1932 struct anv_fence_impl *impl = 1933 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 1934 &fence->temporary : &fence->permanent; 1935 if (impl->type != ANV_FENCE_TYPE_BO && 1936 impl->type != ANV_FENCE_TYPE_WSI_BO) 1937 return false; 1938 } 1939 return true; 1940} 1941 1942VkResult anv_WaitForFences( 1943 VkDevice _device, 1944 uint32_t fenceCount, 1945 const VkFence* pFences, 1946 VkBool32 waitAll, 1947 uint64_t timeout) 1948{ 1949 ANV_FROM_HANDLE(anv_device, device, _device); 1950 1951 if (device->info.no_hw) 1952 return VK_SUCCESS; 1953 1954 if (anv_device_is_lost(device)) 1955 return VK_ERROR_DEVICE_LOST; 1956 1957 uint64_t abs_timeout = anv_get_absolute_timeout(timeout); 1958 if (anv_all_fences_syncobj(fenceCount, pFences)) { 1959 return anv_wait_for_syncobj_fences(device, fenceCount, pFences, 1960 waitAll, abs_timeout); 1961 } else if (anv_all_fences_bo(fenceCount, pFences)) { 1962 return anv_wait_for_bo_fences(device, fenceCount, pFences, 1963 waitAll, abs_timeout); 1964 } else { 1965 return anv_wait_for_fences(device, fenceCount, pFences, 1966 waitAll, abs_timeout); 1967 } 1968} 1969 1970void anv_GetPhysicalDeviceExternalFenceProperties( 1971 VkPhysicalDevice physicalDevice, 1972 const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, 1973 VkExternalFenceProperties* pExternalFenceProperties) 1974{ 1975 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 1976 1977 switch (pExternalFenceInfo->handleType) { 1978 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: 1979 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: 1980 if (device->has_syncobj_wait) { 1981 pExternalFenceProperties->exportFromImportedHandleTypes = 1982 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT | 1983 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; 1984 pExternalFenceProperties->compatibleHandleTypes = 1985 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT | 1986 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; 1987 pExternalFenceProperties->externalFenceFeatures = 1988 VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT | 1989 VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT; 1990 return; 1991 } 1992 break; 1993 1994 default: 1995 break; 1996 } 1997 1998 pExternalFenceProperties->exportFromImportedHandleTypes = 0; 1999 pExternalFenceProperties->compatibleHandleTypes = 0; 2000 pExternalFenceProperties->externalFenceFeatures = 0; 2001} 2002 2003VkResult anv_ImportFenceFdKHR( 2004 VkDevice _device, 2005 const VkImportFenceFdInfoKHR* pImportFenceFdInfo) 2006{ 2007 ANV_FROM_HANDLE(anv_device, device, _device); 2008 ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence); 2009 int fd = pImportFenceFdInfo->fd; 2010 2011 assert(pImportFenceFdInfo->sType == 2012 VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR); 2013 2014 struct anv_fence_impl new_impl = { 2015 .type = ANV_FENCE_TYPE_NONE, 2016 }; 2017 2018 switch (pImportFenceFdInfo->handleType) { 2019 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: 2020 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ; 2021 2022 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd); 2023 if (!new_impl.syncobj) 2024 return vk_error(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE); 2025 2026 break; 2027 2028 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: { 2029 /* Sync files are a bit tricky. Because we want to continue using the 2030 * syncobj implementation of WaitForFences, we don't use the sync file 2031 * directly but instead import it into a syncobj. 2032 */ 2033 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ; 2034 2035 /* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the 2036 * special value -1 for fd is treated like a valid sync file descriptor 2037 * referring to an object that has already signaled. The import 2038 * operation will succeed and the VkFence will have a temporarily 2039 * imported payload as if a valid file descriptor had been provided." 2040 */ 2041 uint32_t create_flags = 0; 2042 if (fd == -1) 2043 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 2044 2045 new_impl.syncobj = anv_gem_syncobj_create(device, create_flags); 2046 if (!new_impl.syncobj) 2047 return vk_error(fence, VK_ERROR_OUT_OF_HOST_MEMORY); 2048 2049 if (fd != -1 && 2050 anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) { 2051 anv_gem_syncobj_destroy(device, new_impl.syncobj); 2052 return vk_errorf(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE, 2053 "syncobj sync file import failed: %m"); 2054 } 2055 break; 2056 } 2057 2058 default: 2059 return vk_error(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE); 2060 } 2061 2062 /* From the Vulkan 1.0.53 spec: 2063 * 2064 * "Importing a fence payload from a file descriptor transfers 2065 * ownership of the file descriptor from the application to the 2066 * Vulkan implementation. The application must not perform any 2067 * operations on the file descriptor after a successful import." 2068 * 2069 * If the import fails, we leave the file descriptor open. 2070 */ 2071 if (fd != -1) 2072 close(fd); 2073 2074 if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) { 2075 anv_fence_impl_cleanup(device, &fence->temporary); 2076 fence->temporary = new_impl; 2077 } else { 2078 anv_fence_impl_cleanup(device, &fence->permanent); 2079 fence->permanent = new_impl; 2080 } 2081 2082 return VK_SUCCESS; 2083} 2084 2085/* The sideband payload of the DRM syncobj was incremented when the 2086 * application called vkQueueSubmit(). Here we wait for a fence with the same 2087 * value to materialize so that we can exporting (typically as a SyncFD). 2088 */ 2089static VkResult 2090wait_syncobj_materialize(struct anv_device *device, 2091 uint32_t syncobj, 2092 int *fd) 2093{ 2094 if (!device->has_thread_submit) 2095 return VK_SUCCESS; 2096 2097 uint64_t binary_value = 0; 2098 /* We might need to wait until the fence materializes before we can 2099 * export to a sync FD when we use a thread for submission. 2100 */ 2101 if (anv_gem_syncobj_timeline_wait(device, &syncobj, &binary_value, 1, 2102 anv_get_absolute_timeout(5ull * NSEC_PER_SEC), 2103 true /* wait_all */, 2104 true /* wait_materialize */)) 2105 return anv_device_set_lost(device, "anv_gem_syncobj_timeline_wait failed: %m"); 2106 2107 return VK_SUCCESS; 2108} 2109 2110VkResult anv_GetFenceFdKHR( 2111 VkDevice _device, 2112 const VkFenceGetFdInfoKHR* pGetFdInfo, 2113 int* pFd) 2114{ 2115 ANV_FROM_HANDLE(anv_device, device, _device); 2116 ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence); 2117 2118 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR); 2119 2120 struct anv_fence_impl *impl = 2121 fence->temporary.type != ANV_FENCE_TYPE_NONE ? 2122 &fence->temporary : &fence->permanent; 2123 2124 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ); 2125 switch (pGetFdInfo->handleType) { 2126 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: { 2127 int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); 2128 if (fd < 0) 2129 return vk_error(fence, VK_ERROR_TOO_MANY_OBJECTS); 2130 2131 *pFd = fd; 2132 break; 2133 } 2134 2135 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: { 2136 VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd); 2137 if (result != VK_SUCCESS) 2138 return result; 2139 2140 int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj); 2141 if (fd < 0) 2142 return vk_error(fence, VK_ERROR_TOO_MANY_OBJECTS); 2143 2144 *pFd = fd; 2145 break; 2146 } 2147 2148 default: 2149 unreachable("Invalid fence export handle type"); 2150 } 2151 2152 /* From the Vulkan 1.0.53 spec: 2153 * 2154 * "Export operations have the same transference as the specified handle 2155 * type’s import operations. [...] If the fence was using a 2156 * temporarily imported payload, the fence’s prior permanent payload 2157 * will be restored. 2158 */ 2159 if (impl == &fence->temporary) 2160 anv_fence_impl_cleanup(device, impl); 2161 2162 return VK_SUCCESS; 2163} 2164 2165// Queue semaphore functions 2166 2167static VkSemaphoreTypeKHR 2168get_semaphore_type(const void *pNext, uint64_t *initial_value) 2169{ 2170 const VkSemaphoreTypeCreateInfoKHR *type_info = 2171 vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR); 2172 2173 if (!type_info) 2174 return VK_SEMAPHORE_TYPE_BINARY_KHR; 2175 2176 if (initial_value) 2177 *initial_value = type_info->initialValue; 2178 return type_info->semaphoreType; 2179} 2180 2181static VkResult 2182binary_semaphore_create(struct anv_device *device, 2183 struct anv_semaphore_impl *impl, 2184 bool exportable) 2185{ 2186 impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; 2187 impl->syncobj = anv_gem_syncobj_create(device, 0); 2188 if (!impl->syncobj) 2189 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2190 return VK_SUCCESS; 2191} 2192 2193static VkResult 2194timeline_semaphore_create(struct anv_device *device, 2195 struct anv_semaphore_impl *impl, 2196 uint64_t initial_value) 2197{ 2198 if (device->has_thread_submit) { 2199 impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE; 2200 impl->syncobj = anv_gem_syncobj_create(device, 0); 2201 if (!impl->syncobj) 2202 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2203 if (initial_value) { 2204 if (anv_gem_syncobj_timeline_signal(device, 2205 &impl->syncobj, 2206 &initial_value, 1)) { 2207 anv_gem_syncobj_destroy(device, impl->syncobj); 2208 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2209 } 2210 } 2211 } else { 2212 impl->type = ANV_SEMAPHORE_TYPE_TIMELINE; 2213 anv_timeline_init(device, &impl->timeline, initial_value); 2214 } 2215 2216 return VK_SUCCESS; 2217} 2218 2219VkResult anv_CreateSemaphore( 2220 VkDevice _device, 2221 const VkSemaphoreCreateInfo* pCreateInfo, 2222 const VkAllocationCallbacks* pAllocator, 2223 VkSemaphore* pSemaphore) 2224{ 2225 ANV_FROM_HANDLE(anv_device, device, _device); 2226 struct anv_semaphore *semaphore; 2227 2228 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); 2229 2230 uint64_t timeline_value = 0; 2231 VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value); 2232 2233 semaphore = vk_object_alloc(&device->vk, NULL, sizeof(*semaphore), 2234 VK_OBJECT_TYPE_SEMAPHORE); 2235 if (semaphore == NULL) 2236 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2237 2238 const VkExportSemaphoreCreateInfo *export = 2239 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO); 2240 VkExternalSemaphoreHandleTypeFlags handleTypes = 2241 export ? export->handleTypes : 0; 2242 VkResult result; 2243 2244 if (handleTypes == 0) { 2245 if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR) 2246 result = binary_semaphore_create(device, &semaphore->permanent, false); 2247 else 2248 result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value); 2249 if (result != VK_SUCCESS) { 2250 vk_object_free(&device->vk, pAllocator, semaphore); 2251 return result; 2252 } 2253 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) { 2254 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 2255 if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR) 2256 result = binary_semaphore_create(device, &semaphore->permanent, true); 2257 else 2258 result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value); 2259 if (result != VK_SUCCESS) { 2260 vk_object_free(&device->vk, pAllocator, semaphore); 2261 return result; 2262 } 2263 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) { 2264 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT); 2265 assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR); 2266 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; 2267 semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0); 2268 if (!semaphore->permanent.syncobj) { 2269 vk_object_free(&device->vk, pAllocator, semaphore); 2270 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2271 } 2272 } else { 2273 assert(!"Unknown handle type"); 2274 vk_object_free(&device->vk, pAllocator, semaphore); 2275 return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE); 2276 } 2277 2278 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE; 2279 2280 *pSemaphore = anv_semaphore_to_handle(semaphore); 2281 2282 return VK_SUCCESS; 2283} 2284 2285static void 2286anv_semaphore_impl_cleanup(struct anv_device *device, 2287 struct anv_semaphore_impl *impl) 2288{ 2289 switch (impl->type) { 2290 case ANV_SEMAPHORE_TYPE_NONE: 2291 case ANV_SEMAPHORE_TYPE_DUMMY: 2292 /* Dummy. Nothing to do */ 2293 break; 2294 2295 case ANV_SEMAPHORE_TYPE_WSI_BO: 2296 anv_device_release_bo(device, impl->bo); 2297 break; 2298 2299 case ANV_SEMAPHORE_TYPE_TIMELINE: 2300 anv_timeline_finish(device, &impl->timeline); 2301 break; 2302 2303 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: 2304 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 2305 anv_gem_syncobj_destroy(device, impl->syncobj); 2306 break; 2307 2308 default: 2309 unreachable("Invalid semaphore type"); 2310 } 2311 2312 impl->type = ANV_SEMAPHORE_TYPE_NONE; 2313} 2314 2315void 2316anv_semaphore_reset_temporary(struct anv_device *device, 2317 struct anv_semaphore *semaphore) 2318{ 2319 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE) 2320 return; 2321 2322 anv_semaphore_impl_cleanup(device, &semaphore->temporary); 2323} 2324 2325void anv_DestroySemaphore( 2326 VkDevice _device, 2327 VkSemaphore _semaphore, 2328 const VkAllocationCallbacks* pAllocator) 2329{ 2330 ANV_FROM_HANDLE(anv_device, device, _device); 2331 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 2332 2333 if (semaphore == NULL) 2334 return; 2335 2336 anv_semaphore_impl_cleanup(device, &semaphore->temporary); 2337 anv_semaphore_impl_cleanup(device, &semaphore->permanent); 2338 2339 vk_object_base_finish(&semaphore->base); 2340 vk_free(&device->vk.alloc, semaphore); 2341} 2342 2343void anv_GetPhysicalDeviceExternalSemaphoreProperties( 2344 VkPhysicalDevice physicalDevice, 2345 const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, 2346 VkExternalSemaphoreProperties* pExternalSemaphoreProperties) 2347{ 2348 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 2349 2350 VkSemaphoreTypeKHR sem_type = 2351 get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL); 2352 2353 switch (pExternalSemaphoreInfo->handleType) { 2354 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: 2355 /* Timeline semaphores are not exportable, unless we have threaded 2356 * submission. 2357 */ 2358 if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && !device->has_thread_submit) 2359 break; 2360 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 2361 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 2362 pExternalSemaphoreProperties->compatibleHandleTypes = 2363 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 2364 pExternalSemaphoreProperties->externalSemaphoreFeatures = 2365 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | 2366 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; 2367 return; 2368 2369 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: 2370 if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR) 2371 break; 2372 if (!device->has_exec_fence) 2373 break; 2374 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 2375 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; 2376 pExternalSemaphoreProperties->compatibleHandleTypes = 2377 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; 2378 pExternalSemaphoreProperties->externalSemaphoreFeatures = 2379 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | 2380 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; 2381 return; 2382 2383 default: 2384 break; 2385 } 2386 2387 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; 2388 pExternalSemaphoreProperties->compatibleHandleTypes = 0; 2389 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; 2390} 2391 2392VkResult anv_ImportSemaphoreFdKHR( 2393 VkDevice _device, 2394 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo) 2395{ 2396 ANV_FROM_HANDLE(anv_device, device, _device); 2397 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore); 2398 int fd = pImportSemaphoreFdInfo->fd; 2399 2400 struct anv_semaphore_impl new_impl = { 2401 .type = ANV_SEMAPHORE_TYPE_NONE, 2402 }; 2403 2404 switch (pImportSemaphoreFdInfo->handleType) { 2405 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: 2406 /* When importing non temporarily, reuse the semaphore's existing 2407 * type. The Linux/DRM implementation allows to interchangeably use 2408 * binary & timeline semaphores and we have no way to differenciate 2409 * them. 2410 */ 2411 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) 2412 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; 2413 else 2414 new_impl.type = semaphore->permanent.type; 2415 2416 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd); 2417 if (!new_impl.syncobj) 2418 return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 2419 2420 /* From the Vulkan spec: 2421 * 2422 * "Importing semaphore state from a file descriptor transfers 2423 * ownership of the file descriptor from the application to the 2424 * Vulkan implementation. The application must not perform any 2425 * operations on the file descriptor after a successful import." 2426 * 2427 * If the import fails, we leave the file descriptor open. 2428 */ 2429 close(fd); 2430 break; 2431 2432 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: { 2433 uint32_t create_flags = 0; 2434 2435 if (fd == -1) 2436 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 2437 2438 new_impl = (struct anv_semaphore_impl) { 2439 .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ, 2440 .syncobj = anv_gem_syncobj_create(device, create_flags), 2441 }; 2442 2443 if (!new_impl.syncobj) 2444 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2445 2446 if (fd != -1) { 2447 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) { 2448 anv_gem_syncobj_destroy(device, new_impl.syncobj); 2449 return vk_errorf(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE, 2450 "syncobj sync file import failed: %m"); 2451 } 2452 /* Ownership of the FD is transfered to Anv. Since we don't need it 2453 * anymore because the associated fence has been put into a syncobj, 2454 * we must close the FD. 2455 */ 2456 close(fd); 2457 } 2458 break; 2459 } 2460 2461 default: 2462 return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 2463 } 2464 2465 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) { 2466 anv_semaphore_impl_cleanup(device, &semaphore->temporary); 2467 semaphore->temporary = new_impl; 2468 } else { 2469 anv_semaphore_impl_cleanup(device, &semaphore->permanent); 2470 semaphore->permanent = new_impl; 2471 } 2472 2473 return VK_SUCCESS; 2474} 2475 2476VkResult anv_GetSemaphoreFdKHR( 2477 VkDevice _device, 2478 const VkSemaphoreGetFdInfoKHR* pGetFdInfo, 2479 int* pFd) 2480{ 2481 ANV_FROM_HANDLE(anv_device, device, _device); 2482 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore); 2483 int fd; 2484 2485 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR); 2486 2487 struct anv_semaphore_impl *impl = 2488 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 2489 &semaphore->temporary : &semaphore->permanent; 2490 2491 switch (impl->type) { 2492 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: 2493 if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) { 2494 VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd); 2495 if (result != VK_SUCCESS) 2496 return result; 2497 2498 fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj); 2499 } else { 2500 assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 2501 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); 2502 } 2503 if (fd < 0) 2504 return vk_error(device, VK_ERROR_TOO_MANY_OBJECTS); 2505 *pFd = fd; 2506 break; 2507 2508 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 2509 assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 2510 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); 2511 if (fd < 0) 2512 return vk_error(device, VK_ERROR_TOO_MANY_OBJECTS); 2513 *pFd = fd; 2514 break; 2515 2516 default: 2517 return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 2518 } 2519 2520 /* From the Vulkan 1.0.53 spec: 2521 * 2522 * "Export operations have the same transference as the specified handle 2523 * type’s import operations. [...] If the semaphore was using a 2524 * temporarily imported payload, the semaphore’s prior permanent payload 2525 * will be restored. 2526 */ 2527 if (impl == &semaphore->temporary) 2528 anv_semaphore_impl_cleanup(device, impl); 2529 2530 return VK_SUCCESS; 2531} 2532 2533VkResult anv_GetSemaphoreCounterValue( 2534 VkDevice _device, 2535 VkSemaphore _semaphore, 2536 uint64_t* pValue) 2537{ 2538 ANV_FROM_HANDLE(anv_device, device, _device); 2539 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 2540 2541 struct anv_semaphore_impl *impl = 2542 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 2543 &semaphore->temporary : &semaphore->permanent; 2544 2545 switch (impl->type) { 2546 case ANV_SEMAPHORE_TYPE_TIMELINE: { 2547 pthread_mutex_lock(&device->mutex); 2548 anv_timeline_gc_locked(device, &impl->timeline); 2549 *pValue = impl->timeline.highest_past; 2550 pthread_mutex_unlock(&device->mutex); 2551 return VK_SUCCESS; 2552 } 2553 2554 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: { 2555 int ret = anv_gem_syncobj_timeline_query(device, &impl->syncobj, pValue, 1); 2556 2557 if (ret != 0) 2558 return anv_device_set_lost(device, "unable to query timeline syncobj"); 2559 2560 return VK_SUCCESS; 2561 } 2562 2563 default: 2564 unreachable("Invalid semaphore type"); 2565 } 2566} 2567 2568static VkResult 2569anv_timeline_wait_locked(struct anv_device *device, 2570 struct anv_timeline *timeline, 2571 uint64_t serial, uint64_t abs_timeout_ns) 2572{ 2573 /* Wait on the queue_submit condition variable until the timeline has a 2574 * time point pending that's at least as high as serial. 2575 */ 2576 while (timeline->highest_pending < serial) { 2577 struct timespec abstime = { 2578 .tv_sec = abs_timeout_ns / NSEC_PER_SEC, 2579 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC, 2580 }; 2581 2582 UNUSED int ret = pthread_cond_timedwait(&device->queue_submit, 2583 &device->mutex, &abstime); 2584 assert(ret != EINVAL); 2585 if (anv_gettime_ns() >= abs_timeout_ns && 2586 timeline->highest_pending < serial) 2587 return VK_TIMEOUT; 2588 } 2589 2590 while (1) { 2591 VkResult result = anv_timeline_gc_locked(device, timeline); 2592 if (result != VK_SUCCESS) 2593 return result; 2594 2595 if (timeline->highest_past >= serial) 2596 return VK_SUCCESS; 2597 2598 /* If we got here, our earliest time point has a busy BO */ 2599 struct anv_timeline_point *point = 2600 list_first_entry(&timeline->points, 2601 struct anv_timeline_point, link); 2602 2603 /* Drop the lock while we wait. */ 2604 point->waiting++; 2605 pthread_mutex_unlock(&device->mutex); 2606 2607 result = anv_device_wait(device, point->bo, 2608 anv_get_relative_timeout(abs_timeout_ns)); 2609 2610 /* Pick the mutex back up */ 2611 pthread_mutex_lock(&device->mutex); 2612 point->waiting--; 2613 2614 /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */ 2615 if (result != VK_SUCCESS) 2616 return result; 2617 } 2618} 2619 2620static VkResult 2621anv_timelines_wait(struct anv_device *device, 2622 struct anv_timeline **timelines, 2623 const uint64_t *serials, 2624 uint32_t n_timelines, 2625 bool wait_all, 2626 uint64_t abs_timeout_ns) 2627{ 2628 if (!wait_all && n_timelines > 1) { 2629 pthread_mutex_lock(&device->mutex); 2630 2631 while (1) { 2632 VkResult result; 2633 for (uint32_t i = 0; i < n_timelines; i++) { 2634 result = 2635 anv_timeline_wait_locked(device, timelines[i], serials[i], 0); 2636 if (result != VK_TIMEOUT) 2637 break; 2638 } 2639 2640 if (result != VK_TIMEOUT || 2641 anv_gettime_ns() >= abs_timeout_ns) { 2642 pthread_mutex_unlock(&device->mutex); 2643 return result; 2644 } 2645 2646 /* If none of them are ready do a short wait so we don't completely 2647 * spin while holding the lock. The 10us is completely arbitrary. 2648 */ 2649 uint64_t abs_short_wait_ns = 2650 anv_get_absolute_timeout( 2651 MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000)); 2652 struct timespec abstime = { 2653 .tv_sec = abs_short_wait_ns / NSEC_PER_SEC, 2654 .tv_nsec = abs_short_wait_ns % NSEC_PER_SEC, 2655 }; 2656 ASSERTED int ret; 2657 ret = pthread_cond_timedwait(&device->queue_submit, 2658 &device->mutex, &abstime); 2659 assert(ret != EINVAL); 2660 } 2661 } else { 2662 VkResult result = VK_SUCCESS; 2663 pthread_mutex_lock(&device->mutex); 2664 for (uint32_t i = 0; i < n_timelines; i++) { 2665 result = 2666 anv_timeline_wait_locked(device, timelines[i], 2667 serials[i], abs_timeout_ns); 2668 if (result != VK_SUCCESS) 2669 break; 2670 } 2671 pthread_mutex_unlock(&device->mutex); 2672 return result; 2673 } 2674} 2675 2676VkResult anv_WaitSemaphores( 2677 VkDevice _device, 2678 const VkSemaphoreWaitInfoKHR* pWaitInfo, 2679 uint64_t timeout) 2680{ 2681 ANV_FROM_HANDLE(anv_device, device, _device); 2682 uint32_t *handles; 2683 struct anv_timeline **timelines; 2684 2685 VK_MULTIALLOC(ma); 2686 2687 VK_MULTIALLOC_DECL(&ma, uint64_t, values, pWaitInfo->semaphoreCount); 2688 if (device->has_thread_submit) { 2689 vk_multialloc_add(&ma, &handles, uint32_t, pWaitInfo->semaphoreCount); 2690 } else { 2691 vk_multialloc_add(&ma, &timelines, struct anv_timeline *, 2692 pWaitInfo->semaphoreCount); 2693 } 2694 2695 if (!vk_multialloc_alloc(&ma, &device->vk.alloc, 2696 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)) 2697 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 2698 2699 uint32_t handle_count = 0; 2700 for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) { 2701 ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]); 2702 struct anv_semaphore_impl *impl = 2703 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 2704 &semaphore->temporary : &semaphore->permanent; 2705 2706 if (pWaitInfo->pValues[i] == 0) 2707 continue; 2708 2709 if (device->has_thread_submit) { 2710 assert(impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE); 2711 handles[handle_count] = impl->syncobj; 2712 } else { 2713 assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE); 2714 timelines[handle_count] = &impl->timeline; 2715 } 2716 values[handle_count] = pWaitInfo->pValues[i]; 2717 handle_count++; 2718 } 2719 2720 VkResult result = VK_SUCCESS; 2721 if (handle_count > 0) { 2722 if (device->has_thread_submit) { 2723 int ret = 2724 anv_gem_syncobj_timeline_wait(device, 2725 handles, values, handle_count, 2726 anv_get_absolute_timeout(timeout), 2727 !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR), 2728 false); 2729 if (ret != 0) 2730 result = errno == ETIME ? VK_TIMEOUT : 2731 anv_device_set_lost(device, "unable to wait on timeline syncobj"); 2732 } else { 2733 result = 2734 anv_timelines_wait(device, timelines, values, handle_count, 2735 !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR), 2736 anv_get_absolute_timeout(timeout)); 2737 } 2738 } 2739 2740 vk_free(&device->vk.alloc, values); 2741 2742 return result; 2743} 2744 2745VkResult anv_SignalSemaphore( 2746 VkDevice _device, 2747 const VkSemaphoreSignalInfoKHR* pSignalInfo) 2748{ 2749 ANV_FROM_HANDLE(anv_device, device, _device); 2750 ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore); 2751 2752 struct anv_semaphore_impl *impl = 2753 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 2754 &semaphore->temporary : &semaphore->permanent; 2755 2756 switch (impl->type) { 2757 case ANV_SEMAPHORE_TYPE_TIMELINE: { 2758 pthread_mutex_lock(&device->mutex); 2759 2760 VkResult result = anv_timeline_gc_locked(device, &impl->timeline); 2761 2762 assert(pSignalInfo->value > impl->timeline.highest_pending); 2763 2764 impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value; 2765 2766 if (result == VK_SUCCESS) 2767 result = anv_device_submit_deferred_locked(device); 2768 2769 pthread_cond_broadcast(&device->queue_submit); 2770 pthread_mutex_unlock(&device->mutex); 2771 return result; 2772 } 2773 2774 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: { 2775 /* Timeline semaphores are created with a value of 0, so signaling on 0 2776 * is a waste of time. 2777 */ 2778 if (pSignalInfo->value == 0) 2779 return VK_SUCCESS; 2780 2781 int ret = anv_gem_syncobj_timeline_signal(device, &impl->syncobj, 2782 &pSignalInfo->value, 1); 2783 2784 return ret == 0 ? VK_SUCCESS : 2785 anv_device_set_lost(device, "unable to signal timeline syncobj"); 2786 } 2787 2788 default: 2789 unreachable("Invalid semaphore type"); 2790 } 2791} 2792