101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2015 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg/** 2501e04c3fSmrg * This file implements VkQueue, VkFence, and VkSemaphore 2601e04c3fSmrg */ 2701e04c3fSmrg 287ec681f3Smrg#include <errno.h> 2901e04c3fSmrg#include <fcntl.h> 3001e04c3fSmrg#include <unistd.h> 3101e04c3fSmrg 327ec681f3Smrg#include "util/os_file.h" 337ec681f3Smrg 3401e04c3fSmrg#include "anv_private.h" 357ec681f3Smrg#include "anv_measure.h" 3601e04c3fSmrg#include "vk_util.h" 3701e04c3fSmrg 387ec681f3Smrg#include "genxml/gen7_pack.h" 397ec681f3Smrg 407ec681f3Smrguint64_t anv_gettime_ns(void) 417ec681f3Smrg{ 427ec681f3Smrg struct timespec current; 437ec681f3Smrg clock_gettime(CLOCK_MONOTONIC, ¤t); 447ec681f3Smrg return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec; 457ec681f3Smrg} 467ec681f3Smrg 477ec681f3Smrguint64_t anv_get_absolute_timeout(uint64_t timeout) 487ec681f3Smrg{ 497ec681f3Smrg if (timeout == 0) 507ec681f3Smrg return 0; 517ec681f3Smrg uint64_t current_time = anv_gettime_ns(); 527ec681f3Smrg uint64_t max_timeout = (uint64_t) INT64_MAX - current_time; 537ec681f3Smrg 547ec681f3Smrg timeout = MIN2(max_timeout, timeout); 557ec681f3Smrg 567ec681f3Smrg return (current_time + timeout); 577ec681f3Smrg} 587ec681f3Smrg 597ec681f3Smrgstatic int64_t anv_get_relative_timeout(uint64_t abs_timeout) 607ec681f3Smrg{ 617ec681f3Smrg uint64_t now = anv_gettime_ns(); 627ec681f3Smrg 637ec681f3Smrg /* We don't want negative timeouts. 647ec681f3Smrg * 657ec681f3Smrg * DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is 667ec681f3Smrg * supposed to block indefinitely timeouts < 0. Unfortunately, 677ec681f3Smrg * this was broken for a couple of kernel releases. Since there's 687ec681f3Smrg * no way to know whether or not the kernel we're using is one of 697ec681f3Smrg * the broken ones, the best we can do is to clamp the timeout to 707ec681f3Smrg * INT64_MAX. This limits the maximum timeout from 584 years to 717ec681f3Smrg * 292 years - likely not a big deal. 727ec681f3Smrg */ 737ec681f3Smrg if (abs_timeout < now) 747ec681f3Smrg return 0; 757ec681f3Smrg 767ec681f3Smrg uint64_t rel_timeout = abs_timeout - now; 777ec681f3Smrg if (rel_timeout > (uint64_t) INT64_MAX) 787ec681f3Smrg rel_timeout = INT64_MAX; 797ec681f3Smrg 807ec681f3Smrg return rel_timeout; 817ec681f3Smrg} 827ec681f3Smrg 837ec681f3Smrgstatic void anv_semaphore_impl_cleanup(struct anv_device *device, 847ec681f3Smrg struct anv_semaphore_impl *impl); 857ec681f3Smrg 867ec681f3Smrgstatic void 877ec681f3Smrganv_queue_submit_free(struct anv_device *device, 887ec681f3Smrg struct anv_queue_submit *submit) 897ec681f3Smrg{ 907ec681f3Smrg const VkAllocationCallbacks *alloc = submit->alloc; 917ec681f3Smrg 927ec681f3Smrg for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++) 937ec681f3Smrg anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]); 947ec681f3Smrg /* Execbuf does not consume the in_fence. It's our job to close it. */ 957ec681f3Smrg if (submit->in_fence != -1) { 967ec681f3Smrg assert(!device->has_thread_submit); 977ec681f3Smrg close(submit->in_fence); 987ec681f3Smrg } 997ec681f3Smrg if (submit->out_fence != -1) { 1007ec681f3Smrg assert(!device->has_thread_submit); 1017ec681f3Smrg close(submit->out_fence); 1027ec681f3Smrg } 1037ec681f3Smrg vk_free(alloc, submit->fences); 1047ec681f3Smrg vk_free(alloc, submit->fence_values); 1057ec681f3Smrg vk_free(alloc, submit->temporary_semaphores); 1067ec681f3Smrg vk_free(alloc, submit->wait_timelines); 1077ec681f3Smrg vk_free(alloc, submit->wait_timeline_values); 1087ec681f3Smrg vk_free(alloc, submit->signal_timelines); 1097ec681f3Smrg vk_free(alloc, submit->signal_timeline_values); 1107ec681f3Smrg vk_free(alloc, submit->fence_bos); 1117ec681f3Smrg vk_free(alloc, submit->cmd_buffers); 1127ec681f3Smrg vk_free(alloc, submit); 1137ec681f3Smrg} 1147ec681f3Smrg 1157ec681f3Smrgstatic bool 1167ec681f3Smrganv_queue_submit_ready_locked(struct anv_queue_submit *submit) 1177ec681f3Smrg{ 1187ec681f3Smrg for (uint32_t i = 0; i < submit->wait_timeline_count; i++) { 1197ec681f3Smrg if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending) 1207ec681f3Smrg return false; 1217ec681f3Smrg } 1227ec681f3Smrg 1237ec681f3Smrg return true; 1247ec681f3Smrg} 1257ec681f3Smrg 1267ec681f3Smrgstatic VkResult 1277ec681f3Smrganv_timeline_init(struct anv_device *device, 1287ec681f3Smrg struct anv_timeline *timeline, 1297ec681f3Smrg uint64_t initial_value) 1307ec681f3Smrg{ 1317ec681f3Smrg timeline->highest_past = 1327ec681f3Smrg timeline->highest_pending = initial_value; 1337ec681f3Smrg list_inithead(&timeline->points); 1347ec681f3Smrg list_inithead(&timeline->free_points); 1357ec681f3Smrg 1367ec681f3Smrg return VK_SUCCESS; 1377ec681f3Smrg} 1387ec681f3Smrg 1397ec681f3Smrgstatic void 1407ec681f3Smrganv_timeline_finish(struct anv_device *device, 1417ec681f3Smrg struct anv_timeline *timeline) 1427ec681f3Smrg{ 1437ec681f3Smrg list_for_each_entry_safe(struct anv_timeline_point, point, 1447ec681f3Smrg &timeline->free_points, link) { 1457ec681f3Smrg list_del(&point->link); 1467ec681f3Smrg anv_device_release_bo(device, point->bo); 1477ec681f3Smrg vk_free(&device->vk.alloc, point); 1487ec681f3Smrg } 1497ec681f3Smrg list_for_each_entry_safe(struct anv_timeline_point, point, 1507ec681f3Smrg &timeline->points, link) { 1517ec681f3Smrg list_del(&point->link); 1527ec681f3Smrg anv_device_release_bo(device, point->bo); 1537ec681f3Smrg vk_free(&device->vk.alloc, point); 1547ec681f3Smrg } 1557ec681f3Smrg} 1567ec681f3Smrg 1577ec681f3Smrgstatic VkResult 1587ec681f3Smrganv_timeline_add_point_locked(struct anv_device *device, 1597ec681f3Smrg struct anv_timeline *timeline, 1607ec681f3Smrg uint64_t value, 1617ec681f3Smrg struct anv_timeline_point **point) 1627ec681f3Smrg{ 1637ec681f3Smrg VkResult result = VK_SUCCESS; 1647ec681f3Smrg 1657ec681f3Smrg if (list_is_empty(&timeline->free_points)) { 1667ec681f3Smrg *point = 1677ec681f3Smrg vk_zalloc(&device->vk.alloc, sizeof(**point), 1687ec681f3Smrg 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 1697ec681f3Smrg if (!(*point)) 1707ec681f3Smrg result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1717ec681f3Smrg if (result == VK_SUCCESS) { 1727ec681f3Smrg result = anv_device_alloc_bo(device, "timeline-semaphore", 4096, 1737ec681f3Smrg ANV_BO_ALLOC_EXTERNAL | 1747ec681f3Smrg ANV_BO_ALLOC_IMPLICIT_SYNC, 1757ec681f3Smrg 0 /* explicit_address */, 1767ec681f3Smrg &(*point)->bo); 1777ec681f3Smrg if (result != VK_SUCCESS) 1787ec681f3Smrg vk_free(&device->vk.alloc, *point); 1797ec681f3Smrg } 1807ec681f3Smrg } else { 1817ec681f3Smrg *point = list_first_entry(&timeline->free_points, 1827ec681f3Smrg struct anv_timeline_point, link); 1837ec681f3Smrg list_del(&(*point)->link); 1847ec681f3Smrg } 1857ec681f3Smrg 1867ec681f3Smrg if (result == VK_SUCCESS) { 1877ec681f3Smrg (*point)->serial = value; 1887ec681f3Smrg list_addtail(&(*point)->link, &timeline->points); 1897ec681f3Smrg } 1907ec681f3Smrg 1917ec681f3Smrg return result; 1927ec681f3Smrg} 1937ec681f3Smrg 1947ec681f3Smrgstatic VkResult 1957ec681f3Smrganv_timeline_gc_locked(struct anv_device *device, 1967ec681f3Smrg struct anv_timeline *timeline) 1977ec681f3Smrg{ 1987ec681f3Smrg list_for_each_entry_safe(struct anv_timeline_point, point, 1997ec681f3Smrg &timeline->points, link) { 2007ec681f3Smrg /* timeline->higest_pending is only incremented once submission has 2017ec681f3Smrg * happened. If this point has a greater serial, it means the point 2027ec681f3Smrg * hasn't been submitted yet. 2037ec681f3Smrg */ 2047ec681f3Smrg if (point->serial > timeline->highest_pending) 2057ec681f3Smrg return VK_SUCCESS; 2067ec681f3Smrg 2077ec681f3Smrg /* If someone is waiting on this time point, consider it busy and don't 2087ec681f3Smrg * try to recycle it. There's a slim possibility that it's no longer 2097ec681f3Smrg * busy by the time we look at it but we would be recycling it out from 2107ec681f3Smrg * under a waiter and that can lead to weird races. 2117ec681f3Smrg * 2127ec681f3Smrg * We walk the list in-order so if this time point is still busy so is 2137ec681f3Smrg * every following time point 2147ec681f3Smrg */ 2157ec681f3Smrg assert(point->waiting >= 0); 2167ec681f3Smrg if (point->waiting) 2177ec681f3Smrg return VK_SUCCESS; 2187ec681f3Smrg 2197ec681f3Smrg /* Garbage collect any signaled point. */ 2207ec681f3Smrg VkResult result = anv_device_bo_busy(device, point->bo); 2217ec681f3Smrg if (result == VK_NOT_READY) { 2227ec681f3Smrg /* We walk the list in-order so if this time point is still busy so 2237ec681f3Smrg * is every following time point 2247ec681f3Smrg */ 2257ec681f3Smrg return VK_SUCCESS; 2267ec681f3Smrg } else if (result != VK_SUCCESS) { 2277ec681f3Smrg return result; 2287ec681f3Smrg } 2297ec681f3Smrg 2307ec681f3Smrg assert(timeline->highest_past < point->serial); 2317ec681f3Smrg timeline->highest_past = point->serial; 2327ec681f3Smrg 2337ec681f3Smrg list_del(&point->link); 2347ec681f3Smrg list_add(&point->link, &timeline->free_points); 2357ec681f3Smrg } 2367ec681f3Smrg 2377ec681f3Smrg return VK_SUCCESS; 2387ec681f3Smrg} 2397ec681f3Smrg 2407ec681f3Smrgstatic VkResult anv_queue_submit_add_fence_bo(struct anv_queue *queue, 2417ec681f3Smrg struct anv_queue_submit *submit, 2427ec681f3Smrg struct anv_bo *bo, 2437ec681f3Smrg bool signal); 2447ec681f3Smrg 2457ec681f3Smrgstatic VkResult 2467ec681f3Smrganv_queue_submit_timeline_locked(struct anv_queue *queue, 2477ec681f3Smrg struct anv_queue_submit *submit) 2487ec681f3Smrg{ 2497ec681f3Smrg VkResult result; 2507ec681f3Smrg 2517ec681f3Smrg for (uint32_t i = 0; i < submit->wait_timeline_count; i++) { 2527ec681f3Smrg struct anv_timeline *timeline = submit->wait_timelines[i]; 2537ec681f3Smrg uint64_t wait_value = submit->wait_timeline_values[i]; 2547ec681f3Smrg 2557ec681f3Smrg if (timeline->highest_past >= wait_value) 2567ec681f3Smrg continue; 2577ec681f3Smrg 2587ec681f3Smrg list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) { 2597ec681f3Smrg if (point->serial < wait_value) 2607ec681f3Smrg continue; 2617ec681f3Smrg result = anv_queue_submit_add_fence_bo(queue, submit, point->bo, false); 2627ec681f3Smrg if (result != VK_SUCCESS) 2637ec681f3Smrg return result; 2647ec681f3Smrg break; 2657ec681f3Smrg } 2667ec681f3Smrg } 2677ec681f3Smrg for (uint32_t i = 0; i < submit->signal_timeline_count; i++) { 2687ec681f3Smrg struct anv_timeline *timeline = submit->signal_timelines[i]; 2697ec681f3Smrg uint64_t signal_value = submit->signal_timeline_values[i]; 2707ec681f3Smrg struct anv_timeline_point *point; 2717ec681f3Smrg 2727ec681f3Smrg result = anv_timeline_add_point_locked(queue->device, timeline, 2737ec681f3Smrg signal_value, &point); 2747ec681f3Smrg if (result != VK_SUCCESS) 2757ec681f3Smrg return result; 2767ec681f3Smrg 2777ec681f3Smrg result = anv_queue_submit_add_fence_bo(queue, submit, point->bo, true); 2787ec681f3Smrg if (result != VK_SUCCESS) 2797ec681f3Smrg return result; 2807ec681f3Smrg } 2817ec681f3Smrg 2827ec681f3Smrg result = anv_queue_execbuf_locked(queue, submit); 2837ec681f3Smrg 2847ec681f3Smrg if (result == VK_SUCCESS) { 2857ec681f3Smrg /* Update the pending values in the timeline objects. */ 2867ec681f3Smrg for (uint32_t i = 0; i < submit->signal_timeline_count; i++) { 2877ec681f3Smrg struct anv_timeline *timeline = submit->signal_timelines[i]; 2887ec681f3Smrg uint64_t signal_value = submit->signal_timeline_values[i]; 2897ec681f3Smrg 2907ec681f3Smrg assert(signal_value > timeline->highest_pending); 2917ec681f3Smrg timeline->highest_pending = signal_value; 2927ec681f3Smrg } 2937ec681f3Smrg } else { 2947ec681f3Smrg /* Unblock any waiter by signaling the points, the application will get 2957ec681f3Smrg * a device lost error code. 2967ec681f3Smrg */ 2977ec681f3Smrg for (uint32_t i = 0; i < submit->signal_timeline_count; i++) { 2987ec681f3Smrg struct anv_timeline *timeline = submit->signal_timelines[i]; 2997ec681f3Smrg uint64_t signal_value = submit->signal_timeline_values[i]; 3007ec681f3Smrg 3017ec681f3Smrg assert(signal_value > timeline->highest_pending); 3027ec681f3Smrg timeline->highest_past = timeline->highest_pending = signal_value; 3037ec681f3Smrg } 3047ec681f3Smrg } 3057ec681f3Smrg 3067ec681f3Smrg return result; 3077ec681f3Smrg} 3087ec681f3Smrg 3097ec681f3Smrgstatic VkResult 3107ec681f3Smrganv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance) 3117ec681f3Smrg{ 3127ec681f3Smrg VkResult result = VK_SUCCESS; 3137ec681f3Smrg 3147ec681f3Smrg /* Go through all the queued submissions and submit then until we find one 3157ec681f3Smrg * that's waiting on a point that hasn't materialized yet. 3167ec681f3Smrg */ 3177ec681f3Smrg list_for_each_entry_safe(struct anv_queue_submit, submit, 3187ec681f3Smrg &queue->queued_submits, link) { 3197ec681f3Smrg if (!anv_queue_submit_ready_locked(submit)) 3207ec681f3Smrg break; 3217ec681f3Smrg 3227ec681f3Smrg (*advance)++; 3237ec681f3Smrg list_del(&submit->link); 3247ec681f3Smrg 3257ec681f3Smrg result = anv_queue_submit_timeline_locked(queue, submit); 3267ec681f3Smrg 3277ec681f3Smrg anv_queue_submit_free(queue->device, submit); 3287ec681f3Smrg 3297ec681f3Smrg if (result != VK_SUCCESS) 3307ec681f3Smrg break; 3317ec681f3Smrg } 3327ec681f3Smrg 3337ec681f3Smrg return result; 3347ec681f3Smrg} 3357ec681f3Smrg 3367ec681f3Smrgstatic VkResult 3377ec681f3Smrganv_device_submit_deferred_locked(struct anv_device *device) 3387ec681f3Smrg{ 3397ec681f3Smrg VkResult result = VK_SUCCESS; 3407ec681f3Smrg 3417ec681f3Smrg uint32_t advance; 3427ec681f3Smrg do { 3437ec681f3Smrg advance = 0; 3447ec681f3Smrg for (uint32_t i = 0; i < device->queue_count; i++) { 3457ec681f3Smrg struct anv_queue *queue = &device->queues[i]; 3467ec681f3Smrg VkResult qres = anv_queue_submit_deferred_locked(queue, &advance); 3477ec681f3Smrg if (qres != VK_SUCCESS) 3487ec681f3Smrg result = qres; 3497ec681f3Smrg } 3507ec681f3Smrg } while (advance); 3517ec681f3Smrg 3527ec681f3Smrg return result; 3537ec681f3Smrg} 3547ec681f3Smrg 3557ec681f3Smrgstatic void 3567ec681f3Smrganv_queue_submit_signal_fences(struct anv_device *device, 3577ec681f3Smrg struct anv_queue_submit *submit) 3587ec681f3Smrg{ 3597ec681f3Smrg for (uint32_t i = 0; i < submit->fence_count; i++) { 3607ec681f3Smrg if (submit->fences[i].flags & I915_EXEC_FENCE_SIGNAL) { 3617ec681f3Smrg anv_gem_syncobj_timeline_signal(device, &submit->fences[i].handle, 3627ec681f3Smrg &submit->fence_values[i], 1); 3637ec681f3Smrg } 3647ec681f3Smrg } 3657ec681f3Smrg} 3667ec681f3Smrg 3677ec681f3Smrgstatic void * 3687ec681f3Smrganv_queue_task(void *_queue) 3697ec681f3Smrg{ 3707ec681f3Smrg struct anv_queue *queue = _queue; 3717ec681f3Smrg 3727ec681f3Smrg pthread_mutex_lock(&queue->mutex); 3737ec681f3Smrg 3747ec681f3Smrg while (!queue->quit) { 3757ec681f3Smrg while (!list_is_empty(&queue->queued_submits)) { 3767ec681f3Smrg struct anv_queue_submit *submit = 3777ec681f3Smrg list_first_entry(&queue->queued_submits, struct anv_queue_submit, link); 3787ec681f3Smrg list_del(&submit->link); 3797ec681f3Smrg 3807ec681f3Smrg pthread_mutex_unlock(&queue->mutex); 3817ec681f3Smrg 3827ec681f3Smrg VkResult result = VK_ERROR_DEVICE_LOST; 3837ec681f3Smrg 3847ec681f3Smrg /* Wait for timeline points to materialize before submitting. We need 3857ec681f3Smrg * to do this because we're using threads to do the submit to i915. 3867ec681f3Smrg * We could end up in a situation where the application submits to 2 3877ec681f3Smrg * queues with the first submit creating the dma-fence for the 3887ec681f3Smrg * second. But because the scheduling of the submission threads might 3897ec681f3Smrg * wakeup the second queue thread first, this would make that execbuf 3907ec681f3Smrg * fail because the dma-fence it depends on hasn't materialized yet. 3917ec681f3Smrg */ 3927ec681f3Smrg if (!queue->lost && submit->wait_timeline_count > 0) { 3937ec681f3Smrg int ret = queue->device->info.no_hw ? 0 : 3947ec681f3Smrg anv_gem_syncobj_timeline_wait( 3957ec681f3Smrg queue->device, submit->wait_timeline_syncobjs, 3967ec681f3Smrg submit->wait_timeline_values, submit->wait_timeline_count, 3977ec681f3Smrg anv_get_absolute_timeout(UINT64_MAX) /* wait forever */, 3987ec681f3Smrg true /* wait for all */, true /* wait for materialize */); 3997ec681f3Smrg if (ret) { 4007ec681f3Smrg result = anv_queue_set_lost(queue, "timeline timeout: %s", 4017ec681f3Smrg strerror(errno)); 4027ec681f3Smrg } 4037ec681f3Smrg } 4047ec681f3Smrg 4057ec681f3Smrg /* Now submit */ 4067ec681f3Smrg if (!queue->lost) { 4077ec681f3Smrg pthread_mutex_lock(&queue->device->mutex); 4087ec681f3Smrg result = anv_queue_execbuf_locked(queue, submit); 4097ec681f3Smrg pthread_mutex_unlock(&queue->device->mutex); 4107ec681f3Smrg } 4117ec681f3Smrg 4127ec681f3Smrg if (result != VK_SUCCESS) { 4137ec681f3Smrg /* vkQueueSubmit or some other entry point will report the 4147ec681f3Smrg * DEVICE_LOST error at some point, but until we have emptied our 4157ec681f3Smrg * list of execbufs we need to wake up all potential the waiters 4167ec681f3Smrg * until one of them spots the error. 4177ec681f3Smrg */ 4187ec681f3Smrg anv_queue_submit_signal_fences(queue->device, submit); 4197ec681f3Smrg } 4207ec681f3Smrg 4217ec681f3Smrg anv_queue_submit_free(queue->device, submit); 4227ec681f3Smrg 4237ec681f3Smrg pthread_mutex_lock(&queue->mutex); 4247ec681f3Smrg } 4257ec681f3Smrg 4267ec681f3Smrg if (!queue->quit) 4277ec681f3Smrg pthread_cond_wait(&queue->cond, &queue->mutex); 4287ec681f3Smrg } 4297ec681f3Smrg 4307ec681f3Smrg pthread_mutex_unlock(&queue->mutex); 4317ec681f3Smrg 4327ec681f3Smrg return NULL; 4337ec681f3Smrg} 4347ec681f3Smrg 4357ec681f3Smrgstatic VkResult 4367ec681f3Smrganv_queue_submit_post(struct anv_queue *queue, 4377ec681f3Smrg struct anv_queue_submit **_submit, 4387ec681f3Smrg bool flush_queue) 4397ec681f3Smrg{ 4407ec681f3Smrg struct anv_queue_submit *submit = *_submit; 4417ec681f3Smrg 4427ec681f3Smrg /* Wait before signal behavior means we might keep alive the 4437ec681f3Smrg * anv_queue_submit object a bit longer, so transfer the ownership to the 4447ec681f3Smrg * anv_queue. 4457ec681f3Smrg */ 4467ec681f3Smrg *_submit = NULL; 4477ec681f3Smrg if (queue->device->has_thread_submit) { 4487ec681f3Smrg pthread_mutex_lock(&queue->mutex); 4497ec681f3Smrg pthread_cond_broadcast(&queue->cond); 4507ec681f3Smrg list_addtail(&submit->link, &queue->queued_submits); 4517ec681f3Smrg pthread_mutex_unlock(&queue->mutex); 4527ec681f3Smrg return VK_SUCCESS; 4537ec681f3Smrg } else { 4547ec681f3Smrg pthread_mutex_lock(&queue->device->mutex); 4557ec681f3Smrg list_addtail(&submit->link, &queue->queued_submits); 4567ec681f3Smrg VkResult result = anv_device_submit_deferred_locked(queue->device); 4577ec681f3Smrg if (flush_queue) { 4587ec681f3Smrg while (result == VK_SUCCESS && !list_is_empty(&queue->queued_submits)) { 4597ec681f3Smrg int ret = pthread_cond_wait(&queue->device->queue_submit, 4607ec681f3Smrg &queue->device->mutex); 4617ec681f3Smrg if (ret != 0) { 4627ec681f3Smrg result = anv_device_set_lost(queue->device, "wait timeout"); 4637ec681f3Smrg break; 4647ec681f3Smrg } 4657ec681f3Smrg 4667ec681f3Smrg result = anv_device_submit_deferred_locked(queue->device); 4677ec681f3Smrg } 4687ec681f3Smrg } 4697ec681f3Smrg pthread_mutex_unlock(&queue->device->mutex); 4707ec681f3Smrg return result; 4717ec681f3Smrg } 4727ec681f3Smrg} 4737ec681f3Smrg 4747ec681f3SmrgVkResult 4757ec681f3Smrganv_queue_init(struct anv_device *device, struct anv_queue *queue, 4767ec681f3Smrg uint32_t exec_flags, 4777ec681f3Smrg const VkDeviceQueueCreateInfo *pCreateInfo, 4787ec681f3Smrg uint32_t index_in_family) 4797ec681f3Smrg{ 4807ec681f3Smrg struct anv_physical_device *pdevice = device->physical; 4817ec681f3Smrg VkResult result; 4827ec681f3Smrg 4837ec681f3Smrg result = vk_queue_init(&queue->vk, &device->vk, pCreateInfo, 4847ec681f3Smrg index_in_family); 4857ec681f3Smrg if (result != VK_SUCCESS) 4867ec681f3Smrg return result; 4877ec681f3Smrg 4887ec681f3Smrg queue->device = device; 4897ec681f3Smrg 4907ec681f3Smrg assert(queue->vk.queue_family_index < pdevice->queue.family_count); 4917ec681f3Smrg queue->family = &pdevice->queue.families[queue->vk.queue_family_index]; 4927ec681f3Smrg 4937ec681f3Smrg queue->exec_flags = exec_flags; 4947ec681f3Smrg queue->lost = false; 4957ec681f3Smrg queue->quit = false; 4967ec681f3Smrg 4977ec681f3Smrg list_inithead(&queue->queued_submits); 4987ec681f3Smrg 4997ec681f3Smrg /* We only need those additional thread/mutex when using a thread for 5007ec681f3Smrg * submission. 5017ec681f3Smrg */ 5027ec681f3Smrg if (device->has_thread_submit) { 5037ec681f3Smrg if (pthread_mutex_init(&queue->mutex, NULL) != 0) { 5047ec681f3Smrg result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED); 5057ec681f3Smrg goto fail_queue; 5067ec681f3Smrg } 5077ec681f3Smrg if (pthread_cond_init(&queue->cond, NULL) != 0) { 5087ec681f3Smrg result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED); 5097ec681f3Smrg goto fail_mutex; 5107ec681f3Smrg } 5117ec681f3Smrg if (pthread_create(&queue->thread, NULL, anv_queue_task, queue)) { 5127ec681f3Smrg result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED); 5137ec681f3Smrg goto fail_cond; 5147ec681f3Smrg } 5157ec681f3Smrg } 5167ec681f3Smrg 5177ec681f3Smrg return VK_SUCCESS; 5187ec681f3Smrg 5197ec681f3Smrg fail_cond: 5207ec681f3Smrg pthread_cond_destroy(&queue->cond); 5217ec681f3Smrg fail_mutex: 5227ec681f3Smrg pthread_mutex_destroy(&queue->mutex); 5237ec681f3Smrg fail_queue: 5247ec681f3Smrg vk_queue_finish(&queue->vk); 5257ec681f3Smrg 5267ec681f3Smrg return result; 5277ec681f3Smrg} 5287ec681f3Smrg 5297ec681f3Smrgvoid 5307ec681f3Smrganv_queue_finish(struct anv_queue *queue) 5317ec681f3Smrg{ 5327ec681f3Smrg if (queue->device->has_thread_submit) { 5337ec681f3Smrg pthread_mutex_lock(&queue->mutex); 5347ec681f3Smrg pthread_cond_broadcast(&queue->cond); 5357ec681f3Smrg queue->quit = true; 5367ec681f3Smrg pthread_mutex_unlock(&queue->mutex); 5377ec681f3Smrg 5387ec681f3Smrg void *ret; 5397ec681f3Smrg pthread_join(queue->thread, &ret); 5407ec681f3Smrg 5417ec681f3Smrg pthread_cond_destroy(&queue->cond); 5427ec681f3Smrg pthread_mutex_destroy(&queue->mutex); 5437ec681f3Smrg } 5447ec681f3Smrg 5457ec681f3Smrg vk_queue_finish(&queue->vk); 5467ec681f3Smrg} 5477ec681f3Smrg 5487ec681f3Smrgstatic VkResult 5497ec681f3Smrganv_queue_submit_add_fence_bo(struct anv_queue *queue, 5507ec681f3Smrg struct anv_queue_submit *submit, 5517ec681f3Smrg struct anv_bo *bo, 5527ec681f3Smrg bool signal) 5537ec681f3Smrg{ 5547ec681f3Smrg if (submit->fence_bo_count >= submit->fence_bo_array_length) { 5557ec681f3Smrg uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64); 5567ec681f3Smrg uintptr_t *new_fence_bos = 5577ec681f3Smrg vk_realloc(submit->alloc, 5587ec681f3Smrg submit->fence_bos, new_len * sizeof(*submit->fence_bos), 5597ec681f3Smrg 8, submit->alloc_scope); 5607ec681f3Smrg if (new_fence_bos == NULL) 5617ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 5627ec681f3Smrg 5637ec681f3Smrg submit->fence_bos = new_fence_bos; 5647ec681f3Smrg submit->fence_bo_array_length = new_len; 5657ec681f3Smrg } 5667ec681f3Smrg 5677ec681f3Smrg /* Take advantage that anv_bo are allocated at 8 byte alignement so we can 5687ec681f3Smrg * use the lowest bit to store whether this is a BO we need to signal. 5697ec681f3Smrg */ 5707ec681f3Smrg submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal); 5717ec681f3Smrg 5727ec681f3Smrg return VK_SUCCESS; 5737ec681f3Smrg} 5747ec681f3Smrg 5757ec681f3Smrgstatic VkResult 5767ec681f3Smrganv_queue_submit_add_syncobj(struct anv_queue *queue, 5777ec681f3Smrg struct anv_queue_submit* submit, 5787ec681f3Smrg uint32_t handle, uint32_t flags, 5797ec681f3Smrg uint64_t value) 5807ec681f3Smrg{ 5817ec681f3Smrg assert(flags != 0); 5827ec681f3Smrg 5837ec681f3Smrg if (queue->device->has_thread_submit && (flags & I915_EXEC_FENCE_WAIT)) { 5847ec681f3Smrg if (submit->wait_timeline_count >= submit->wait_timeline_array_length) { 5857ec681f3Smrg uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64); 5867ec681f3Smrg 5877ec681f3Smrg uint32_t *new_wait_timeline_syncobjs = 5887ec681f3Smrg vk_realloc(submit->alloc, 5897ec681f3Smrg submit->wait_timeline_syncobjs, 5907ec681f3Smrg new_len * sizeof(*submit->wait_timeline_syncobjs), 5917ec681f3Smrg 8, submit->alloc_scope); 5927ec681f3Smrg if (new_wait_timeline_syncobjs == NULL) 5937ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 5947ec681f3Smrg 5957ec681f3Smrg submit->wait_timeline_syncobjs = new_wait_timeline_syncobjs; 5967ec681f3Smrg 5977ec681f3Smrg uint64_t *new_wait_timeline_values = 5987ec681f3Smrg vk_realloc(submit->alloc, 5997ec681f3Smrg submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values), 6007ec681f3Smrg 8, submit->alloc_scope); 6017ec681f3Smrg if (new_wait_timeline_values == NULL) 6027ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 6037ec681f3Smrg 6047ec681f3Smrg submit->wait_timeline_values = new_wait_timeline_values; 6057ec681f3Smrg submit->wait_timeline_array_length = new_len; 6067ec681f3Smrg } 6077ec681f3Smrg 6087ec681f3Smrg submit->wait_timeline_syncobjs[submit->wait_timeline_count] = handle; 6097ec681f3Smrg submit->wait_timeline_values[submit->wait_timeline_count] = value; 6107ec681f3Smrg 6117ec681f3Smrg submit->wait_timeline_count++; 6127ec681f3Smrg } 6137ec681f3Smrg 6147ec681f3Smrg if (submit->fence_count >= submit->fence_array_length) { 6157ec681f3Smrg uint32_t new_len = MAX2(submit->fence_array_length * 2, 64); 6167ec681f3Smrg struct drm_i915_gem_exec_fence *new_fences = 6177ec681f3Smrg vk_realloc(submit->alloc, 6187ec681f3Smrg submit->fences, new_len * sizeof(*submit->fences), 6197ec681f3Smrg 8, submit->alloc_scope); 6207ec681f3Smrg if (new_fences == NULL) 6217ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 6227ec681f3Smrg 6237ec681f3Smrg submit->fences = new_fences; 6247ec681f3Smrg 6257ec681f3Smrg uint64_t *new_fence_values = 6267ec681f3Smrg vk_realloc(submit->alloc, 6277ec681f3Smrg submit->fence_values, new_len * sizeof(*submit->fence_values), 6287ec681f3Smrg 8, submit->alloc_scope); 6297ec681f3Smrg if (new_fence_values == NULL) 6307ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 6317ec681f3Smrg 6327ec681f3Smrg submit->fence_values = new_fence_values; 6337ec681f3Smrg submit->fence_array_length = new_len; 6347ec681f3Smrg } 6357ec681f3Smrg 6367ec681f3Smrg submit->fences[submit->fence_count] = (struct drm_i915_gem_exec_fence) { 6377ec681f3Smrg .handle = handle, 6387ec681f3Smrg .flags = flags, 6397ec681f3Smrg }; 6407ec681f3Smrg submit->fence_values[submit->fence_count] = value; 6417ec681f3Smrg submit->fence_count++; 6427ec681f3Smrg 6437ec681f3Smrg return VK_SUCCESS; 6447ec681f3Smrg} 6457ec681f3Smrg 6467ec681f3Smrgstatic VkResult 6477ec681f3Smrganv_queue_submit_add_timeline_wait(struct anv_queue *queue, 6487ec681f3Smrg struct anv_queue_submit* submit, 6497ec681f3Smrg struct anv_timeline *timeline, 6507ec681f3Smrg uint64_t value) 6517ec681f3Smrg{ 6527ec681f3Smrg if (submit->wait_timeline_count >= submit->wait_timeline_array_length) { 6537ec681f3Smrg uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64); 6547ec681f3Smrg struct anv_timeline **new_wait_timelines = 6557ec681f3Smrg vk_realloc(submit->alloc, 6567ec681f3Smrg submit->wait_timelines, new_len * sizeof(*submit->wait_timelines), 6577ec681f3Smrg 8, submit->alloc_scope); 6587ec681f3Smrg if (new_wait_timelines == NULL) 6597ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 6607ec681f3Smrg 6617ec681f3Smrg submit->wait_timelines = new_wait_timelines; 6627ec681f3Smrg 6637ec681f3Smrg uint64_t *new_wait_timeline_values = 6647ec681f3Smrg vk_realloc(submit->alloc, 6657ec681f3Smrg submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values), 6667ec681f3Smrg 8, submit->alloc_scope); 6677ec681f3Smrg if (new_wait_timeline_values == NULL) 6687ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 6697ec681f3Smrg 6707ec681f3Smrg submit->wait_timeline_values = new_wait_timeline_values; 6717ec681f3Smrg 6727ec681f3Smrg submit->wait_timeline_array_length = new_len; 6737ec681f3Smrg } 6747ec681f3Smrg 6757ec681f3Smrg submit->wait_timelines[submit->wait_timeline_count] = timeline; 6767ec681f3Smrg submit->wait_timeline_values[submit->wait_timeline_count] = value; 6777ec681f3Smrg 6787ec681f3Smrg submit->wait_timeline_count++; 6797ec681f3Smrg 6807ec681f3Smrg return VK_SUCCESS; 6817ec681f3Smrg} 6827ec681f3Smrg 6837ec681f3Smrgstatic VkResult 6847ec681f3Smrganv_queue_submit_add_timeline_signal(struct anv_queue *queue, 6857ec681f3Smrg struct anv_queue_submit* submit, 6867ec681f3Smrg struct anv_timeline *timeline, 6877ec681f3Smrg uint64_t value) 6887ec681f3Smrg{ 6897ec681f3Smrg assert(timeline->highest_pending < value); 6907ec681f3Smrg 6917ec681f3Smrg if (submit->signal_timeline_count >= submit->signal_timeline_array_length) { 6927ec681f3Smrg uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64); 6937ec681f3Smrg struct anv_timeline **new_signal_timelines = 6947ec681f3Smrg vk_realloc(submit->alloc, 6957ec681f3Smrg submit->signal_timelines, new_len * sizeof(*submit->signal_timelines), 6967ec681f3Smrg 8, submit->alloc_scope); 6977ec681f3Smrg if (new_signal_timelines == NULL) 6987ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 6997ec681f3Smrg 7007ec681f3Smrg submit->signal_timelines = new_signal_timelines; 7017ec681f3Smrg 7027ec681f3Smrg uint64_t *new_signal_timeline_values = 7037ec681f3Smrg vk_realloc(submit->alloc, 7047ec681f3Smrg submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values), 7057ec681f3Smrg 8, submit->alloc_scope); 7067ec681f3Smrg if (new_signal_timeline_values == NULL) 7077ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 7087ec681f3Smrg 7097ec681f3Smrg submit->signal_timeline_values = new_signal_timeline_values; 7107ec681f3Smrg 7117ec681f3Smrg submit->signal_timeline_array_length = new_len; 7127ec681f3Smrg } 7137ec681f3Smrg 7147ec681f3Smrg submit->signal_timelines[submit->signal_timeline_count] = timeline; 7157ec681f3Smrg submit->signal_timeline_values[submit->signal_timeline_count] = value; 7167ec681f3Smrg 7177ec681f3Smrg submit->signal_timeline_count++; 7187ec681f3Smrg 7197ec681f3Smrg return VK_SUCCESS; 7207ec681f3Smrg} 7217ec681f3Smrg 7227ec681f3Smrgstatic struct anv_queue_submit * 7237ec681f3Smrganv_queue_submit_alloc(struct anv_device *device) 7247ec681f3Smrg{ 7257ec681f3Smrg const VkAllocationCallbacks *alloc = &device->vk.alloc; 7267ec681f3Smrg VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; 7277ec681f3Smrg 7287ec681f3Smrg struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope); 7297ec681f3Smrg if (!submit) 7307ec681f3Smrg return NULL; 7317ec681f3Smrg 7327ec681f3Smrg submit->alloc = alloc; 7337ec681f3Smrg submit->alloc_scope = alloc_scope; 7347ec681f3Smrg submit->in_fence = -1; 7357ec681f3Smrg submit->out_fence = -1; 7367ec681f3Smrg submit->perf_query_pass = -1; 7377ec681f3Smrg 7387ec681f3Smrg return submit; 7397ec681f3Smrg} 7407ec681f3Smrg 7417ec681f3SmrgVkResult 7427ec681f3Smrganv_queue_submit_simple_batch(struct anv_queue *queue, 7437ec681f3Smrg struct anv_batch *batch) 7447ec681f3Smrg{ 7457ec681f3Smrg if (queue->device->info.no_hw) 7467ec681f3Smrg return VK_SUCCESS; 7477ec681f3Smrg 7487ec681f3Smrg struct anv_device *device = queue->device; 7497ec681f3Smrg struct anv_queue_submit *submit = anv_queue_submit_alloc(device); 7507ec681f3Smrg if (!submit) 7517ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 7527ec681f3Smrg 7537ec681f3Smrg bool has_syncobj_wait = device->physical->has_syncobj_wait; 7547ec681f3Smrg VkResult result; 7557ec681f3Smrg uint32_t syncobj; 7567ec681f3Smrg struct anv_bo *batch_bo, *sync_bo; 7577ec681f3Smrg 7587ec681f3Smrg if (has_syncobj_wait) { 7597ec681f3Smrg syncobj = anv_gem_syncobj_create(device, 0); 7607ec681f3Smrg if (!syncobj) { 7617ec681f3Smrg result = vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 7627ec681f3Smrg goto err_free_submit; 7637ec681f3Smrg } 7647ec681f3Smrg 7657ec681f3Smrg result = anv_queue_submit_add_syncobj(queue, submit, syncobj, 7667ec681f3Smrg I915_EXEC_FENCE_SIGNAL, 0); 7677ec681f3Smrg } else { 7687ec681f3Smrg result = anv_device_alloc_bo(device, "simple-batch-sync", 4096, 7697ec681f3Smrg ANV_BO_ALLOC_EXTERNAL | 7707ec681f3Smrg ANV_BO_ALLOC_IMPLICIT_SYNC, 7717ec681f3Smrg 0 /* explicit_address */, 7727ec681f3Smrg &sync_bo); 7737ec681f3Smrg if (result != VK_SUCCESS) 7747ec681f3Smrg goto err_free_submit; 7757ec681f3Smrg 7767ec681f3Smrg result = anv_queue_submit_add_fence_bo(queue, submit, sync_bo, 7777ec681f3Smrg true /* signal */); 7787ec681f3Smrg } 7797ec681f3Smrg 7807ec681f3Smrg if (result != VK_SUCCESS) 7817ec681f3Smrg goto err_destroy_sync_primitive; 7827ec681f3Smrg 7837ec681f3Smrg if (batch) { 7847ec681f3Smrg uint32_t size = align_u32(batch->next - batch->start, 8); 7857ec681f3Smrg result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo); 7867ec681f3Smrg if (result != VK_SUCCESS) 7877ec681f3Smrg goto err_destroy_sync_primitive; 7887ec681f3Smrg 7897ec681f3Smrg memcpy(batch_bo->map, batch->start, size); 7907ec681f3Smrg if (!device->info.has_llc) 7917ec681f3Smrg intel_flush_range(batch_bo->map, size); 7927ec681f3Smrg 7937ec681f3Smrg submit->simple_bo = batch_bo; 7947ec681f3Smrg submit->simple_bo_size = size; 7957ec681f3Smrg } 7967ec681f3Smrg 7977ec681f3Smrg result = anv_queue_submit_post(queue, &submit, true); 7987ec681f3Smrg 7997ec681f3Smrg if (result == VK_SUCCESS) { 8007ec681f3Smrg if (has_syncobj_wait) { 8017ec681f3Smrg if (anv_gem_syncobj_wait(device, &syncobj, 1, 8027ec681f3Smrg anv_get_absolute_timeout(INT64_MAX), true)) 8037ec681f3Smrg result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m"); 8047ec681f3Smrg anv_gem_syncobj_destroy(device, syncobj); 8057ec681f3Smrg } else { 8067ec681f3Smrg result = anv_device_wait(device, sync_bo, 8077ec681f3Smrg anv_get_relative_timeout(INT64_MAX)); 8087ec681f3Smrg anv_device_release_bo(device, sync_bo); 8097ec681f3Smrg } 8107ec681f3Smrg } 8117ec681f3Smrg 8127ec681f3Smrg if (batch) 8137ec681f3Smrg anv_bo_pool_free(&device->batch_bo_pool, batch_bo); 8147ec681f3Smrg 8157ec681f3Smrg if (submit) 8167ec681f3Smrg anv_queue_submit_free(device, submit); 8177ec681f3Smrg 8187ec681f3Smrg return result; 8197ec681f3Smrg 8207ec681f3Smrg err_destroy_sync_primitive: 8217ec681f3Smrg if (has_syncobj_wait) 8227ec681f3Smrg anv_gem_syncobj_destroy(device, syncobj); 8237ec681f3Smrg else 8247ec681f3Smrg anv_device_release_bo(device, sync_bo); 8257ec681f3Smrg err_free_submit: 8267ec681f3Smrg if (submit) 8277ec681f3Smrg anv_queue_submit_free(device, submit); 8287ec681f3Smrg 8297ec681f3Smrg return result; 8307ec681f3Smrg} 8317ec681f3Smrg 8327ec681f3Smrgstatic VkResult 8337ec681f3Smrgadd_temporary_semaphore(struct anv_queue *queue, 8347ec681f3Smrg struct anv_queue_submit *submit, 8357ec681f3Smrg struct anv_semaphore_impl *impl, 8367ec681f3Smrg struct anv_semaphore_impl **out_impl) 8377ec681f3Smrg{ 8387ec681f3Smrg /* 8397ec681f3Smrg * There is a requirement to reset semaphore to their permanent state after 8407ec681f3Smrg * submission. From the Vulkan 1.0.53 spec: 8417ec681f3Smrg * 8427ec681f3Smrg * "If the import is temporary, the implementation must restore the 8437ec681f3Smrg * semaphore to its prior permanent state after submitting the next 8447ec681f3Smrg * semaphore wait operation." 8457ec681f3Smrg * 8467ec681f3Smrg * In the case we defer the actual submission to a thread because of the 8477ec681f3Smrg * wait-before-submit behavior required for timeline semaphores, we need to 8487ec681f3Smrg * make copies of the temporary syncobj to ensure they stay alive until we 8497ec681f3Smrg * do the actual execbuffer ioctl. 8507ec681f3Smrg */ 8517ec681f3Smrg if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) { 8527ec681f3Smrg uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8); 8537ec681f3Smrg /* Make sure that if the realloc fails, we still have the old semaphore 8547ec681f3Smrg * array around to properly clean things up on failure. 8557ec681f3Smrg */ 8567ec681f3Smrg struct anv_semaphore_impl *new_array = 8577ec681f3Smrg vk_realloc(submit->alloc, 8587ec681f3Smrg submit->temporary_semaphores, 8597ec681f3Smrg new_len * sizeof(*submit->temporary_semaphores), 8607ec681f3Smrg 8, submit->alloc_scope); 8617ec681f3Smrg if (new_array == NULL) 8627ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 8637ec681f3Smrg 8647ec681f3Smrg submit->temporary_semaphores = new_array; 8657ec681f3Smrg submit->temporary_semaphore_array_length = new_len; 8667ec681f3Smrg } 8677ec681f3Smrg 8687ec681f3Smrg /* Copy anv_semaphore_impl into anv_queue_submit. */ 8697ec681f3Smrg submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl; 8707ec681f3Smrg *out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1]; 8717ec681f3Smrg 8727ec681f3Smrg return VK_SUCCESS; 8737ec681f3Smrg} 8747ec681f3Smrg 8757ec681f3Smrgstatic VkResult 8767ec681f3Smrgclone_syncobj_dma_fence(struct anv_queue *queue, 8777ec681f3Smrg struct anv_semaphore_impl *out, 8787ec681f3Smrg const struct anv_semaphore_impl *in) 8797ec681f3Smrg{ 8807ec681f3Smrg struct anv_device *device = queue->device; 8817ec681f3Smrg 8827ec681f3Smrg out->syncobj = anv_gem_syncobj_create(device, 0); 8837ec681f3Smrg if (!out->syncobj) 8847ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 8857ec681f3Smrg 8867ec681f3Smrg int fd = anv_gem_syncobj_export_sync_file(device, in->syncobj); 8877ec681f3Smrg if (fd < 0) { 8887ec681f3Smrg anv_gem_syncobj_destroy(device, out->syncobj); 8897ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 8907ec681f3Smrg } 8917ec681f3Smrg 8927ec681f3Smrg int ret = anv_gem_syncobj_import_sync_file(device, 8937ec681f3Smrg out->syncobj, 8947ec681f3Smrg fd); 8957ec681f3Smrg close(fd); 8967ec681f3Smrg if (ret < 0) { 8977ec681f3Smrg anv_gem_syncobj_destroy(device, out->syncobj); 8987ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_DEVICE_MEMORY); 8997ec681f3Smrg } 9007ec681f3Smrg 9017ec681f3Smrg return VK_SUCCESS; 9027ec681f3Smrg} 9037ec681f3Smrg 9047ec681f3Smrg/* Clone semaphore in the following cases : 9057ec681f3Smrg * 9067ec681f3Smrg * - We're dealing with a temporary semaphore that needs to be reset to 9077ec681f3Smrg * follow the Vulkan spec requirements. 9087ec681f3Smrg * 9097ec681f3Smrg * - We're dealing with a syncobj semaphore and are using threaded 9107ec681f3Smrg * submission to i915. Because we might want to export the semaphore right 9117ec681f3Smrg * after calling vkQueueSubmit, we need to make sure it doesn't contain a 9127ec681f3Smrg * staled DMA fence. In this case we reset the original syncobj, but make 9137ec681f3Smrg * a clone of the contained DMA fence into another syncobj for submission 9147ec681f3Smrg * to i915. 9157ec681f3Smrg * 9167ec681f3Smrg * Those temporary semaphores are later freed in anv_queue_submit_free(). 9177ec681f3Smrg */ 9187ec681f3Smrgstatic VkResult 9197ec681f3Smrgmaybe_transfer_temporary_semaphore(struct anv_queue *queue, 9207ec681f3Smrg struct anv_queue_submit *submit, 9217ec681f3Smrg struct anv_semaphore *semaphore, 9227ec681f3Smrg struct anv_semaphore_impl **out_impl) 9237ec681f3Smrg{ 9247ec681f3Smrg struct anv_semaphore_impl *impl = &semaphore->temporary; 9257ec681f3Smrg VkResult result; 9267ec681f3Smrg 9277ec681f3Smrg if (impl->type == ANV_SEMAPHORE_TYPE_NONE) { 9287ec681f3Smrg /* No temporary, use the permanent semaphore. */ 9297ec681f3Smrg impl = &semaphore->permanent; 9307ec681f3Smrg 9317ec681f3Smrg /* We need to reset syncobj before submission so that they do not 9327ec681f3Smrg * contain a stale DMA fence. When using a submission thread this is 9337ec681f3Smrg * problematic because the i915 EXECBUF ioctl happens after 9347ec681f3Smrg * vkQueueSubmit has returned. A subsequent vkQueueSubmit() call could 9357ec681f3Smrg * reset the syncobj that i915 is about to see from the submission 9367ec681f3Smrg * thread. 9377ec681f3Smrg * 9387ec681f3Smrg * To avoid this, clone the DMA fence in the semaphore, into a another 9397ec681f3Smrg * syncobj that the submission thread will destroy when it's done with 9407ec681f3Smrg * it. 9417ec681f3Smrg */ 9427ec681f3Smrg if (queue->device->physical->has_thread_submit && 9437ec681f3Smrg impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ) { 9447ec681f3Smrg struct anv_semaphore_impl template = { 9457ec681f3Smrg .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ, 9467ec681f3Smrg }; 9477ec681f3Smrg 9487ec681f3Smrg /* Put the fence into a new syncobj so the old one can be reset. */ 9497ec681f3Smrg result = clone_syncobj_dma_fence(queue, &template, impl); 9507ec681f3Smrg if (result != VK_SUCCESS) 9517ec681f3Smrg return result; 9527ec681f3Smrg 9537ec681f3Smrg /* Create a copy of the anv_semaphore structure. */ 9547ec681f3Smrg result = add_temporary_semaphore(queue, submit, &template, out_impl); 9557ec681f3Smrg if (result != VK_SUCCESS) { 9567ec681f3Smrg anv_gem_syncobj_destroy(queue->device, template.syncobj); 9577ec681f3Smrg return result; 9587ec681f3Smrg } 9597ec681f3Smrg 9607ec681f3Smrg return VK_SUCCESS; 9617ec681f3Smrg } 9627ec681f3Smrg 9637ec681f3Smrg *out_impl = impl; 9647ec681f3Smrg return VK_SUCCESS; 9657ec681f3Smrg } 9667ec681f3Smrg 9677ec681f3Smrg /* BO backed timeline semaphores cannot be temporary. */ 9687ec681f3Smrg assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE); 96901e04c3fSmrg 9707ec681f3Smrg /* Copy anv_semaphore_impl into anv_queue_submit. */ 9717ec681f3Smrg result = add_temporary_semaphore(queue, submit, impl, out_impl); 9727ec681f3Smrg if (result != VK_SUCCESS) 9737ec681f3Smrg return result; 9747ec681f3Smrg 9757ec681f3Smrg /* Clear the incoming semaphore */ 9767ec681f3Smrg impl->type = ANV_SEMAPHORE_TYPE_NONE; 9777ec681f3Smrg 9787ec681f3Smrg return VK_SUCCESS; 9797ec681f3Smrg} 9807ec681f3Smrg 9817ec681f3Smrgstatic VkResult 9827ec681f3Smrganv_queue_submit_add_in_semaphore(struct anv_queue *queue, 9837ec681f3Smrg struct anv_queue_submit *submit, 9847ec681f3Smrg const VkSemaphore _semaphore, 9857ec681f3Smrg const uint64_t value) 98601e04c3fSmrg{ 9877ec681f3Smrg ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 9887ec681f3Smrg struct anv_semaphore_impl *impl = 9897ec681f3Smrg semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 9907ec681f3Smrg &semaphore->temporary : &semaphore->permanent; 9917ec681f3Smrg VkResult result; 9927ec681f3Smrg 9937ec681f3Smrg /* When using a binary semaphore with threaded submission, wait for the 9947ec681f3Smrg * dma-fence to materialize in the syncobj. This is needed to be able to 9957ec681f3Smrg * clone in maybe_transfer_temporary_semaphore(). 9967ec681f3Smrg */ 9977ec681f3Smrg if (queue->device->has_thread_submit && 9987ec681f3Smrg impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ) { 9997ec681f3Smrg uint64_t value = 0; 10007ec681f3Smrg int ret = 10017ec681f3Smrg anv_gem_syncobj_timeline_wait(queue->device, 10027ec681f3Smrg &impl->syncobj, &value, 1, 10037ec681f3Smrg anv_get_absolute_timeout(INT64_MAX), 10047ec681f3Smrg true /* wait_all */, 10057ec681f3Smrg true /* wait_materialize */); 10067ec681f3Smrg if (ret != 0) { 10077ec681f3Smrg return anv_queue_set_lost(queue, 10087ec681f3Smrg "unable to wait on syncobj to materialize"); 10097ec681f3Smrg } 101001e04c3fSmrg } 101101e04c3fSmrg 10127ec681f3Smrg result = maybe_transfer_temporary_semaphore(queue, submit, semaphore, &impl); 10137ec681f3Smrg if (result != VK_SUCCESS) 10147ec681f3Smrg return result; 10157ec681f3Smrg 10167ec681f3Smrg switch (impl->type) { 10177ec681f3Smrg case ANV_SEMAPHORE_TYPE_WSI_BO: 10187ec681f3Smrg /* When using a window-system buffer as a semaphore, always enable 10197ec681f3Smrg * EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or 10207ec681f3Smrg * compositor's read of the buffer and enforces that we don't start 10217ec681f3Smrg * rendering until they are finished. This is exactly the 10227ec681f3Smrg * synchronization we want with vkAcquireNextImage. 10237ec681f3Smrg */ 10247ec681f3Smrg result = anv_queue_submit_add_fence_bo(queue, submit, impl->bo, 10257ec681f3Smrg true /* signal */); 10267ec681f3Smrg if (result != VK_SUCCESS) 10277ec681f3Smrg return result; 10287ec681f3Smrg break; 10297ec681f3Smrg 10307ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: 10317ec681f3Smrg result = anv_queue_submit_add_syncobj(queue, submit, 10327ec681f3Smrg impl->syncobj, 10337ec681f3Smrg I915_EXEC_FENCE_WAIT, 10347ec681f3Smrg 0); 10357ec681f3Smrg if (result != VK_SUCCESS) 10367ec681f3Smrg return result; 10377ec681f3Smrg break; 10387ec681f3Smrg 10397ec681f3Smrg case ANV_SEMAPHORE_TYPE_TIMELINE: 10407ec681f3Smrg if (value == 0) 10417ec681f3Smrg break; 10427ec681f3Smrg result = anv_queue_submit_add_timeline_wait(queue, submit, 10437ec681f3Smrg &impl->timeline, 10447ec681f3Smrg value); 10457ec681f3Smrg if (result != VK_SUCCESS) 10467ec681f3Smrg return result; 10477ec681f3Smrg break; 10487ec681f3Smrg 10497ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 10507ec681f3Smrg if (value == 0) 10517ec681f3Smrg break; 10527ec681f3Smrg result = anv_queue_submit_add_syncobj(queue, submit, 10537ec681f3Smrg impl->syncobj, 10547ec681f3Smrg I915_EXEC_FENCE_WAIT, 10557ec681f3Smrg value); 10567ec681f3Smrg if (result != VK_SUCCESS) 10577ec681f3Smrg return result; 10587ec681f3Smrg break; 10597ec681f3Smrg 10607ec681f3Smrg default: 10617ec681f3Smrg break; 106201e04c3fSmrg } 106301e04c3fSmrg 106401e04c3fSmrg return VK_SUCCESS; 106501e04c3fSmrg} 106601e04c3fSmrg 10677ec681f3Smrgstatic VkResult 10687ec681f3Smrganv_queue_submit_add_out_semaphore(struct anv_queue *queue, 10697ec681f3Smrg struct anv_queue_submit *submit, 10707ec681f3Smrg const VkSemaphore _semaphore, 10717ec681f3Smrg const uint64_t value) 107201e04c3fSmrg{ 10737ec681f3Smrg ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 10747ec681f3Smrg VkResult result; 107501e04c3fSmrg 10767ec681f3Smrg /* Under most circumstances, out fences won't be temporary. However, the 10777ec681f3Smrg * spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec: 10787ec681f3Smrg * 10797ec681f3Smrg * "If the import is temporary, the implementation must restore the 10807ec681f3Smrg * semaphore to its prior permanent state after submitting the next 10817ec681f3Smrg * semaphore wait operation." 10827ec681f3Smrg * 10837ec681f3Smrg * The spec says nothing whatsoever about signal operations on temporarily 10847ec681f3Smrg * imported semaphores so it appears they are allowed. There are also CTS 10857ec681f3Smrg * tests that require this to work. 10867ec681f3Smrg */ 10877ec681f3Smrg struct anv_semaphore_impl *impl = 10887ec681f3Smrg semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 10897ec681f3Smrg &semaphore->temporary : &semaphore->permanent; 109001e04c3fSmrg 10917ec681f3Smrg switch (impl->type) { 10927ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: { 10937ec681f3Smrg /* 10947ec681f3Smrg * Reset the content of the syncobj so it doesn't contain a previously 10957ec681f3Smrg * signaled dma-fence, until one is added by EXECBUFFER by the 10967ec681f3Smrg * submission thread. 10977ec681f3Smrg */ 10987ec681f3Smrg anv_gem_syncobj_reset(queue->device, impl->syncobj); 10997ec681f3Smrg 11007ec681f3Smrg result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj, 11017ec681f3Smrg I915_EXEC_FENCE_SIGNAL, 11027ec681f3Smrg 0); 11037ec681f3Smrg if (result != VK_SUCCESS) 11047ec681f3Smrg return result; 11057ec681f3Smrg break; 11067ec681f3Smrg } 110701e04c3fSmrg 11087ec681f3Smrg case ANV_SEMAPHORE_TYPE_TIMELINE: 11097ec681f3Smrg if (value == 0) 11107ec681f3Smrg break; 11117ec681f3Smrg result = anv_queue_submit_add_timeline_signal(queue, submit, 11127ec681f3Smrg &impl->timeline, 11137ec681f3Smrg value); 11147ec681f3Smrg if (result != VK_SUCCESS) 11157ec681f3Smrg return result; 11167ec681f3Smrg break; 111701e04c3fSmrg 11187ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 11197ec681f3Smrg if (value == 0) 11207ec681f3Smrg break; 11217ec681f3Smrg result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj, 11227ec681f3Smrg I915_EXEC_FENCE_SIGNAL, 11237ec681f3Smrg value); 11247ec681f3Smrg if (result != VK_SUCCESS) 11257ec681f3Smrg return result; 11267ec681f3Smrg break; 112701e04c3fSmrg 11287ec681f3Smrg default: 11297ec681f3Smrg break; 11307ec681f3Smrg } 11317ec681f3Smrg 11327ec681f3Smrg return VK_SUCCESS; 11337ec681f3Smrg} 11347ec681f3Smrg 11357ec681f3Smrgstatic VkResult 11367ec681f3Smrganv_queue_submit_add_fence(struct anv_queue *queue, 11377ec681f3Smrg struct anv_queue_submit *submit, 11387ec681f3Smrg struct anv_fence *fence) 11397ec681f3Smrg{ 11407ec681f3Smrg /* Under most circumstances, out fences won't be temporary. However, the 11417ec681f3Smrg * spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec: 11427ec681f3Smrg * 11437ec681f3Smrg * "If the import is temporary, the implementation must restore the 11447ec681f3Smrg * semaphore to its prior permanent state after submitting the next 11457ec681f3Smrg * semaphore wait operation." 11467ec681f3Smrg * 11477ec681f3Smrg * The spec says nothing whatsoever about signal operations on temporarily 11487ec681f3Smrg * imported semaphores so it appears they are allowed. There are also CTS 11497ec681f3Smrg * tests that require this to work. 11507ec681f3Smrg */ 11517ec681f3Smrg struct anv_fence_impl *impl = 11527ec681f3Smrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 11537ec681f3Smrg &fence->temporary : &fence->permanent; 11547ec681f3Smrg 11557ec681f3Smrg VkResult result; 11567ec681f3Smrg 11577ec681f3Smrg switch (impl->type) { 11587ec681f3Smrg case ANV_FENCE_TYPE_BO: 11597ec681f3Smrg assert(!queue->device->has_thread_submit); 11607ec681f3Smrg result = anv_queue_submit_add_fence_bo(queue, submit, impl->bo.bo, 11617ec681f3Smrg true /* signal */); 11627ec681f3Smrg if (result != VK_SUCCESS) 11637ec681f3Smrg return result; 11647ec681f3Smrg break; 11657ec681f3Smrg 11667ec681f3Smrg case ANV_FENCE_TYPE_SYNCOBJ: { 11677ec681f3Smrg /* 11687ec681f3Smrg * For the same reason we reset the signaled binary syncobj above, also 11697ec681f3Smrg * reset the fence's syncobj so that they don't contain a signaled 11707ec681f3Smrg * dma-fence. 11717ec681f3Smrg */ 11727ec681f3Smrg anv_gem_syncobj_reset(queue->device, impl->syncobj); 11737ec681f3Smrg 11747ec681f3Smrg result = anv_queue_submit_add_syncobj(queue, submit, impl->syncobj, 11757ec681f3Smrg I915_EXEC_FENCE_SIGNAL, 11767ec681f3Smrg 0); 11777ec681f3Smrg if (result != VK_SUCCESS) 11787ec681f3Smrg return result; 11797ec681f3Smrg break; 11807ec681f3Smrg } 11817ec681f3Smrg 11827ec681f3Smrg default: 11837ec681f3Smrg unreachable("Invalid fence type"); 11847ec681f3Smrg } 11857ec681f3Smrg 11867ec681f3Smrg return VK_SUCCESS; 11877ec681f3Smrg} 11887ec681f3Smrg 11897ec681f3Smrgstatic void 11907ec681f3Smrganv_post_queue_fence_update(struct anv_device *device, struct anv_fence *fence) 11917ec681f3Smrg{ 11927ec681f3Smrg if (fence->permanent.type == ANV_FENCE_TYPE_BO) { 11937ec681f3Smrg assert(!device->has_thread_submit); 11947ec681f3Smrg /* If we have permanent BO fence, the only type of temporary possible 11957ec681f3Smrg * would be BO_WSI (because BO fences are not shareable). The Vulkan spec 11967ec681f3Smrg * also requires that the fence passed to vkQueueSubmit() be : 11977ec681f3Smrg * 11987ec681f3Smrg * * unsignaled 11997ec681f3Smrg * * not be associated with any other queue command that has not yet 12007ec681f3Smrg * completed execution on that queue 12017ec681f3Smrg * 12027ec681f3Smrg * So the only acceptable type for the temporary is NONE. 12037ec681f3Smrg */ 12047ec681f3Smrg assert(fence->temporary.type == ANV_FENCE_TYPE_NONE); 12057ec681f3Smrg 12067ec681f3Smrg /* Once the execbuf has returned, we need to set the fence state to 12077ec681f3Smrg * SUBMITTED. We can't do this before calling execbuf because 12087ec681f3Smrg * anv_GetFenceStatus does take the global device lock before checking 12097ec681f3Smrg * fence->state. 12107ec681f3Smrg * 12117ec681f3Smrg * We set the fence state to SUBMITTED regardless of whether or not the 12127ec681f3Smrg * execbuf succeeds because we need to ensure that vkWaitForFences() and 12137ec681f3Smrg * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or 12147ec681f3Smrg * VK_SUCCESS) in a finite amount of time even if execbuf fails. 12157ec681f3Smrg */ 12167ec681f3Smrg fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED; 12177ec681f3Smrg } 12187ec681f3Smrg} 12197ec681f3Smrg 12207ec681f3Smrgstatic VkResult 12217ec681f3Smrganv_queue_submit_add_cmd_buffer(struct anv_queue *queue, 12227ec681f3Smrg struct anv_queue_submit *submit, 12237ec681f3Smrg struct anv_cmd_buffer *cmd_buffer, 12247ec681f3Smrg int perf_pass) 12257ec681f3Smrg{ 12267ec681f3Smrg if (submit->cmd_buffer_count >= submit->cmd_buffer_array_length) { 12277ec681f3Smrg uint32_t new_len = MAX2(submit->cmd_buffer_array_length * 2, 4); 12287ec681f3Smrg struct anv_cmd_buffer **new_cmd_buffers = 12297ec681f3Smrg vk_realloc(submit->alloc, 12307ec681f3Smrg submit->cmd_buffers, new_len * sizeof(*submit->cmd_buffers), 12317ec681f3Smrg 8, submit->alloc_scope); 12327ec681f3Smrg if (new_cmd_buffers == NULL) 12337ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 12347ec681f3Smrg 12357ec681f3Smrg submit->cmd_buffers = new_cmd_buffers; 12367ec681f3Smrg submit->cmd_buffer_array_length = new_len; 12377ec681f3Smrg } 12387ec681f3Smrg 12397ec681f3Smrg submit->cmd_buffers[submit->cmd_buffer_count++] = cmd_buffer; 12407ec681f3Smrg /* Only update the perf_query_pool if there is one. We can decide to batch 12417ec681f3Smrg * 2 command buffers if the second one doesn't use a query pool, but we 12427ec681f3Smrg * can't drop the already chosen one. 12437ec681f3Smrg */ 12447ec681f3Smrg if (cmd_buffer->perf_query_pool) 12457ec681f3Smrg submit->perf_query_pool = cmd_buffer->perf_query_pool; 12467ec681f3Smrg submit->perf_query_pass = perf_pass; 12477ec681f3Smrg 12487ec681f3Smrg return VK_SUCCESS; 12497ec681f3Smrg} 12507ec681f3Smrg 12517ec681f3Smrgstatic bool 12527ec681f3Smrganv_queue_submit_can_add_cmd_buffer(const struct anv_queue_submit *submit, 12537ec681f3Smrg const struct anv_cmd_buffer *cmd_buffer, 12547ec681f3Smrg int perf_pass) 12557ec681f3Smrg{ 12567ec681f3Smrg /* If first command buffer, no problem. */ 12577ec681f3Smrg if (submit->cmd_buffer_count == 0) 12587ec681f3Smrg return true; 12597ec681f3Smrg 12607ec681f3Smrg /* Can we chain the last buffer into the next one? */ 12617ec681f3Smrg if (!anv_cmd_buffer_is_chainable(submit->cmd_buffers[submit->cmd_buffer_count - 1])) 12627ec681f3Smrg return false; 12637ec681f3Smrg 12647ec681f3Smrg /* A change of perf query pools between VkSubmitInfo elements means we 12657ec681f3Smrg * can't batch things up. 12667ec681f3Smrg */ 12677ec681f3Smrg if (cmd_buffer->perf_query_pool && 12687ec681f3Smrg submit->perf_query_pool && 12697ec681f3Smrg submit->perf_query_pool != cmd_buffer->perf_query_pool) 12707ec681f3Smrg return false; 12717ec681f3Smrg 12727ec681f3Smrg /* A change of perf pass also prevents batching things up. 12737ec681f3Smrg */ 12747ec681f3Smrg if (submit->perf_query_pass != -1 && 12757ec681f3Smrg submit->perf_query_pass != perf_pass) 12767ec681f3Smrg return false; 12777ec681f3Smrg 12787ec681f3Smrg return true; 12797ec681f3Smrg} 12807ec681f3Smrg 12817ec681f3Smrgstatic bool 12827ec681f3Smrganv_queue_submit_can_add_submit(const struct anv_queue_submit *submit, 12837ec681f3Smrg uint32_t n_wait_semaphores, 12847ec681f3Smrg uint32_t n_signal_semaphores, 12857ec681f3Smrg int perf_pass) 12867ec681f3Smrg{ 12877ec681f3Smrg /* We can add to an empty anv_queue_submit. */ 12887ec681f3Smrg if (submit->cmd_buffer_count == 0 && 12897ec681f3Smrg submit->fence_count == 0 && 12907ec681f3Smrg submit->wait_timeline_count == 0 && 12917ec681f3Smrg submit->signal_timeline_count == 0 && 12927ec681f3Smrg submit->fence_bo_count == 0) 12937ec681f3Smrg return true; 12947ec681f3Smrg 12957ec681f3Smrg /* Different perf passes will require different EXECBUF ioctls. */ 12967ec681f3Smrg if (perf_pass != submit->perf_query_pass) 12977ec681f3Smrg return false; 12987ec681f3Smrg 12997ec681f3Smrg /* If the current submit is signaling anything, we can't add anything. */ 13007ec681f3Smrg if (submit->signal_timeline_count) 13017ec681f3Smrg return false; 13027ec681f3Smrg 13037ec681f3Smrg /* If a submit is waiting on anything, anything that happened before needs 13047ec681f3Smrg * to be submitted. 13057ec681f3Smrg */ 13067ec681f3Smrg if (n_wait_semaphores) 13077ec681f3Smrg return false; 13087ec681f3Smrg 13097ec681f3Smrg return true; 13107ec681f3Smrg} 13117ec681f3Smrg 13127ec681f3Smrgstatic VkResult 13137ec681f3Smrganv_queue_submit_post_and_alloc_new(struct anv_queue *queue, 13147ec681f3Smrg struct anv_queue_submit **submit) 13157ec681f3Smrg{ 13167ec681f3Smrg VkResult result = anv_queue_submit_post(queue, submit, false); 13177ec681f3Smrg if (result != VK_SUCCESS) 13187ec681f3Smrg return result; 13197ec681f3Smrg 13207ec681f3Smrg *submit = anv_queue_submit_alloc(queue->device); 13217ec681f3Smrg if (!*submit) 13227ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 13237ec681f3Smrg return VK_SUCCESS; 132401e04c3fSmrg} 132501e04c3fSmrg 13267ec681f3SmrgVkResult anv_QueueSubmit2KHR( 132701e04c3fSmrg VkQueue _queue, 132801e04c3fSmrg uint32_t submitCount, 13297ec681f3Smrg const VkSubmitInfo2KHR* pSubmits, 13307ec681f3Smrg VkFence _fence) 133101e04c3fSmrg{ 133201e04c3fSmrg ANV_FROM_HANDLE(anv_queue, queue, _queue); 13337ec681f3Smrg ANV_FROM_HANDLE(anv_fence, fence, _fence); 133401e04c3fSmrg struct anv_device *device = queue->device; 133501e04c3fSmrg 13367ec681f3Smrg if (device->info.no_hw) 13377ec681f3Smrg return VK_SUCCESS; 13387ec681f3Smrg 133901e04c3fSmrg /* Query for device status prior to submitting. Technically, we don't need 134001e04c3fSmrg * to do this. However, if we have a client that's submitting piles of 134101e04c3fSmrg * garbage, we would rather break as early as possible to keep the GPU 134201e04c3fSmrg * hanging contained. If we don't check here, we'll either be waiting for 134301e04c3fSmrg * the kernel to kick us or we'll have to wait until the client waits on a 134401e04c3fSmrg * fence before we actually know whether or not we've hung. 134501e04c3fSmrg */ 134601e04c3fSmrg VkResult result = anv_device_query_status(device); 134701e04c3fSmrg if (result != VK_SUCCESS) 134801e04c3fSmrg return result; 134901e04c3fSmrg 13507ec681f3Smrg struct anv_queue_submit *submit = anv_queue_submit_alloc(device); 13517ec681f3Smrg if (!submit) 13527ec681f3Smrg return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 135301e04c3fSmrg 135401e04c3fSmrg for (uint32_t i = 0; i < submitCount; i++) { 13557ec681f3Smrg const struct wsi_memory_signal_submit_info *mem_signal_info = 13567ec681f3Smrg vk_find_struct_const(pSubmits[i].pNext, 13577ec681f3Smrg WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA); 13587ec681f3Smrg struct anv_bo *wsi_signal_bo = 13597ec681f3Smrg mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ? 13607ec681f3Smrg anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL; 13617ec681f3Smrg 13627ec681f3Smrg const VkPerformanceQuerySubmitInfoKHR *perf_info = 13637ec681f3Smrg vk_find_struct_const(pSubmits[i].pNext, 13647ec681f3Smrg PERFORMANCE_QUERY_SUBMIT_INFO_KHR); 13657ec681f3Smrg const int perf_pass = perf_info ? perf_info->counterPassIndex : 0; 13667ec681f3Smrg 13677ec681f3Smrg if (!anv_queue_submit_can_add_submit(submit, 13687ec681f3Smrg pSubmits[i].waitSemaphoreInfoCount, 13697ec681f3Smrg pSubmits[i].signalSemaphoreInfoCount, 13707ec681f3Smrg perf_pass)) { 13717ec681f3Smrg result = anv_queue_submit_post_and_alloc_new(queue, &submit); 137201e04c3fSmrg if (result != VK_SUCCESS) 137301e04c3fSmrg goto out; 13747ec681f3Smrg } 137501e04c3fSmrg 13767ec681f3Smrg /* Wait semaphores */ 13777ec681f3Smrg for (uint32_t j = 0; j < pSubmits[i].waitSemaphoreInfoCount; j++) { 13787ec681f3Smrg result = anv_queue_submit_add_in_semaphore(queue, submit, 13797ec681f3Smrg pSubmits[i].pWaitSemaphoreInfos[j].semaphore, 13807ec681f3Smrg pSubmits[i].pWaitSemaphoreInfos[j].value); 13817ec681f3Smrg if (result != VK_SUCCESS) 13827ec681f3Smrg goto out; 138301e04c3fSmrg } 138401e04c3fSmrg 13857ec681f3Smrg /* Command buffers */ 13867ec681f3Smrg for (uint32_t j = 0; j < pSubmits[i].commandBufferInfoCount; j++) { 138701e04c3fSmrg ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, 13887ec681f3Smrg pSubmits[i].pCommandBufferInfos[j].commandBuffer); 138901e04c3fSmrg assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY); 139001e04c3fSmrg assert(!anv_batch_has_error(&cmd_buffer->batch)); 13917ec681f3Smrg anv_measure_submit(cmd_buffer); 139201e04c3fSmrg 13937ec681f3Smrg /* If we can't add an additional command buffer to the existing 13947ec681f3Smrg * anv_queue_submit, post it and create a new one. 13957ec681f3Smrg */ 13967ec681f3Smrg if (!anv_queue_submit_can_add_cmd_buffer(submit, cmd_buffer, perf_pass)) { 13977ec681f3Smrg result = anv_queue_submit_post_and_alloc_new(queue, &submit); 13987ec681f3Smrg if (result != VK_SUCCESS) 13997ec681f3Smrg goto out; 140001e04c3fSmrg } 140101e04c3fSmrg 14027ec681f3Smrg result = anv_queue_submit_add_cmd_buffer(queue, submit, 14037ec681f3Smrg cmd_buffer, perf_pass); 14047ec681f3Smrg if (result != VK_SUCCESS) 14057ec681f3Smrg goto out; 14067ec681f3Smrg } 14077ec681f3Smrg 14087ec681f3Smrg /* Signal semaphores */ 14097ec681f3Smrg for (uint32_t j = 0; j < pSubmits[i].signalSemaphoreInfoCount; j++) { 14107ec681f3Smrg result = anv_queue_submit_add_out_semaphore(queue, submit, 14117ec681f3Smrg pSubmits[i].pSignalSemaphoreInfos[j].semaphore, 14127ec681f3Smrg pSubmits[i].pSignalSemaphoreInfos[j].value); 14137ec681f3Smrg if (result != VK_SUCCESS) 14147ec681f3Smrg goto out; 14157ec681f3Smrg } 141601e04c3fSmrg 14177ec681f3Smrg /* WSI BO */ 14187ec681f3Smrg if (wsi_signal_bo) { 14197ec681f3Smrg result = anv_queue_submit_add_fence_bo(queue, submit, wsi_signal_bo, 14207ec681f3Smrg true /* signal */); 142101e04c3fSmrg if (result != VK_SUCCESS) 142201e04c3fSmrg goto out; 142301e04c3fSmrg } 142401e04c3fSmrg } 142501e04c3fSmrg 14267ec681f3Smrg if (fence) { 14277ec681f3Smrg result = anv_queue_submit_add_fence(queue, submit, fence); 14287ec681f3Smrg if (result != VK_SUCCESS) 14297ec681f3Smrg goto out; 14307ec681f3Smrg } 14317ec681f3Smrg 14327ec681f3Smrg result = anv_queue_submit_post(queue, &submit, false); 14337ec681f3Smrg if (result != VK_SUCCESS) 14347ec681f3Smrg goto out; 14357ec681f3Smrg 14367ec681f3Smrg if (fence) 14377ec681f3Smrg anv_post_queue_fence_update(device, fence); 143801e04c3fSmrg 143901e04c3fSmrgout: 14407ec681f3Smrg if (submit) 14417ec681f3Smrg anv_queue_submit_free(device, submit); 14427ec681f3Smrg 14437ec681f3Smrg if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) { 144401e04c3fSmrg /* In the case that something has gone wrong we may end up with an 144501e04c3fSmrg * inconsistent state from which it may not be trivial to recover. 144601e04c3fSmrg * For example, we might have computed address relocations and 144701e04c3fSmrg * any future attempt to re-submit this job will need to know about 144801e04c3fSmrg * this and avoid computing relocation addresses again. 144901e04c3fSmrg * 145001e04c3fSmrg * To avoid this sort of issues, we assume that if something was 145101e04c3fSmrg * wrong during submission we must already be in a really bad situation 145201e04c3fSmrg * anyway (such us being out of memory) and return 145301e04c3fSmrg * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to 145401e04c3fSmrg * submit the same job again to this device. 14557ec681f3Smrg * 14567ec681f3Smrg * We skip doing this on VK_ERROR_DEVICE_LOST because 14577ec681f3Smrg * anv_device_set_lost() would have been called already by a callee of 14587ec681f3Smrg * anv_queue_submit(). 145901e04c3fSmrg */ 14607ec681f3Smrg result = anv_device_set_lost(device, "vkQueueSubmit2KHR() failed"); 146101e04c3fSmrg } 146201e04c3fSmrg 146301e04c3fSmrg return result; 146401e04c3fSmrg} 146501e04c3fSmrg 146601e04c3fSmrgVkResult anv_QueueWaitIdle( 146701e04c3fSmrg VkQueue _queue) 146801e04c3fSmrg{ 146901e04c3fSmrg ANV_FROM_HANDLE(anv_queue, queue, _queue); 147001e04c3fSmrg 14717ec681f3Smrg if (anv_device_is_lost(queue->device)) 14727ec681f3Smrg return VK_ERROR_DEVICE_LOST; 14737ec681f3Smrg 14747ec681f3Smrg return anv_queue_submit_simple_batch(queue, NULL); 147501e04c3fSmrg} 147601e04c3fSmrg 147701e04c3fSmrgVkResult anv_CreateFence( 147801e04c3fSmrg VkDevice _device, 147901e04c3fSmrg const VkFenceCreateInfo* pCreateInfo, 148001e04c3fSmrg const VkAllocationCallbacks* pAllocator, 148101e04c3fSmrg VkFence* pFence) 148201e04c3fSmrg{ 148301e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 148401e04c3fSmrg struct anv_fence *fence; 148501e04c3fSmrg 148601e04c3fSmrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO); 148701e04c3fSmrg 14887ec681f3Smrg fence = vk_object_zalloc(&device->vk, pAllocator, sizeof(*fence), 14897ec681f3Smrg VK_OBJECT_TYPE_FENCE); 149001e04c3fSmrg if (fence == NULL) 14917ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 149201e04c3fSmrg 14937ec681f3Smrg if (device->physical->has_syncobj_wait) { 149401e04c3fSmrg fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ; 149501e04c3fSmrg 149601e04c3fSmrg uint32_t create_flags = 0; 149701e04c3fSmrg if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) 149801e04c3fSmrg create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 149901e04c3fSmrg 150001e04c3fSmrg fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags); 150101e04c3fSmrg if (!fence->permanent.syncobj) 15027ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 150301e04c3fSmrg } else { 150401e04c3fSmrg fence->permanent.type = ANV_FENCE_TYPE_BO; 150501e04c3fSmrg 15067ec681f3Smrg VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096, 15077ec681f3Smrg &fence->permanent.bo.bo); 150801e04c3fSmrg if (result != VK_SUCCESS) 150901e04c3fSmrg return result; 151001e04c3fSmrg 151101e04c3fSmrg if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) { 151201e04c3fSmrg fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED; 151301e04c3fSmrg } else { 151401e04c3fSmrg fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET; 151501e04c3fSmrg } 151601e04c3fSmrg } 151701e04c3fSmrg 151801e04c3fSmrg *pFence = anv_fence_to_handle(fence); 151901e04c3fSmrg 152001e04c3fSmrg return VK_SUCCESS; 152101e04c3fSmrg} 152201e04c3fSmrg 152301e04c3fSmrgstatic void 152401e04c3fSmrganv_fence_impl_cleanup(struct anv_device *device, 152501e04c3fSmrg struct anv_fence_impl *impl) 152601e04c3fSmrg{ 152701e04c3fSmrg switch (impl->type) { 152801e04c3fSmrg case ANV_FENCE_TYPE_NONE: 152901e04c3fSmrg /* Dummy. Nothing to do */ 153001e04c3fSmrg break; 153101e04c3fSmrg 153201e04c3fSmrg case ANV_FENCE_TYPE_BO: 15337ec681f3Smrg anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo); 15347ec681f3Smrg break; 15357ec681f3Smrg 15367ec681f3Smrg case ANV_FENCE_TYPE_WSI_BO: 15377ec681f3Smrg anv_device_release_bo(device, impl->bo.bo); 153801e04c3fSmrg break; 153901e04c3fSmrg 154001e04c3fSmrg case ANV_FENCE_TYPE_SYNCOBJ: 154101e04c3fSmrg anv_gem_syncobj_destroy(device, impl->syncobj); 154201e04c3fSmrg break; 154301e04c3fSmrg 154401e04c3fSmrg case ANV_FENCE_TYPE_WSI: 154501e04c3fSmrg impl->fence_wsi->destroy(impl->fence_wsi); 154601e04c3fSmrg break; 154701e04c3fSmrg 154801e04c3fSmrg default: 154901e04c3fSmrg unreachable("Invalid fence type"); 155001e04c3fSmrg } 155101e04c3fSmrg 155201e04c3fSmrg impl->type = ANV_FENCE_TYPE_NONE; 155301e04c3fSmrg} 155401e04c3fSmrg 15557ec681f3Smrgvoid 15567ec681f3Smrganv_fence_reset_temporary(struct anv_device *device, 15577ec681f3Smrg struct anv_fence *fence) 15587ec681f3Smrg{ 15597ec681f3Smrg if (fence->temporary.type == ANV_FENCE_TYPE_NONE) 15607ec681f3Smrg return; 15617ec681f3Smrg 15627ec681f3Smrg anv_fence_impl_cleanup(device, &fence->temporary); 15637ec681f3Smrg} 15647ec681f3Smrg 156501e04c3fSmrgvoid anv_DestroyFence( 156601e04c3fSmrg VkDevice _device, 156701e04c3fSmrg VkFence _fence, 156801e04c3fSmrg const VkAllocationCallbacks* pAllocator) 156901e04c3fSmrg{ 157001e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 157101e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, _fence); 157201e04c3fSmrg 157301e04c3fSmrg if (!fence) 157401e04c3fSmrg return; 157501e04c3fSmrg 157601e04c3fSmrg anv_fence_impl_cleanup(device, &fence->temporary); 157701e04c3fSmrg anv_fence_impl_cleanup(device, &fence->permanent); 157801e04c3fSmrg 15797ec681f3Smrg vk_object_free(&device->vk, pAllocator, fence); 158001e04c3fSmrg} 158101e04c3fSmrg 158201e04c3fSmrgVkResult anv_ResetFences( 158301e04c3fSmrg VkDevice _device, 158401e04c3fSmrg uint32_t fenceCount, 158501e04c3fSmrg const VkFence* pFences) 158601e04c3fSmrg{ 158701e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 158801e04c3fSmrg 158901e04c3fSmrg for (uint32_t i = 0; i < fenceCount; i++) { 159001e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 159101e04c3fSmrg 159201e04c3fSmrg /* From the Vulkan 1.0.53 spec: 159301e04c3fSmrg * 159401e04c3fSmrg * "If any member of pFences currently has its payload imported with 159501e04c3fSmrg * temporary permanence, that fence’s prior permanent payload is 159601e04c3fSmrg * first restored. The remaining operations described therefore 159701e04c3fSmrg * operate on the restored payload. 159801e04c3fSmrg */ 15997ec681f3Smrg anv_fence_reset_temporary(device, fence); 160001e04c3fSmrg 160101e04c3fSmrg struct anv_fence_impl *impl = &fence->permanent; 160201e04c3fSmrg 160301e04c3fSmrg switch (impl->type) { 160401e04c3fSmrg case ANV_FENCE_TYPE_BO: 160501e04c3fSmrg impl->bo.state = ANV_BO_FENCE_STATE_RESET; 160601e04c3fSmrg break; 160701e04c3fSmrg 160801e04c3fSmrg case ANV_FENCE_TYPE_SYNCOBJ: 160901e04c3fSmrg anv_gem_syncobj_reset(device, impl->syncobj); 161001e04c3fSmrg break; 161101e04c3fSmrg 161201e04c3fSmrg default: 161301e04c3fSmrg unreachable("Invalid fence type"); 161401e04c3fSmrg } 161501e04c3fSmrg } 161601e04c3fSmrg 161701e04c3fSmrg return VK_SUCCESS; 161801e04c3fSmrg} 161901e04c3fSmrg 162001e04c3fSmrgVkResult anv_GetFenceStatus( 162101e04c3fSmrg VkDevice _device, 162201e04c3fSmrg VkFence _fence) 162301e04c3fSmrg{ 162401e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 162501e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, _fence); 162601e04c3fSmrg 162701e04c3fSmrg if (anv_device_is_lost(device)) 162801e04c3fSmrg return VK_ERROR_DEVICE_LOST; 162901e04c3fSmrg 163001e04c3fSmrg struct anv_fence_impl *impl = 163101e04c3fSmrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 163201e04c3fSmrg &fence->temporary : &fence->permanent; 163301e04c3fSmrg 163401e04c3fSmrg switch (impl->type) { 163501e04c3fSmrg case ANV_FENCE_TYPE_BO: 16367ec681f3Smrg case ANV_FENCE_TYPE_WSI_BO: 163701e04c3fSmrg switch (impl->bo.state) { 163801e04c3fSmrg case ANV_BO_FENCE_STATE_RESET: 163901e04c3fSmrg /* If it hasn't even been sent off to the GPU yet, it's not ready */ 164001e04c3fSmrg return VK_NOT_READY; 164101e04c3fSmrg 164201e04c3fSmrg case ANV_BO_FENCE_STATE_SIGNALED: 164301e04c3fSmrg /* It's been signaled, return success */ 164401e04c3fSmrg return VK_SUCCESS; 164501e04c3fSmrg 164601e04c3fSmrg case ANV_BO_FENCE_STATE_SUBMITTED: { 16477ec681f3Smrg VkResult result = anv_device_bo_busy(device, impl->bo.bo); 164801e04c3fSmrg if (result == VK_SUCCESS) { 164901e04c3fSmrg impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED; 165001e04c3fSmrg return VK_SUCCESS; 165101e04c3fSmrg } else { 165201e04c3fSmrg return result; 165301e04c3fSmrg } 165401e04c3fSmrg } 165501e04c3fSmrg default: 165601e04c3fSmrg unreachable("Invalid fence status"); 165701e04c3fSmrg } 165801e04c3fSmrg 165901e04c3fSmrg case ANV_FENCE_TYPE_SYNCOBJ: { 16607ec681f3Smrg if (device->has_thread_submit) { 16617ec681f3Smrg uint64_t binary_value = 0; 16627ec681f3Smrg int ret = anv_gem_syncobj_timeline_wait(device, &impl->syncobj, 16637ec681f3Smrg &binary_value, 1, 0, 16647ec681f3Smrg true /* wait_all */, 16657ec681f3Smrg false /* wait_materialize */); 16667ec681f3Smrg if (ret == -1) { 16677ec681f3Smrg if (errno == ETIME) { 16687ec681f3Smrg return VK_NOT_READY; 16697ec681f3Smrg } else { 16707ec681f3Smrg /* We don't know the real error. */ 16717ec681f3Smrg return anv_device_set_lost(device, "drm_syncobj_wait failed: %m"); 16727ec681f3Smrg } 167301e04c3fSmrg } else { 16747ec681f3Smrg return VK_SUCCESS; 167501e04c3fSmrg } 167601e04c3fSmrg } else { 16777ec681f3Smrg int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, false); 16787ec681f3Smrg if (ret == -1) { 16797ec681f3Smrg if (errno == ETIME) { 16807ec681f3Smrg return VK_NOT_READY; 16817ec681f3Smrg } else { 16827ec681f3Smrg /* We don't know the real error. */ 16837ec681f3Smrg return anv_device_set_lost(device, "drm_syncobj_wait failed: %m"); 16847ec681f3Smrg } 16857ec681f3Smrg } else { 16867ec681f3Smrg return VK_SUCCESS; 16877ec681f3Smrg } 16887ec681f3Smrg } 16897ec681f3Smrg } 169001e04c3fSmrg 16917ec681f3Smrg default: 16927ec681f3Smrg unreachable("Invalid fence type"); 16937ec681f3Smrg } 169401e04c3fSmrg} 169501e04c3fSmrg 169601e04c3fSmrgstatic VkResult 169701e04c3fSmrganv_wait_for_syncobj_fences(struct anv_device *device, 169801e04c3fSmrg uint32_t fenceCount, 169901e04c3fSmrg const VkFence *pFences, 170001e04c3fSmrg bool waitAll, 170101e04c3fSmrg uint64_t abs_timeout_ns) 170201e04c3fSmrg{ 17037ec681f3Smrg uint32_t *syncobjs = vk_zalloc(&device->vk.alloc, 170401e04c3fSmrg sizeof(*syncobjs) * fenceCount, 8, 170501e04c3fSmrg VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 170601e04c3fSmrg if (!syncobjs) 17077ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 170801e04c3fSmrg 170901e04c3fSmrg for (uint32_t i = 0; i < fenceCount; i++) { 171001e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 171101e04c3fSmrg assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ); 171201e04c3fSmrg 171301e04c3fSmrg struct anv_fence_impl *impl = 171401e04c3fSmrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 171501e04c3fSmrg &fence->temporary : &fence->permanent; 171601e04c3fSmrg 171701e04c3fSmrg assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ); 171801e04c3fSmrg syncobjs[i] = impl->syncobj; 171901e04c3fSmrg } 172001e04c3fSmrg 17217ec681f3Smrg int ret = 0; 172201e04c3fSmrg /* The gem_syncobj_wait ioctl may return early due to an inherent 17237ec681f3Smrg * limitation in the way it computes timeouts. Loop until we've actually 172401e04c3fSmrg * passed the timeout. 172501e04c3fSmrg */ 172601e04c3fSmrg do { 172701e04c3fSmrg ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount, 172801e04c3fSmrg abs_timeout_ns, waitAll); 17297ec681f3Smrg } while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns); 173001e04c3fSmrg 17317ec681f3Smrg vk_free(&device->vk.alloc, syncobjs); 173201e04c3fSmrg 173301e04c3fSmrg if (ret == -1) { 173401e04c3fSmrg if (errno == ETIME) { 173501e04c3fSmrg return VK_TIMEOUT; 173601e04c3fSmrg } else { 173701e04c3fSmrg /* We don't know the real error. */ 173801e04c3fSmrg return anv_device_set_lost(device, "drm_syncobj_wait failed: %m"); 173901e04c3fSmrg } 174001e04c3fSmrg } else { 174101e04c3fSmrg return VK_SUCCESS; 174201e04c3fSmrg } 174301e04c3fSmrg} 174401e04c3fSmrg 174501e04c3fSmrgstatic VkResult 174601e04c3fSmrganv_wait_for_bo_fences(struct anv_device *device, 174701e04c3fSmrg uint32_t fenceCount, 174801e04c3fSmrg const VkFence *pFences, 174901e04c3fSmrg bool waitAll, 175001e04c3fSmrg uint64_t abs_timeout_ns) 175101e04c3fSmrg{ 175201e04c3fSmrg VkResult result = VK_SUCCESS; 175301e04c3fSmrg uint32_t pending_fences = fenceCount; 175401e04c3fSmrg while (pending_fences) { 175501e04c3fSmrg pending_fences = 0; 175601e04c3fSmrg bool signaled_fences = false; 175701e04c3fSmrg for (uint32_t i = 0; i < fenceCount; i++) { 175801e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 175901e04c3fSmrg 17607ec681f3Smrg struct anv_fence_impl *impl = 17617ec681f3Smrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 17627ec681f3Smrg &fence->temporary : &fence->permanent; 17637ec681f3Smrg assert(impl->type == ANV_FENCE_TYPE_BO || 17647ec681f3Smrg impl->type == ANV_FENCE_TYPE_WSI_BO); 176501e04c3fSmrg 176601e04c3fSmrg switch (impl->bo.state) { 176701e04c3fSmrg case ANV_BO_FENCE_STATE_RESET: 176801e04c3fSmrg /* This fence hasn't been submitted yet, we'll catch it the next 176901e04c3fSmrg * time around. Yes, this may mean we dead-loop but, short of 177001e04c3fSmrg * lots of locking and a condition variable, there's not much that 177101e04c3fSmrg * we can do about that. 177201e04c3fSmrg */ 177301e04c3fSmrg pending_fences++; 177401e04c3fSmrg continue; 177501e04c3fSmrg 177601e04c3fSmrg case ANV_BO_FENCE_STATE_SIGNALED: 177701e04c3fSmrg /* This fence is not pending. If waitAll isn't set, we can return 177801e04c3fSmrg * early. Otherwise, we have to keep going. 177901e04c3fSmrg */ 178001e04c3fSmrg if (!waitAll) { 178101e04c3fSmrg result = VK_SUCCESS; 178201e04c3fSmrg goto done; 178301e04c3fSmrg } 178401e04c3fSmrg continue; 178501e04c3fSmrg 178601e04c3fSmrg case ANV_BO_FENCE_STATE_SUBMITTED: 178701e04c3fSmrg /* These are the fences we really care about. Go ahead and wait 178801e04c3fSmrg * on it until we hit a timeout. 178901e04c3fSmrg */ 17907ec681f3Smrg result = anv_device_wait(device, impl->bo.bo, 179101e04c3fSmrg anv_get_relative_timeout(abs_timeout_ns)); 179201e04c3fSmrg switch (result) { 179301e04c3fSmrg case VK_SUCCESS: 179401e04c3fSmrg impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED; 179501e04c3fSmrg signaled_fences = true; 179601e04c3fSmrg if (!waitAll) 179701e04c3fSmrg goto done; 179801e04c3fSmrg break; 179901e04c3fSmrg 180001e04c3fSmrg case VK_TIMEOUT: 180101e04c3fSmrg goto done; 180201e04c3fSmrg 180301e04c3fSmrg default: 180401e04c3fSmrg return result; 180501e04c3fSmrg } 180601e04c3fSmrg } 180701e04c3fSmrg } 180801e04c3fSmrg 180901e04c3fSmrg if (pending_fences && !signaled_fences) { 181001e04c3fSmrg /* If we've hit this then someone decided to vkWaitForFences before 181101e04c3fSmrg * they've actually submitted any of them to a queue. This is a 181201e04c3fSmrg * fairly pessimal case, so it's ok to lock here and use a standard 181301e04c3fSmrg * pthreads condition variable. 181401e04c3fSmrg */ 181501e04c3fSmrg pthread_mutex_lock(&device->mutex); 181601e04c3fSmrg 181701e04c3fSmrg /* It's possible that some of the fences have changed state since the 181801e04c3fSmrg * last time we checked. Now that we have the lock, check for 181901e04c3fSmrg * pending fences again and don't wait if it's changed. 182001e04c3fSmrg */ 182101e04c3fSmrg uint32_t now_pending_fences = 0; 182201e04c3fSmrg for (uint32_t i = 0; i < fenceCount; i++) { 182301e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 182401e04c3fSmrg if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET) 182501e04c3fSmrg now_pending_fences++; 182601e04c3fSmrg } 182701e04c3fSmrg assert(now_pending_fences <= pending_fences); 182801e04c3fSmrg 182901e04c3fSmrg if (now_pending_fences == pending_fences) { 183001e04c3fSmrg struct timespec abstime = { 183101e04c3fSmrg .tv_sec = abs_timeout_ns / NSEC_PER_SEC, 183201e04c3fSmrg .tv_nsec = abs_timeout_ns % NSEC_PER_SEC, 183301e04c3fSmrg }; 183401e04c3fSmrg 18357ec681f3Smrg ASSERTED int ret; 183601e04c3fSmrg ret = pthread_cond_timedwait(&device->queue_submit, 183701e04c3fSmrg &device->mutex, &abstime); 183801e04c3fSmrg assert(ret != EINVAL); 18397ec681f3Smrg if (anv_gettime_ns() >= abs_timeout_ns) { 184001e04c3fSmrg pthread_mutex_unlock(&device->mutex); 184101e04c3fSmrg result = VK_TIMEOUT; 184201e04c3fSmrg goto done; 184301e04c3fSmrg } 184401e04c3fSmrg } 184501e04c3fSmrg 184601e04c3fSmrg pthread_mutex_unlock(&device->mutex); 184701e04c3fSmrg } 184801e04c3fSmrg } 184901e04c3fSmrg 185001e04c3fSmrgdone: 185101e04c3fSmrg if (anv_device_is_lost(device)) 185201e04c3fSmrg return VK_ERROR_DEVICE_LOST; 185301e04c3fSmrg 185401e04c3fSmrg return result; 185501e04c3fSmrg} 185601e04c3fSmrg 185701e04c3fSmrgstatic VkResult 185801e04c3fSmrganv_wait_for_wsi_fence(struct anv_device *device, 18597ec681f3Smrg struct anv_fence_impl *impl, 186001e04c3fSmrg uint64_t abs_timeout) 186101e04c3fSmrg{ 186201e04c3fSmrg return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout); 186301e04c3fSmrg} 186401e04c3fSmrg 186501e04c3fSmrgstatic VkResult 186601e04c3fSmrganv_wait_for_fences(struct anv_device *device, 186701e04c3fSmrg uint32_t fenceCount, 186801e04c3fSmrg const VkFence *pFences, 186901e04c3fSmrg bool waitAll, 187001e04c3fSmrg uint64_t abs_timeout) 187101e04c3fSmrg{ 187201e04c3fSmrg VkResult result = VK_SUCCESS; 187301e04c3fSmrg 187401e04c3fSmrg if (fenceCount <= 1 || waitAll) { 187501e04c3fSmrg for (uint32_t i = 0; i < fenceCount; i++) { 187601e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 18777ec681f3Smrg struct anv_fence_impl *impl = 18787ec681f3Smrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 18797ec681f3Smrg &fence->temporary : &fence->permanent; 18807ec681f3Smrg 18817ec681f3Smrg switch (impl->type) { 188201e04c3fSmrg case ANV_FENCE_TYPE_BO: 18837ec681f3Smrg assert(!device->physical->has_syncobj_wait); 18847ec681f3Smrg FALLTHROUGH; 18857ec681f3Smrg case ANV_FENCE_TYPE_WSI_BO: 188601e04c3fSmrg result = anv_wait_for_bo_fences(device, 1, &pFences[i], 188701e04c3fSmrg true, abs_timeout); 188801e04c3fSmrg break; 188901e04c3fSmrg case ANV_FENCE_TYPE_SYNCOBJ: 189001e04c3fSmrg result = anv_wait_for_syncobj_fences(device, 1, &pFences[i], 189101e04c3fSmrg true, abs_timeout); 189201e04c3fSmrg break; 189301e04c3fSmrg case ANV_FENCE_TYPE_WSI: 18947ec681f3Smrg result = anv_wait_for_wsi_fence(device, impl, abs_timeout); 189501e04c3fSmrg break; 189601e04c3fSmrg case ANV_FENCE_TYPE_NONE: 189701e04c3fSmrg result = VK_SUCCESS; 189801e04c3fSmrg break; 189901e04c3fSmrg } 190001e04c3fSmrg if (result != VK_SUCCESS) 190101e04c3fSmrg return result; 190201e04c3fSmrg } 190301e04c3fSmrg } else { 190401e04c3fSmrg do { 190501e04c3fSmrg for (uint32_t i = 0; i < fenceCount; i++) { 190601e04c3fSmrg if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS) 190701e04c3fSmrg return VK_SUCCESS; 190801e04c3fSmrg } 19097ec681f3Smrg } while (anv_gettime_ns() < abs_timeout); 191001e04c3fSmrg result = VK_TIMEOUT; 191101e04c3fSmrg } 191201e04c3fSmrg return result; 191301e04c3fSmrg} 191401e04c3fSmrg 191501e04c3fSmrgstatic bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences) 191601e04c3fSmrg{ 191701e04c3fSmrg for (uint32_t i = 0; i < fenceCount; ++i) { 191801e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 19197ec681f3Smrg struct anv_fence_impl *impl = 19207ec681f3Smrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 19217ec681f3Smrg &fence->temporary : &fence->permanent; 19227ec681f3Smrg if (impl->type != ANV_FENCE_TYPE_SYNCOBJ) 192301e04c3fSmrg return false; 192401e04c3fSmrg } 192501e04c3fSmrg return true; 192601e04c3fSmrg} 192701e04c3fSmrg 192801e04c3fSmrgstatic bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences) 192901e04c3fSmrg{ 193001e04c3fSmrg for (uint32_t i = 0; i < fenceCount; ++i) { 193101e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); 19327ec681f3Smrg struct anv_fence_impl *impl = 19337ec681f3Smrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 19347ec681f3Smrg &fence->temporary : &fence->permanent; 19357ec681f3Smrg if (impl->type != ANV_FENCE_TYPE_BO && 19367ec681f3Smrg impl->type != ANV_FENCE_TYPE_WSI_BO) 193701e04c3fSmrg return false; 193801e04c3fSmrg } 193901e04c3fSmrg return true; 194001e04c3fSmrg} 194101e04c3fSmrg 194201e04c3fSmrgVkResult anv_WaitForFences( 194301e04c3fSmrg VkDevice _device, 194401e04c3fSmrg uint32_t fenceCount, 194501e04c3fSmrg const VkFence* pFences, 194601e04c3fSmrg VkBool32 waitAll, 194701e04c3fSmrg uint64_t timeout) 194801e04c3fSmrg{ 194901e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 195001e04c3fSmrg 19517ec681f3Smrg if (device->info.no_hw) 19527ec681f3Smrg return VK_SUCCESS; 19537ec681f3Smrg 195401e04c3fSmrg if (anv_device_is_lost(device)) 195501e04c3fSmrg return VK_ERROR_DEVICE_LOST; 195601e04c3fSmrg 195701e04c3fSmrg uint64_t abs_timeout = anv_get_absolute_timeout(timeout); 195801e04c3fSmrg if (anv_all_fences_syncobj(fenceCount, pFences)) { 195901e04c3fSmrg return anv_wait_for_syncobj_fences(device, fenceCount, pFences, 196001e04c3fSmrg waitAll, abs_timeout); 196101e04c3fSmrg } else if (anv_all_fences_bo(fenceCount, pFences)) { 196201e04c3fSmrg return anv_wait_for_bo_fences(device, fenceCount, pFences, 196301e04c3fSmrg waitAll, abs_timeout); 196401e04c3fSmrg } else { 196501e04c3fSmrg return anv_wait_for_fences(device, fenceCount, pFences, 196601e04c3fSmrg waitAll, abs_timeout); 196701e04c3fSmrg } 196801e04c3fSmrg} 196901e04c3fSmrg 197001e04c3fSmrgvoid anv_GetPhysicalDeviceExternalFenceProperties( 197101e04c3fSmrg VkPhysicalDevice physicalDevice, 19729f464c52Smaya const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, 19739f464c52Smaya VkExternalFenceProperties* pExternalFenceProperties) 197401e04c3fSmrg{ 197501e04c3fSmrg ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 197601e04c3fSmrg 197701e04c3fSmrg switch (pExternalFenceInfo->handleType) { 197801e04c3fSmrg case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: 197901e04c3fSmrg case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: 198001e04c3fSmrg if (device->has_syncobj_wait) { 198101e04c3fSmrg pExternalFenceProperties->exportFromImportedHandleTypes = 198201e04c3fSmrg VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT | 198301e04c3fSmrg VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; 198401e04c3fSmrg pExternalFenceProperties->compatibleHandleTypes = 198501e04c3fSmrg VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT | 198601e04c3fSmrg VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; 198701e04c3fSmrg pExternalFenceProperties->externalFenceFeatures = 198801e04c3fSmrg VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT | 198901e04c3fSmrg VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT; 199001e04c3fSmrg return; 199101e04c3fSmrg } 199201e04c3fSmrg break; 199301e04c3fSmrg 199401e04c3fSmrg default: 199501e04c3fSmrg break; 199601e04c3fSmrg } 199701e04c3fSmrg 199801e04c3fSmrg pExternalFenceProperties->exportFromImportedHandleTypes = 0; 199901e04c3fSmrg pExternalFenceProperties->compatibleHandleTypes = 0; 200001e04c3fSmrg pExternalFenceProperties->externalFenceFeatures = 0; 200101e04c3fSmrg} 200201e04c3fSmrg 200301e04c3fSmrgVkResult anv_ImportFenceFdKHR( 200401e04c3fSmrg VkDevice _device, 200501e04c3fSmrg const VkImportFenceFdInfoKHR* pImportFenceFdInfo) 200601e04c3fSmrg{ 200701e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 200801e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence); 200901e04c3fSmrg int fd = pImportFenceFdInfo->fd; 201001e04c3fSmrg 201101e04c3fSmrg assert(pImportFenceFdInfo->sType == 201201e04c3fSmrg VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR); 201301e04c3fSmrg 201401e04c3fSmrg struct anv_fence_impl new_impl = { 201501e04c3fSmrg .type = ANV_FENCE_TYPE_NONE, 201601e04c3fSmrg }; 201701e04c3fSmrg 201801e04c3fSmrg switch (pImportFenceFdInfo->handleType) { 201901e04c3fSmrg case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: 202001e04c3fSmrg new_impl.type = ANV_FENCE_TYPE_SYNCOBJ; 202101e04c3fSmrg 202201e04c3fSmrg new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd); 202301e04c3fSmrg if (!new_impl.syncobj) 20247ec681f3Smrg return vk_error(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE); 202501e04c3fSmrg 202601e04c3fSmrg break; 202701e04c3fSmrg 20287ec681f3Smrg case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: { 202901e04c3fSmrg /* Sync files are a bit tricky. Because we want to continue using the 203001e04c3fSmrg * syncobj implementation of WaitForFences, we don't use the sync file 203101e04c3fSmrg * directly but instead import it into a syncobj. 203201e04c3fSmrg */ 203301e04c3fSmrg new_impl.type = ANV_FENCE_TYPE_SYNCOBJ; 203401e04c3fSmrg 20357ec681f3Smrg /* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the 20367ec681f3Smrg * special value -1 for fd is treated like a valid sync file descriptor 20377ec681f3Smrg * referring to an object that has already signaled. The import 20387ec681f3Smrg * operation will succeed and the VkFence will have a temporarily 20397ec681f3Smrg * imported payload as if a valid file descriptor had been provided." 20407ec681f3Smrg */ 20417ec681f3Smrg uint32_t create_flags = 0; 20427ec681f3Smrg if (fd == -1) 20437ec681f3Smrg create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 20447ec681f3Smrg 20457ec681f3Smrg new_impl.syncobj = anv_gem_syncobj_create(device, create_flags); 204601e04c3fSmrg if (!new_impl.syncobj) 20477ec681f3Smrg return vk_error(fence, VK_ERROR_OUT_OF_HOST_MEMORY); 204801e04c3fSmrg 20497ec681f3Smrg if (fd != -1 && 20507ec681f3Smrg anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) { 205101e04c3fSmrg anv_gem_syncobj_destroy(device, new_impl.syncobj); 20527ec681f3Smrg return vk_errorf(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE, 205301e04c3fSmrg "syncobj sync file import failed: %m"); 205401e04c3fSmrg } 205501e04c3fSmrg break; 20567ec681f3Smrg } 205701e04c3fSmrg 205801e04c3fSmrg default: 20597ec681f3Smrg return vk_error(fence, VK_ERROR_INVALID_EXTERNAL_HANDLE); 206001e04c3fSmrg } 206101e04c3fSmrg 206201e04c3fSmrg /* From the Vulkan 1.0.53 spec: 206301e04c3fSmrg * 206401e04c3fSmrg * "Importing a fence payload from a file descriptor transfers 206501e04c3fSmrg * ownership of the file descriptor from the application to the 206601e04c3fSmrg * Vulkan implementation. The application must not perform any 206701e04c3fSmrg * operations on the file descriptor after a successful import." 206801e04c3fSmrg * 206901e04c3fSmrg * If the import fails, we leave the file descriptor open. 207001e04c3fSmrg */ 20717ec681f3Smrg if (fd != -1) 20727ec681f3Smrg close(fd); 207301e04c3fSmrg 207401e04c3fSmrg if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) { 207501e04c3fSmrg anv_fence_impl_cleanup(device, &fence->temporary); 207601e04c3fSmrg fence->temporary = new_impl; 207701e04c3fSmrg } else { 207801e04c3fSmrg anv_fence_impl_cleanup(device, &fence->permanent); 207901e04c3fSmrg fence->permanent = new_impl; 208001e04c3fSmrg } 208101e04c3fSmrg 208201e04c3fSmrg return VK_SUCCESS; 208301e04c3fSmrg} 208401e04c3fSmrg 20857ec681f3Smrg/* The sideband payload of the DRM syncobj was incremented when the 20867ec681f3Smrg * application called vkQueueSubmit(). Here we wait for a fence with the same 20877ec681f3Smrg * value to materialize so that we can exporting (typically as a SyncFD). 20887ec681f3Smrg */ 20897ec681f3Smrgstatic VkResult 20907ec681f3Smrgwait_syncobj_materialize(struct anv_device *device, 20917ec681f3Smrg uint32_t syncobj, 20927ec681f3Smrg int *fd) 20937ec681f3Smrg{ 20947ec681f3Smrg if (!device->has_thread_submit) 20957ec681f3Smrg return VK_SUCCESS; 20967ec681f3Smrg 20977ec681f3Smrg uint64_t binary_value = 0; 20987ec681f3Smrg /* We might need to wait until the fence materializes before we can 20997ec681f3Smrg * export to a sync FD when we use a thread for submission. 21007ec681f3Smrg */ 21017ec681f3Smrg if (anv_gem_syncobj_timeline_wait(device, &syncobj, &binary_value, 1, 21027ec681f3Smrg anv_get_absolute_timeout(5ull * NSEC_PER_SEC), 21037ec681f3Smrg true /* wait_all */, 21047ec681f3Smrg true /* wait_materialize */)) 21057ec681f3Smrg return anv_device_set_lost(device, "anv_gem_syncobj_timeline_wait failed: %m"); 21067ec681f3Smrg 21077ec681f3Smrg return VK_SUCCESS; 21087ec681f3Smrg} 21097ec681f3Smrg 211001e04c3fSmrgVkResult anv_GetFenceFdKHR( 211101e04c3fSmrg VkDevice _device, 211201e04c3fSmrg const VkFenceGetFdInfoKHR* pGetFdInfo, 211301e04c3fSmrg int* pFd) 211401e04c3fSmrg{ 211501e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 211601e04c3fSmrg ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence); 211701e04c3fSmrg 211801e04c3fSmrg assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR); 211901e04c3fSmrg 212001e04c3fSmrg struct anv_fence_impl *impl = 212101e04c3fSmrg fence->temporary.type != ANV_FENCE_TYPE_NONE ? 212201e04c3fSmrg &fence->temporary : &fence->permanent; 212301e04c3fSmrg 212401e04c3fSmrg assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ); 212501e04c3fSmrg switch (pGetFdInfo->handleType) { 212601e04c3fSmrg case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: { 212701e04c3fSmrg int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); 212801e04c3fSmrg if (fd < 0) 21297ec681f3Smrg return vk_error(fence, VK_ERROR_TOO_MANY_OBJECTS); 213001e04c3fSmrg 213101e04c3fSmrg *pFd = fd; 213201e04c3fSmrg break; 213301e04c3fSmrg } 213401e04c3fSmrg 213501e04c3fSmrg case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: { 21367ec681f3Smrg VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd); 21377ec681f3Smrg if (result != VK_SUCCESS) 21387ec681f3Smrg return result; 21397ec681f3Smrg 214001e04c3fSmrg int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj); 214101e04c3fSmrg if (fd < 0) 21427ec681f3Smrg return vk_error(fence, VK_ERROR_TOO_MANY_OBJECTS); 214301e04c3fSmrg 214401e04c3fSmrg *pFd = fd; 214501e04c3fSmrg break; 214601e04c3fSmrg } 214701e04c3fSmrg 214801e04c3fSmrg default: 214901e04c3fSmrg unreachable("Invalid fence export handle type"); 215001e04c3fSmrg } 215101e04c3fSmrg 215201e04c3fSmrg /* From the Vulkan 1.0.53 spec: 215301e04c3fSmrg * 215401e04c3fSmrg * "Export operations have the same transference as the specified handle 215501e04c3fSmrg * type’s import operations. [...] If the fence was using a 215601e04c3fSmrg * temporarily imported payload, the fence’s prior permanent payload 215701e04c3fSmrg * will be restored. 215801e04c3fSmrg */ 215901e04c3fSmrg if (impl == &fence->temporary) 216001e04c3fSmrg anv_fence_impl_cleanup(device, impl); 216101e04c3fSmrg 216201e04c3fSmrg return VK_SUCCESS; 216301e04c3fSmrg} 216401e04c3fSmrg 216501e04c3fSmrg// Queue semaphore functions 216601e04c3fSmrg 21677ec681f3Smrgstatic VkSemaphoreTypeKHR 21687ec681f3Smrgget_semaphore_type(const void *pNext, uint64_t *initial_value) 21697ec681f3Smrg{ 21707ec681f3Smrg const VkSemaphoreTypeCreateInfoKHR *type_info = 21717ec681f3Smrg vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR); 21727ec681f3Smrg 21737ec681f3Smrg if (!type_info) 21747ec681f3Smrg return VK_SEMAPHORE_TYPE_BINARY_KHR; 21757ec681f3Smrg 21767ec681f3Smrg if (initial_value) 21777ec681f3Smrg *initial_value = type_info->initialValue; 21787ec681f3Smrg return type_info->semaphoreType; 21797ec681f3Smrg} 21807ec681f3Smrg 21817ec681f3Smrgstatic VkResult 21827ec681f3Smrgbinary_semaphore_create(struct anv_device *device, 21837ec681f3Smrg struct anv_semaphore_impl *impl, 21847ec681f3Smrg bool exportable) 21857ec681f3Smrg{ 21867ec681f3Smrg impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; 21877ec681f3Smrg impl->syncobj = anv_gem_syncobj_create(device, 0); 21887ec681f3Smrg if (!impl->syncobj) 21897ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 21907ec681f3Smrg return VK_SUCCESS; 21917ec681f3Smrg} 21927ec681f3Smrg 21937ec681f3Smrgstatic VkResult 21947ec681f3Smrgtimeline_semaphore_create(struct anv_device *device, 21957ec681f3Smrg struct anv_semaphore_impl *impl, 21967ec681f3Smrg uint64_t initial_value) 21977ec681f3Smrg{ 21987ec681f3Smrg if (device->has_thread_submit) { 21997ec681f3Smrg impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE; 22007ec681f3Smrg impl->syncobj = anv_gem_syncobj_create(device, 0); 22017ec681f3Smrg if (!impl->syncobj) 22027ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 22037ec681f3Smrg if (initial_value) { 22047ec681f3Smrg if (anv_gem_syncobj_timeline_signal(device, 22057ec681f3Smrg &impl->syncobj, 22067ec681f3Smrg &initial_value, 1)) { 22077ec681f3Smrg anv_gem_syncobj_destroy(device, impl->syncobj); 22087ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 22097ec681f3Smrg } 22107ec681f3Smrg } 22117ec681f3Smrg } else { 22127ec681f3Smrg impl->type = ANV_SEMAPHORE_TYPE_TIMELINE; 22137ec681f3Smrg anv_timeline_init(device, &impl->timeline, initial_value); 22147ec681f3Smrg } 22157ec681f3Smrg 22167ec681f3Smrg return VK_SUCCESS; 22177ec681f3Smrg} 22187ec681f3Smrg 221901e04c3fSmrgVkResult anv_CreateSemaphore( 222001e04c3fSmrg VkDevice _device, 222101e04c3fSmrg const VkSemaphoreCreateInfo* pCreateInfo, 222201e04c3fSmrg const VkAllocationCallbacks* pAllocator, 222301e04c3fSmrg VkSemaphore* pSemaphore) 222401e04c3fSmrg{ 222501e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 222601e04c3fSmrg struct anv_semaphore *semaphore; 222701e04c3fSmrg 222801e04c3fSmrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); 222901e04c3fSmrg 22307ec681f3Smrg uint64_t timeline_value = 0; 22317ec681f3Smrg VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value); 22327ec681f3Smrg 22337ec681f3Smrg semaphore = vk_object_alloc(&device->vk, NULL, sizeof(*semaphore), 22347ec681f3Smrg VK_OBJECT_TYPE_SEMAPHORE); 223501e04c3fSmrg if (semaphore == NULL) 22367ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 223701e04c3fSmrg 22389f464c52Smaya const VkExportSemaphoreCreateInfo *export = 223901e04c3fSmrg vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO); 22407ec681f3Smrg VkExternalSemaphoreHandleTypeFlags handleTypes = 224101e04c3fSmrg export ? export->handleTypes : 0; 22427ec681f3Smrg VkResult result; 224301e04c3fSmrg 224401e04c3fSmrg if (handleTypes == 0) { 22457ec681f3Smrg if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR) 22467ec681f3Smrg result = binary_semaphore_create(device, &semaphore->permanent, false); 22477ec681f3Smrg else 22487ec681f3Smrg result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value); 22497ec681f3Smrg if (result != VK_SUCCESS) { 22507ec681f3Smrg vk_object_free(&device->vk, pAllocator, semaphore); 22517ec681f3Smrg return result; 22527ec681f3Smrg } 225301e04c3fSmrg } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) { 225401e04c3fSmrg assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 22557ec681f3Smrg if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR) 22567ec681f3Smrg result = binary_semaphore_create(device, &semaphore->permanent, true); 22577ec681f3Smrg else 22587ec681f3Smrg result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value); 22597ec681f3Smrg if (result != VK_SUCCESS) { 22607ec681f3Smrg vk_object_free(&device->vk, pAllocator, semaphore); 22617ec681f3Smrg return result; 226201e04c3fSmrg } 226301e04c3fSmrg } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) { 226401e04c3fSmrg assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT); 22657ec681f3Smrg assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR); 22667ec681f3Smrg semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; 22677ec681f3Smrg semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0); 22687ec681f3Smrg if (!semaphore->permanent.syncobj) { 22697ec681f3Smrg vk_object_free(&device->vk, pAllocator, semaphore); 22707ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 22717ec681f3Smrg } 227201e04c3fSmrg } else { 227301e04c3fSmrg assert(!"Unknown handle type"); 22747ec681f3Smrg vk_object_free(&device->vk, pAllocator, semaphore); 22757ec681f3Smrg return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE); 227601e04c3fSmrg } 227701e04c3fSmrg 227801e04c3fSmrg semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE; 227901e04c3fSmrg 228001e04c3fSmrg *pSemaphore = anv_semaphore_to_handle(semaphore); 228101e04c3fSmrg 228201e04c3fSmrg return VK_SUCCESS; 228301e04c3fSmrg} 228401e04c3fSmrg 228501e04c3fSmrgstatic void 228601e04c3fSmrganv_semaphore_impl_cleanup(struct anv_device *device, 228701e04c3fSmrg struct anv_semaphore_impl *impl) 228801e04c3fSmrg{ 228901e04c3fSmrg switch (impl->type) { 229001e04c3fSmrg case ANV_SEMAPHORE_TYPE_NONE: 229101e04c3fSmrg case ANV_SEMAPHORE_TYPE_DUMMY: 229201e04c3fSmrg /* Dummy. Nothing to do */ 229301e04c3fSmrg break; 229401e04c3fSmrg 22957ec681f3Smrg case ANV_SEMAPHORE_TYPE_WSI_BO: 22967ec681f3Smrg anv_device_release_bo(device, impl->bo); 229701e04c3fSmrg break; 229801e04c3fSmrg 22997ec681f3Smrg case ANV_SEMAPHORE_TYPE_TIMELINE: 23007ec681f3Smrg anv_timeline_finish(device, &impl->timeline); 230101e04c3fSmrg break; 230201e04c3fSmrg 230301e04c3fSmrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: 23047ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 230501e04c3fSmrg anv_gem_syncobj_destroy(device, impl->syncobj); 230601e04c3fSmrg break; 230701e04c3fSmrg 230801e04c3fSmrg default: 230901e04c3fSmrg unreachable("Invalid semaphore type"); 231001e04c3fSmrg } 231101e04c3fSmrg 231201e04c3fSmrg impl->type = ANV_SEMAPHORE_TYPE_NONE; 231301e04c3fSmrg} 231401e04c3fSmrg 231501e04c3fSmrgvoid 231601e04c3fSmrganv_semaphore_reset_temporary(struct anv_device *device, 231701e04c3fSmrg struct anv_semaphore *semaphore) 231801e04c3fSmrg{ 231901e04c3fSmrg if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE) 232001e04c3fSmrg return; 232101e04c3fSmrg 232201e04c3fSmrg anv_semaphore_impl_cleanup(device, &semaphore->temporary); 232301e04c3fSmrg} 232401e04c3fSmrg 232501e04c3fSmrgvoid anv_DestroySemaphore( 232601e04c3fSmrg VkDevice _device, 232701e04c3fSmrg VkSemaphore _semaphore, 232801e04c3fSmrg const VkAllocationCallbacks* pAllocator) 232901e04c3fSmrg{ 233001e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 233101e04c3fSmrg ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 233201e04c3fSmrg 233301e04c3fSmrg if (semaphore == NULL) 233401e04c3fSmrg return; 233501e04c3fSmrg 233601e04c3fSmrg anv_semaphore_impl_cleanup(device, &semaphore->temporary); 233701e04c3fSmrg anv_semaphore_impl_cleanup(device, &semaphore->permanent); 233801e04c3fSmrg 23397ec681f3Smrg vk_object_base_finish(&semaphore->base); 23407ec681f3Smrg vk_free(&device->vk.alloc, semaphore); 234101e04c3fSmrg} 234201e04c3fSmrg 234301e04c3fSmrgvoid anv_GetPhysicalDeviceExternalSemaphoreProperties( 234401e04c3fSmrg VkPhysicalDevice physicalDevice, 23459f464c52Smaya const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, 23469f464c52Smaya VkExternalSemaphoreProperties* pExternalSemaphoreProperties) 234701e04c3fSmrg{ 234801e04c3fSmrg ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); 234901e04c3fSmrg 23507ec681f3Smrg VkSemaphoreTypeKHR sem_type = 23517ec681f3Smrg get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL); 23527ec681f3Smrg 235301e04c3fSmrg switch (pExternalSemaphoreInfo->handleType) { 235401e04c3fSmrg case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: 23557ec681f3Smrg /* Timeline semaphores are not exportable, unless we have threaded 23567ec681f3Smrg * submission. 23577ec681f3Smrg */ 23587ec681f3Smrg if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && !device->has_thread_submit) 23597ec681f3Smrg break; 236001e04c3fSmrg pExternalSemaphoreProperties->exportFromImportedHandleTypes = 236101e04c3fSmrg VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 236201e04c3fSmrg pExternalSemaphoreProperties->compatibleHandleTypes = 236301e04c3fSmrg VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 236401e04c3fSmrg pExternalSemaphoreProperties->externalSemaphoreFeatures = 236501e04c3fSmrg VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | 236601e04c3fSmrg VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; 236701e04c3fSmrg return; 236801e04c3fSmrg 236901e04c3fSmrg case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: 23707ec681f3Smrg if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR) 23717ec681f3Smrg break; 23727ec681f3Smrg if (!device->has_exec_fence) 23737ec681f3Smrg break; 23747ec681f3Smrg pExternalSemaphoreProperties->exportFromImportedHandleTypes = 23757ec681f3Smrg VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; 23767ec681f3Smrg pExternalSemaphoreProperties->compatibleHandleTypes = 23777ec681f3Smrg VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; 23787ec681f3Smrg pExternalSemaphoreProperties->externalSemaphoreFeatures = 23797ec681f3Smrg VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | 23807ec681f3Smrg VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; 23817ec681f3Smrg return; 238201e04c3fSmrg 238301e04c3fSmrg default: 238401e04c3fSmrg break; 238501e04c3fSmrg } 238601e04c3fSmrg 238701e04c3fSmrg pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; 238801e04c3fSmrg pExternalSemaphoreProperties->compatibleHandleTypes = 0; 238901e04c3fSmrg pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; 239001e04c3fSmrg} 239101e04c3fSmrg 239201e04c3fSmrgVkResult anv_ImportSemaphoreFdKHR( 239301e04c3fSmrg VkDevice _device, 239401e04c3fSmrg const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo) 239501e04c3fSmrg{ 239601e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 239701e04c3fSmrg ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore); 239801e04c3fSmrg int fd = pImportSemaphoreFdInfo->fd; 239901e04c3fSmrg 240001e04c3fSmrg struct anv_semaphore_impl new_impl = { 240101e04c3fSmrg .type = ANV_SEMAPHORE_TYPE_NONE, 240201e04c3fSmrg }; 240301e04c3fSmrg 240401e04c3fSmrg switch (pImportSemaphoreFdInfo->handleType) { 240501e04c3fSmrg case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: 24067ec681f3Smrg /* When importing non temporarily, reuse the semaphore's existing 24077ec681f3Smrg * type. The Linux/DRM implementation allows to interchangeably use 24087ec681f3Smrg * binary & timeline semaphores and we have no way to differenciate 24097ec681f3Smrg * them. 24107ec681f3Smrg */ 24117ec681f3Smrg if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) 241201e04c3fSmrg new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ; 24137ec681f3Smrg else 24147ec681f3Smrg new_impl.type = semaphore->permanent.type; 241501e04c3fSmrg 24167ec681f3Smrg new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd); 24177ec681f3Smrg if (!new_impl.syncobj) 24187ec681f3Smrg return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 241901e04c3fSmrg 242001e04c3fSmrg /* From the Vulkan spec: 242101e04c3fSmrg * 242201e04c3fSmrg * "Importing semaphore state from a file descriptor transfers 242301e04c3fSmrg * ownership of the file descriptor from the application to the 242401e04c3fSmrg * Vulkan implementation. The application must not perform any 242501e04c3fSmrg * operations on the file descriptor after a successful import." 242601e04c3fSmrg * 242701e04c3fSmrg * If the import fails, we leave the file descriptor open. 242801e04c3fSmrg */ 242901e04c3fSmrg close(fd); 243001e04c3fSmrg break; 243101e04c3fSmrg 24327ec681f3Smrg case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: { 24337ec681f3Smrg uint32_t create_flags = 0; 24347ec681f3Smrg 24357ec681f3Smrg if (fd == -1) 24367ec681f3Smrg create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 24377ec681f3Smrg 243801e04c3fSmrg new_impl = (struct anv_semaphore_impl) { 24397ec681f3Smrg .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ, 24407ec681f3Smrg .syncobj = anv_gem_syncobj_create(device, create_flags), 244101e04c3fSmrg }; 24427ec681f3Smrg 24437ec681f3Smrg if (!new_impl.syncobj) 24447ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 24457ec681f3Smrg 24467ec681f3Smrg if (fd != -1) { 24477ec681f3Smrg if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) { 24487ec681f3Smrg anv_gem_syncobj_destroy(device, new_impl.syncobj); 24497ec681f3Smrg return vk_errorf(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE, 24507ec681f3Smrg "syncobj sync file import failed: %m"); 24517ec681f3Smrg } 24527ec681f3Smrg /* Ownership of the FD is transfered to Anv. Since we don't need it 24537ec681f3Smrg * anymore because the associated fence has been put into a syncobj, 24547ec681f3Smrg * we must close the FD. 24557ec681f3Smrg */ 24567ec681f3Smrg close(fd); 24577ec681f3Smrg } 245801e04c3fSmrg break; 24597ec681f3Smrg } 246001e04c3fSmrg 246101e04c3fSmrg default: 24627ec681f3Smrg return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 246301e04c3fSmrg } 246401e04c3fSmrg 246501e04c3fSmrg if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) { 246601e04c3fSmrg anv_semaphore_impl_cleanup(device, &semaphore->temporary); 246701e04c3fSmrg semaphore->temporary = new_impl; 246801e04c3fSmrg } else { 246901e04c3fSmrg anv_semaphore_impl_cleanup(device, &semaphore->permanent); 247001e04c3fSmrg semaphore->permanent = new_impl; 247101e04c3fSmrg } 247201e04c3fSmrg 247301e04c3fSmrg return VK_SUCCESS; 247401e04c3fSmrg} 247501e04c3fSmrg 247601e04c3fSmrgVkResult anv_GetSemaphoreFdKHR( 247701e04c3fSmrg VkDevice _device, 247801e04c3fSmrg const VkSemaphoreGetFdInfoKHR* pGetFdInfo, 247901e04c3fSmrg int* pFd) 248001e04c3fSmrg{ 248101e04c3fSmrg ANV_FROM_HANDLE(anv_device, device, _device); 248201e04c3fSmrg ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore); 248301e04c3fSmrg int fd; 248401e04c3fSmrg 248501e04c3fSmrg assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR); 248601e04c3fSmrg 248701e04c3fSmrg struct anv_semaphore_impl *impl = 248801e04c3fSmrg semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 248901e04c3fSmrg &semaphore->temporary : &semaphore->permanent; 249001e04c3fSmrg 249101e04c3fSmrg switch (impl->type) { 24927ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: 24937ec681f3Smrg if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) { 24947ec681f3Smrg VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd); 24957ec681f3Smrg if (result != VK_SUCCESS) 24967ec681f3Smrg return result; 249701e04c3fSmrg 24987ec681f3Smrg fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj); 24997ec681f3Smrg } else { 25007ec681f3Smrg assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 25017ec681f3Smrg fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); 25027ec681f3Smrg } 25037ec681f3Smrg if (fd < 0) 25047ec681f3Smrg return vk_error(device, VK_ERROR_TOO_MANY_OBJECTS); 25057ec681f3Smrg *pFd = fd; 25067ec681f3Smrg break; 250701e04c3fSmrg 25087ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: 25097ec681f3Smrg assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 251001e04c3fSmrg fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj); 251101e04c3fSmrg if (fd < 0) 25127ec681f3Smrg return vk_error(device, VK_ERROR_TOO_MANY_OBJECTS); 251301e04c3fSmrg *pFd = fd; 251401e04c3fSmrg break; 251501e04c3fSmrg 251601e04c3fSmrg default: 25177ec681f3Smrg return vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 251801e04c3fSmrg } 251901e04c3fSmrg 252001e04c3fSmrg /* From the Vulkan 1.0.53 spec: 252101e04c3fSmrg * 252201e04c3fSmrg * "Export operations have the same transference as the specified handle 252301e04c3fSmrg * type’s import operations. [...] If the semaphore was using a 252401e04c3fSmrg * temporarily imported payload, the semaphore’s prior permanent payload 252501e04c3fSmrg * will be restored. 252601e04c3fSmrg */ 252701e04c3fSmrg if (impl == &semaphore->temporary) 252801e04c3fSmrg anv_semaphore_impl_cleanup(device, impl); 252901e04c3fSmrg 253001e04c3fSmrg return VK_SUCCESS; 253101e04c3fSmrg} 25327ec681f3Smrg 25337ec681f3SmrgVkResult anv_GetSemaphoreCounterValue( 25347ec681f3Smrg VkDevice _device, 25357ec681f3Smrg VkSemaphore _semaphore, 25367ec681f3Smrg uint64_t* pValue) 25377ec681f3Smrg{ 25387ec681f3Smrg ANV_FROM_HANDLE(anv_device, device, _device); 25397ec681f3Smrg ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore); 25407ec681f3Smrg 25417ec681f3Smrg struct anv_semaphore_impl *impl = 25427ec681f3Smrg semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 25437ec681f3Smrg &semaphore->temporary : &semaphore->permanent; 25447ec681f3Smrg 25457ec681f3Smrg switch (impl->type) { 25467ec681f3Smrg case ANV_SEMAPHORE_TYPE_TIMELINE: { 25477ec681f3Smrg pthread_mutex_lock(&device->mutex); 25487ec681f3Smrg anv_timeline_gc_locked(device, &impl->timeline); 25497ec681f3Smrg *pValue = impl->timeline.highest_past; 25507ec681f3Smrg pthread_mutex_unlock(&device->mutex); 25517ec681f3Smrg return VK_SUCCESS; 25527ec681f3Smrg } 25537ec681f3Smrg 25547ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: { 25557ec681f3Smrg int ret = anv_gem_syncobj_timeline_query(device, &impl->syncobj, pValue, 1); 25567ec681f3Smrg 25577ec681f3Smrg if (ret != 0) 25587ec681f3Smrg return anv_device_set_lost(device, "unable to query timeline syncobj"); 25597ec681f3Smrg 25607ec681f3Smrg return VK_SUCCESS; 25617ec681f3Smrg } 25627ec681f3Smrg 25637ec681f3Smrg default: 25647ec681f3Smrg unreachable("Invalid semaphore type"); 25657ec681f3Smrg } 25667ec681f3Smrg} 25677ec681f3Smrg 25687ec681f3Smrgstatic VkResult 25697ec681f3Smrganv_timeline_wait_locked(struct anv_device *device, 25707ec681f3Smrg struct anv_timeline *timeline, 25717ec681f3Smrg uint64_t serial, uint64_t abs_timeout_ns) 25727ec681f3Smrg{ 25737ec681f3Smrg /* Wait on the queue_submit condition variable until the timeline has a 25747ec681f3Smrg * time point pending that's at least as high as serial. 25757ec681f3Smrg */ 25767ec681f3Smrg while (timeline->highest_pending < serial) { 25777ec681f3Smrg struct timespec abstime = { 25787ec681f3Smrg .tv_sec = abs_timeout_ns / NSEC_PER_SEC, 25797ec681f3Smrg .tv_nsec = abs_timeout_ns % NSEC_PER_SEC, 25807ec681f3Smrg }; 25817ec681f3Smrg 25827ec681f3Smrg UNUSED int ret = pthread_cond_timedwait(&device->queue_submit, 25837ec681f3Smrg &device->mutex, &abstime); 25847ec681f3Smrg assert(ret != EINVAL); 25857ec681f3Smrg if (anv_gettime_ns() >= abs_timeout_ns && 25867ec681f3Smrg timeline->highest_pending < serial) 25877ec681f3Smrg return VK_TIMEOUT; 25887ec681f3Smrg } 25897ec681f3Smrg 25907ec681f3Smrg while (1) { 25917ec681f3Smrg VkResult result = anv_timeline_gc_locked(device, timeline); 25927ec681f3Smrg if (result != VK_SUCCESS) 25937ec681f3Smrg return result; 25947ec681f3Smrg 25957ec681f3Smrg if (timeline->highest_past >= serial) 25967ec681f3Smrg return VK_SUCCESS; 25977ec681f3Smrg 25987ec681f3Smrg /* If we got here, our earliest time point has a busy BO */ 25997ec681f3Smrg struct anv_timeline_point *point = 26007ec681f3Smrg list_first_entry(&timeline->points, 26017ec681f3Smrg struct anv_timeline_point, link); 26027ec681f3Smrg 26037ec681f3Smrg /* Drop the lock while we wait. */ 26047ec681f3Smrg point->waiting++; 26057ec681f3Smrg pthread_mutex_unlock(&device->mutex); 26067ec681f3Smrg 26077ec681f3Smrg result = anv_device_wait(device, point->bo, 26087ec681f3Smrg anv_get_relative_timeout(abs_timeout_ns)); 26097ec681f3Smrg 26107ec681f3Smrg /* Pick the mutex back up */ 26117ec681f3Smrg pthread_mutex_lock(&device->mutex); 26127ec681f3Smrg point->waiting--; 26137ec681f3Smrg 26147ec681f3Smrg /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */ 26157ec681f3Smrg if (result != VK_SUCCESS) 26167ec681f3Smrg return result; 26177ec681f3Smrg } 26187ec681f3Smrg} 26197ec681f3Smrg 26207ec681f3Smrgstatic VkResult 26217ec681f3Smrganv_timelines_wait(struct anv_device *device, 26227ec681f3Smrg struct anv_timeline **timelines, 26237ec681f3Smrg const uint64_t *serials, 26247ec681f3Smrg uint32_t n_timelines, 26257ec681f3Smrg bool wait_all, 26267ec681f3Smrg uint64_t abs_timeout_ns) 26277ec681f3Smrg{ 26287ec681f3Smrg if (!wait_all && n_timelines > 1) { 26297ec681f3Smrg pthread_mutex_lock(&device->mutex); 26307ec681f3Smrg 26317ec681f3Smrg while (1) { 26327ec681f3Smrg VkResult result; 26337ec681f3Smrg for (uint32_t i = 0; i < n_timelines; i++) { 26347ec681f3Smrg result = 26357ec681f3Smrg anv_timeline_wait_locked(device, timelines[i], serials[i], 0); 26367ec681f3Smrg if (result != VK_TIMEOUT) 26377ec681f3Smrg break; 26387ec681f3Smrg } 26397ec681f3Smrg 26407ec681f3Smrg if (result != VK_TIMEOUT || 26417ec681f3Smrg anv_gettime_ns() >= abs_timeout_ns) { 26427ec681f3Smrg pthread_mutex_unlock(&device->mutex); 26437ec681f3Smrg return result; 26447ec681f3Smrg } 26457ec681f3Smrg 26467ec681f3Smrg /* If none of them are ready do a short wait so we don't completely 26477ec681f3Smrg * spin while holding the lock. The 10us is completely arbitrary. 26487ec681f3Smrg */ 26497ec681f3Smrg uint64_t abs_short_wait_ns = 26507ec681f3Smrg anv_get_absolute_timeout( 26517ec681f3Smrg MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000)); 26527ec681f3Smrg struct timespec abstime = { 26537ec681f3Smrg .tv_sec = abs_short_wait_ns / NSEC_PER_SEC, 26547ec681f3Smrg .tv_nsec = abs_short_wait_ns % NSEC_PER_SEC, 26557ec681f3Smrg }; 26567ec681f3Smrg ASSERTED int ret; 26577ec681f3Smrg ret = pthread_cond_timedwait(&device->queue_submit, 26587ec681f3Smrg &device->mutex, &abstime); 26597ec681f3Smrg assert(ret != EINVAL); 26607ec681f3Smrg } 26617ec681f3Smrg } else { 26627ec681f3Smrg VkResult result = VK_SUCCESS; 26637ec681f3Smrg pthread_mutex_lock(&device->mutex); 26647ec681f3Smrg for (uint32_t i = 0; i < n_timelines; i++) { 26657ec681f3Smrg result = 26667ec681f3Smrg anv_timeline_wait_locked(device, timelines[i], 26677ec681f3Smrg serials[i], abs_timeout_ns); 26687ec681f3Smrg if (result != VK_SUCCESS) 26697ec681f3Smrg break; 26707ec681f3Smrg } 26717ec681f3Smrg pthread_mutex_unlock(&device->mutex); 26727ec681f3Smrg return result; 26737ec681f3Smrg } 26747ec681f3Smrg} 26757ec681f3Smrg 26767ec681f3SmrgVkResult anv_WaitSemaphores( 26777ec681f3Smrg VkDevice _device, 26787ec681f3Smrg const VkSemaphoreWaitInfoKHR* pWaitInfo, 26797ec681f3Smrg uint64_t timeout) 26807ec681f3Smrg{ 26817ec681f3Smrg ANV_FROM_HANDLE(anv_device, device, _device); 26827ec681f3Smrg uint32_t *handles; 26837ec681f3Smrg struct anv_timeline **timelines; 26847ec681f3Smrg 26857ec681f3Smrg VK_MULTIALLOC(ma); 26867ec681f3Smrg 26877ec681f3Smrg VK_MULTIALLOC_DECL(&ma, uint64_t, values, pWaitInfo->semaphoreCount); 26887ec681f3Smrg if (device->has_thread_submit) { 26897ec681f3Smrg vk_multialloc_add(&ma, &handles, uint32_t, pWaitInfo->semaphoreCount); 26907ec681f3Smrg } else { 26917ec681f3Smrg vk_multialloc_add(&ma, &timelines, struct anv_timeline *, 26927ec681f3Smrg pWaitInfo->semaphoreCount); 26937ec681f3Smrg } 26947ec681f3Smrg 26957ec681f3Smrg if (!vk_multialloc_alloc(&ma, &device->vk.alloc, 26967ec681f3Smrg VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)) 26977ec681f3Smrg return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 26987ec681f3Smrg 26997ec681f3Smrg uint32_t handle_count = 0; 27007ec681f3Smrg for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) { 27017ec681f3Smrg ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]); 27027ec681f3Smrg struct anv_semaphore_impl *impl = 27037ec681f3Smrg semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 27047ec681f3Smrg &semaphore->temporary : &semaphore->permanent; 27057ec681f3Smrg 27067ec681f3Smrg if (pWaitInfo->pValues[i] == 0) 27077ec681f3Smrg continue; 27087ec681f3Smrg 27097ec681f3Smrg if (device->has_thread_submit) { 27107ec681f3Smrg assert(impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE); 27117ec681f3Smrg handles[handle_count] = impl->syncobj; 27127ec681f3Smrg } else { 27137ec681f3Smrg assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE); 27147ec681f3Smrg timelines[handle_count] = &impl->timeline; 27157ec681f3Smrg } 27167ec681f3Smrg values[handle_count] = pWaitInfo->pValues[i]; 27177ec681f3Smrg handle_count++; 27187ec681f3Smrg } 27197ec681f3Smrg 27207ec681f3Smrg VkResult result = VK_SUCCESS; 27217ec681f3Smrg if (handle_count > 0) { 27227ec681f3Smrg if (device->has_thread_submit) { 27237ec681f3Smrg int ret = 27247ec681f3Smrg anv_gem_syncobj_timeline_wait(device, 27257ec681f3Smrg handles, values, handle_count, 27267ec681f3Smrg anv_get_absolute_timeout(timeout), 27277ec681f3Smrg !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR), 27287ec681f3Smrg false); 27297ec681f3Smrg if (ret != 0) 27307ec681f3Smrg result = errno == ETIME ? VK_TIMEOUT : 27317ec681f3Smrg anv_device_set_lost(device, "unable to wait on timeline syncobj"); 27327ec681f3Smrg } else { 27337ec681f3Smrg result = 27347ec681f3Smrg anv_timelines_wait(device, timelines, values, handle_count, 27357ec681f3Smrg !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR), 27367ec681f3Smrg anv_get_absolute_timeout(timeout)); 27377ec681f3Smrg } 27387ec681f3Smrg } 27397ec681f3Smrg 27407ec681f3Smrg vk_free(&device->vk.alloc, values); 27417ec681f3Smrg 27427ec681f3Smrg return result; 27437ec681f3Smrg} 27447ec681f3Smrg 27457ec681f3SmrgVkResult anv_SignalSemaphore( 27467ec681f3Smrg VkDevice _device, 27477ec681f3Smrg const VkSemaphoreSignalInfoKHR* pSignalInfo) 27487ec681f3Smrg{ 27497ec681f3Smrg ANV_FROM_HANDLE(anv_device, device, _device); 27507ec681f3Smrg ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore); 27517ec681f3Smrg 27527ec681f3Smrg struct anv_semaphore_impl *impl = 27537ec681f3Smrg semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? 27547ec681f3Smrg &semaphore->temporary : &semaphore->permanent; 27557ec681f3Smrg 27567ec681f3Smrg switch (impl->type) { 27577ec681f3Smrg case ANV_SEMAPHORE_TYPE_TIMELINE: { 27587ec681f3Smrg pthread_mutex_lock(&device->mutex); 27597ec681f3Smrg 27607ec681f3Smrg VkResult result = anv_timeline_gc_locked(device, &impl->timeline); 27617ec681f3Smrg 27627ec681f3Smrg assert(pSignalInfo->value > impl->timeline.highest_pending); 27637ec681f3Smrg 27647ec681f3Smrg impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value; 27657ec681f3Smrg 27667ec681f3Smrg if (result == VK_SUCCESS) 27677ec681f3Smrg result = anv_device_submit_deferred_locked(device); 27687ec681f3Smrg 27697ec681f3Smrg pthread_cond_broadcast(&device->queue_submit); 27707ec681f3Smrg pthread_mutex_unlock(&device->mutex); 27717ec681f3Smrg return result; 27727ec681f3Smrg } 27737ec681f3Smrg 27747ec681f3Smrg case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: { 27757ec681f3Smrg /* Timeline semaphores are created with a value of 0, so signaling on 0 27767ec681f3Smrg * is a waste of time. 27777ec681f3Smrg */ 27787ec681f3Smrg if (pSignalInfo->value == 0) 27797ec681f3Smrg return VK_SUCCESS; 27807ec681f3Smrg 27817ec681f3Smrg int ret = anv_gem_syncobj_timeline_signal(device, &impl->syncobj, 27827ec681f3Smrg &pSignalInfo->value, 1); 27837ec681f3Smrg 27847ec681f3Smrg return ret == 0 ? VK_SUCCESS : 27857ec681f3Smrg anv_device_set_lost(device, "unable to signal timeline syncobj"); 27867ec681f3Smrg } 27877ec681f3Smrg 27887ec681f3Smrg default: 27897ec681f3Smrg unreachable("Invalid semaphore type"); 27907ec681f3Smrg } 27917ec681f3Smrg} 2792