Path: blob/21.2-virgl/src/intel/vulkan/anv_queue.c
4547 views
/*1* Copyright © 2015 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223/**24* This file implements VkQueue, VkFence, and VkSemaphore25*/2627#include <errno.h>28#include <fcntl.h>29#include <unistd.h>3031#include "util/os_file.h"3233#include "anv_private.h"34#include "anv_measure.h"35#include "vk_util.h"3637#include "genxml/gen7_pack.h"3839uint64_t anv_gettime_ns(void)40{41struct timespec current;42clock_gettime(CLOCK_MONOTONIC, ¤t);43return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;44}4546uint64_t anv_get_absolute_timeout(uint64_t timeout)47{48if (timeout == 0)49return 0;50uint64_t current_time = anv_gettime_ns();51uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;5253timeout = MIN2(max_timeout, timeout);5455return (current_time + timeout);56}5758static int64_t anv_get_relative_timeout(uint64_t abs_timeout)59{60uint64_t now = anv_gettime_ns();6162/* We don't want negative timeouts.63*64* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is65* supposed to block indefinitely timeouts < 0. Unfortunately,66* this was broken for a couple of kernel releases. Since there's67* no way to know whether or not the kernel we're using is one of68* the broken ones, the best we can do is to clamp the timeout to69* INT64_MAX. This limits the maximum timeout from 584 years to70* 292 years - likely not a big deal.71*/72if (abs_timeout < now)73return 0;7475uint64_t rel_timeout = abs_timeout - now;76if (rel_timeout > (uint64_t) INT64_MAX)77rel_timeout = INT64_MAX;7879return rel_timeout;80}8182static struct anv_semaphore *anv_semaphore_ref(struct anv_semaphore *semaphore);83static void anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore);84static void anv_semaphore_impl_cleanup(struct anv_device *device,85struct anv_semaphore_impl *impl);8687static void88anv_queue_submit_free(struct anv_device *device,89struct anv_queue_submit *submit)90{91const VkAllocationCallbacks *alloc = submit->alloc;9293for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++)94anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]);95for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++)96anv_semaphore_unref(device, submit->sync_fd_semaphores[i]);97/* Execbuf does not consume the in_fence. It's our job to close it. */98if (submit->in_fence != -1) {99assert(!device->has_thread_submit);100close(submit->in_fence);101}102if (submit->out_fence != -1) {103assert(!device->has_thread_submit);104close(submit->out_fence);105}106vk_free(alloc, submit->fences);107vk_free(alloc, submit->fence_values);108vk_free(alloc, submit->temporary_semaphores);109vk_free(alloc, submit->wait_timelines);110vk_free(alloc, submit->wait_timeline_values);111vk_free(alloc, submit->signal_timelines);112vk_free(alloc, submit->signal_timeline_values);113vk_free(alloc, submit->fence_bos);114vk_free(alloc, submit->cmd_buffers);115vk_free(alloc, submit);116}117118static bool119anv_queue_submit_ready_locked(struct anv_queue_submit *submit)120{121for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {122if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending)123return false;124}125126return true;127}128129static VkResult130anv_timeline_init(struct anv_device *device,131struct anv_timeline *timeline,132uint64_t initial_value)133{134timeline->highest_past =135timeline->highest_pending = initial_value;136list_inithead(&timeline->points);137list_inithead(&timeline->free_points);138139return VK_SUCCESS;140}141142static void143anv_timeline_finish(struct anv_device *device,144struct anv_timeline *timeline)145{146list_for_each_entry_safe(struct anv_timeline_point, point,147&timeline->free_points, link) {148list_del(&point->link);149anv_device_release_bo(device, point->bo);150vk_free(&device->vk.alloc, point);151}152list_for_each_entry_safe(struct anv_timeline_point, point,153&timeline->points, link) {154list_del(&point->link);155anv_device_release_bo(device, point->bo);156vk_free(&device->vk.alloc, point);157}158}159160static VkResult161anv_timeline_add_point_locked(struct anv_device *device,162struct anv_timeline *timeline,163uint64_t value,164struct anv_timeline_point **point)165{166VkResult result = VK_SUCCESS;167168if (list_is_empty(&timeline->free_points)) {169*point =170vk_zalloc(&device->vk.alloc, sizeof(**point),1718, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);172if (!(*point))173result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);174if (result == VK_SUCCESS) {175result = anv_device_alloc_bo(device, "timeline-semaphore", 4096,176ANV_BO_ALLOC_EXTERNAL |177ANV_BO_ALLOC_IMPLICIT_SYNC,1780 /* explicit_address */,179&(*point)->bo);180if (result != VK_SUCCESS)181vk_free(&device->vk.alloc, *point);182}183} else {184*point = list_first_entry(&timeline->free_points,185struct anv_timeline_point, link);186list_del(&(*point)->link);187}188189if (result == VK_SUCCESS) {190(*point)->serial = value;191list_addtail(&(*point)->link, &timeline->points);192}193194return result;195}196197static VkResult198anv_timeline_gc_locked(struct anv_device *device,199struct anv_timeline *timeline)200{201list_for_each_entry_safe(struct anv_timeline_point, point,202&timeline->points, link) {203/* timeline->higest_pending is only incremented once submission has204* happened. If this point has a greater serial, it means the point205* hasn't been submitted yet.206*/207if (point->serial > timeline->highest_pending)208return VK_SUCCESS;209210/* If someone is waiting on this time point, consider it busy and don't211* try to recycle it. There's a slim possibility that it's no longer212* busy by the time we look at it but we would be recycling it out from213* under a waiter and that can lead to weird races.214*215* We walk the list in-order so if this time point is still busy so is216* every following time point217*/218assert(point->waiting >= 0);219if (point->waiting)220return VK_SUCCESS;221222/* Garbage collect any signaled point. */223VkResult result = anv_device_bo_busy(device, point->bo);224if (result == VK_NOT_READY) {225/* We walk the list in-order so if this time point is still busy so226* is every following time point227*/228return VK_SUCCESS;229} else if (result != VK_SUCCESS) {230return result;231}232233assert(timeline->highest_past < point->serial);234timeline->highest_past = point->serial;235236list_del(&point->link);237list_add(&point->link, &timeline->free_points);238}239240return VK_SUCCESS;241}242243static VkResult anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,244struct anv_bo *bo,245bool signal);246247static VkResult248anv_queue_submit_timeline_locked(struct anv_queue *queue,249struct anv_queue_submit *submit)250{251VkResult result;252253for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {254struct anv_timeline *timeline = submit->wait_timelines[i];255uint64_t wait_value = submit->wait_timeline_values[i];256257if (timeline->highest_past >= wait_value)258continue;259260list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) {261if (point->serial < wait_value)262continue;263result = anv_queue_submit_add_fence_bo(submit, point->bo, false);264if (result != VK_SUCCESS)265return result;266break;267}268}269for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {270struct anv_timeline *timeline = submit->signal_timelines[i];271uint64_t signal_value = submit->signal_timeline_values[i];272struct anv_timeline_point *point;273274result = anv_timeline_add_point_locked(queue->device, timeline,275signal_value, &point);276if (result != VK_SUCCESS)277return result;278279result = anv_queue_submit_add_fence_bo(submit, point->bo, true);280if (result != VK_SUCCESS)281return result;282}283284result = anv_queue_execbuf_locked(queue, submit);285286if (result == VK_SUCCESS) {287/* Update the pending values in the timeline objects. */288for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {289struct anv_timeline *timeline = submit->signal_timelines[i];290uint64_t signal_value = submit->signal_timeline_values[i];291292assert(signal_value > timeline->highest_pending);293timeline->highest_pending = signal_value;294}295296/* Update signaled semaphores backed by syncfd. */297for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {298struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];299/* Out fences can't have temporary state because that would imply300* that we imported a sync file and are trying to signal it.301*/302assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);303struct anv_semaphore_impl *impl = &semaphore->permanent;304305assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);306impl->fd = os_dupfd_cloexec(submit->out_fence);307}308} else {309/* Unblock any waiter by signaling the points, the application will get310* a device lost error code.311*/312for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {313struct anv_timeline *timeline = submit->signal_timelines[i];314uint64_t signal_value = submit->signal_timeline_values[i];315316assert(signal_value > timeline->highest_pending);317timeline->highest_past = timeline->highest_pending = signal_value;318}319}320321return result;322}323324static VkResult325anv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance)326{327VkResult result = VK_SUCCESS;328329/* Go through all the queued submissions and submit then until we find one330* that's waiting on a point that hasn't materialized yet.331*/332list_for_each_entry_safe(struct anv_queue_submit, submit,333&queue->queued_submits, link) {334if (!anv_queue_submit_ready_locked(submit))335break;336337(*advance)++;338list_del(&submit->link);339340result = anv_queue_submit_timeline_locked(queue, submit);341342anv_queue_submit_free(queue->device, submit);343344if (result != VK_SUCCESS)345break;346}347348return result;349}350351static VkResult352anv_device_submit_deferred_locked(struct anv_device *device)353{354VkResult result = VK_SUCCESS;355356uint32_t advance;357do {358advance = 0;359for (uint32_t i = 0; i < device->queue_count; i++) {360struct anv_queue *queue = &device->queues[i];361VkResult qres = anv_queue_submit_deferred_locked(queue, &advance);362if (qres != VK_SUCCESS)363result = qres;364}365} while (advance);366367return result;368}369370static void371anv_queue_submit_signal_fences(struct anv_device *device,372struct anv_queue_submit *submit)373{374for (uint32_t i = 0; i < submit->fence_count; i++) {375if (submit->fences[i].flags & I915_EXEC_FENCE_SIGNAL) {376anv_gem_syncobj_timeline_signal(device, &submit->fences[i].handle,377&submit->fence_values[i], 1);378}379}380}381382static void *383anv_queue_task(void *_queue)384{385struct anv_queue *queue = _queue;386387pthread_mutex_lock(&queue->mutex);388389while (!queue->quit) {390while (!list_is_empty(&queue->queued_submits)) {391struct anv_queue_submit *submit =392list_first_entry(&queue->queued_submits, struct anv_queue_submit, link);393list_del(&submit->link);394395pthread_mutex_unlock(&queue->mutex);396397VkResult result = VK_ERROR_DEVICE_LOST;398399/* Wait for timeline points to materialize before submitting. We need400* to do this because we're using threads to do the submit to i915.401* We could end up in a situation where the application submits to 2402* queues with the first submit creating the dma-fence for the403* second. But because the scheduling of the submission threads might404* wakeup the second queue thread first, this would make that execbuf405* fail because the dma-fence it depends on hasn't materialized yet.406*/407if (!queue->lost && submit->wait_timeline_count > 0) {408int ret = queue->device->no_hw ? 0 :409anv_gem_syncobj_timeline_wait(410queue->device, submit->wait_timeline_syncobjs,411submit->wait_timeline_values, submit->wait_timeline_count,412anv_get_absolute_timeout(UINT64_MAX) /* wait forever */,413true /* wait for all */, true /* wait for materialize */);414if (ret) {415result = anv_queue_set_lost(queue, "timeline timeout: %s",416strerror(errno));417}418}419420/* Now submit */421if (!queue->lost) {422pthread_mutex_lock(&queue->device->mutex);423result = anv_queue_execbuf_locked(queue, submit);424pthread_mutex_unlock(&queue->device->mutex);425}426427for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {428struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];429/* Out fences can't have temporary state because that would imply430* that we imported a sync file and are trying to signal it.431*/432assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);433struct anv_semaphore_impl *impl = &semaphore->permanent;434435assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);436impl->fd = dup(submit->out_fence);437}438439if (result != VK_SUCCESS) {440/* vkQueueSubmit or some other entry point will report the441* DEVICE_LOST error at some point, but until we have emptied our442* list of execbufs we need to wake up all potential the waiters443* until one of them spots the error.444*/445anv_queue_submit_signal_fences(queue->device, submit);446}447448anv_queue_submit_free(queue->device, submit);449450pthread_mutex_lock(&queue->mutex);451}452453if (!queue->quit)454pthread_cond_wait(&queue->cond, &queue->mutex);455}456457pthread_mutex_unlock(&queue->mutex);458459return NULL;460}461462static VkResult463anv_queue_submit_post(struct anv_queue *queue,464struct anv_queue_submit **_submit,465bool flush_queue)466{467struct anv_queue_submit *submit = *_submit;468469/* Wait before signal behavior means we might keep alive the470* anv_queue_submit object a bit longer, so transfer the ownership to the471* anv_queue.472*/473*_submit = NULL;474if (queue->device->has_thread_submit) {475pthread_mutex_lock(&queue->mutex);476pthread_cond_broadcast(&queue->cond);477list_addtail(&submit->link, &queue->queued_submits);478pthread_mutex_unlock(&queue->mutex);479return VK_SUCCESS;480} else {481pthread_mutex_lock(&queue->device->mutex);482list_addtail(&submit->link, &queue->queued_submits);483VkResult result = anv_device_submit_deferred_locked(queue->device);484if (flush_queue) {485while (result == VK_SUCCESS && !list_is_empty(&queue->queued_submits)) {486int ret = pthread_cond_wait(&queue->device->queue_submit,487&queue->device->mutex);488if (ret != 0) {489result = anv_device_set_lost(queue->device, "wait timeout");490break;491}492493result = anv_device_submit_deferred_locked(queue->device);494}495}496pthread_mutex_unlock(&queue->device->mutex);497return result;498}499}500501VkResult502anv_queue_init(struct anv_device *device, struct anv_queue *queue,503uint32_t exec_flags,504const VkDeviceQueueCreateInfo *pCreateInfo)505{506struct anv_physical_device *pdevice = device->physical;507VkResult result;508509queue->device = device;510queue->flags = pCreateInfo->flags;511512assert(pCreateInfo->queueFamilyIndex < pdevice->queue.family_count);513queue->family = &pdevice->queue.families[pCreateInfo->queueFamilyIndex];514515queue->exec_flags = exec_flags;516queue->lost = false;517queue->quit = false;518519list_inithead(&queue->queued_submits);520521/* We only need those additional thread/mutex when using a thread for522* submission.523*/524if (device->has_thread_submit) {525if (pthread_mutex_init(&queue->mutex, NULL) != 0)526return vk_error(VK_ERROR_INITIALIZATION_FAILED);527528if (pthread_cond_init(&queue->cond, NULL) != 0) {529result = vk_error(VK_ERROR_INITIALIZATION_FAILED);530goto fail_mutex;531}532if (pthread_create(&queue->thread, NULL, anv_queue_task, queue)) {533result = vk_error(VK_ERROR_INITIALIZATION_FAILED);534goto fail_cond;535}536}537538vk_object_base_init(&device->vk, &queue->base, VK_OBJECT_TYPE_QUEUE);539540return VK_SUCCESS;541542fail_cond:543pthread_cond_destroy(&queue->cond);544fail_mutex:545pthread_mutex_destroy(&queue->mutex);546547return result;548}549550void551anv_queue_finish(struct anv_queue *queue)552{553if (queue->device->has_thread_submit) {554pthread_mutex_lock(&queue->mutex);555pthread_cond_broadcast(&queue->cond);556queue->quit = true;557pthread_mutex_unlock(&queue->mutex);558559void *ret;560pthread_join(queue->thread, &ret);561562pthread_cond_destroy(&queue->cond);563pthread_mutex_destroy(&queue->mutex);564}565566vk_object_base_finish(&queue->base);567}568569static VkResult570anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,571struct anv_bo *bo,572bool signal)573{574if (submit->fence_bo_count >= submit->fence_bo_array_length) {575uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64);576uintptr_t *new_fence_bos =577vk_realloc(submit->alloc,578submit->fence_bos, new_len * sizeof(*submit->fence_bos),5798, submit->alloc_scope);580if (new_fence_bos == NULL)581return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);582583submit->fence_bos = new_fence_bos;584submit->fence_bo_array_length = new_len;585}586587/* Take advantage that anv_bo are allocated at 8 byte alignement so we can588* use the lowest bit to store whether this is a BO we need to signal.589*/590submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal);591592return VK_SUCCESS;593}594595static VkResult596anv_queue_submit_add_syncobj(struct anv_queue_submit* submit,597struct anv_device *device,598uint32_t handle, uint32_t flags,599uint64_t value)600{601assert(flags != 0);602603if (device->has_thread_submit && (flags & I915_EXEC_FENCE_WAIT)) {604if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {605uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);606607uint32_t *new_wait_timeline_syncobjs =608vk_realloc(submit->alloc,609submit->wait_timeline_syncobjs,610new_len * sizeof(*submit->wait_timeline_syncobjs),6118, submit->alloc_scope);612if (new_wait_timeline_syncobjs == NULL)613return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);614615submit->wait_timeline_syncobjs = new_wait_timeline_syncobjs;616617uint64_t *new_wait_timeline_values =618vk_realloc(submit->alloc,619submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),6208, submit->alloc_scope);621if (new_wait_timeline_values == NULL)622return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);623624submit->wait_timeline_values = new_wait_timeline_values;625submit->wait_timeline_array_length = new_len;626}627628submit->wait_timeline_syncobjs[submit->wait_timeline_count] = handle;629submit->wait_timeline_values[submit->wait_timeline_count] = value;630631submit->wait_timeline_count++;632}633634if (submit->fence_count >= submit->fence_array_length) {635uint32_t new_len = MAX2(submit->fence_array_length * 2, 64);636struct drm_i915_gem_exec_fence *new_fences =637vk_realloc(submit->alloc,638submit->fences, new_len * sizeof(*submit->fences),6398, submit->alloc_scope);640if (new_fences == NULL)641return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);642643submit->fences = new_fences;644645uint64_t *new_fence_values =646vk_realloc(submit->alloc,647submit->fence_values, new_len * sizeof(*submit->fence_values),6488, submit->alloc_scope);649if (new_fence_values == NULL)650return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);651652submit->fence_values = new_fence_values;653submit->fence_array_length = new_len;654}655656submit->fences[submit->fence_count] = (struct drm_i915_gem_exec_fence) {657.handle = handle,658.flags = flags,659};660submit->fence_values[submit->fence_count] = value;661submit->fence_count++;662663return VK_SUCCESS;664}665666static VkResult667anv_queue_submit_add_sync_fd_fence(struct anv_queue_submit *submit,668struct anv_semaphore *semaphore)669{670if (submit->sync_fd_semaphore_count >= submit->sync_fd_semaphore_array_length) {671uint32_t new_len = MAX2(submit->sync_fd_semaphore_array_length * 2, 64);672struct anv_semaphore **new_semaphores =673vk_realloc(submit->alloc, submit->sync_fd_semaphores,674new_len * sizeof(*submit->sync_fd_semaphores), 8,675submit->alloc_scope);676if (new_semaphores == NULL)677return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);678679submit->sync_fd_semaphores = new_semaphores;680}681682submit->sync_fd_semaphores[submit->sync_fd_semaphore_count++] =683anv_semaphore_ref(semaphore);684submit->need_out_fence = true;685686return VK_SUCCESS;687}688689static VkResult690anv_queue_submit_add_timeline_wait(struct anv_queue_submit* submit,691struct anv_device *device,692struct anv_timeline *timeline,693uint64_t value)694{695if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {696uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);697struct anv_timeline **new_wait_timelines =698vk_realloc(submit->alloc,699submit->wait_timelines, new_len * sizeof(*submit->wait_timelines),7008, submit->alloc_scope);701if (new_wait_timelines == NULL)702return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);703704submit->wait_timelines = new_wait_timelines;705706uint64_t *new_wait_timeline_values =707vk_realloc(submit->alloc,708submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),7098, submit->alloc_scope);710if (new_wait_timeline_values == NULL)711return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);712713submit->wait_timeline_values = new_wait_timeline_values;714715submit->wait_timeline_array_length = new_len;716}717718submit->wait_timelines[submit->wait_timeline_count] = timeline;719submit->wait_timeline_values[submit->wait_timeline_count] = value;720721submit->wait_timeline_count++;722723return VK_SUCCESS;724}725726static VkResult727anv_queue_submit_add_timeline_signal(struct anv_queue_submit* submit,728struct anv_device *device,729struct anv_timeline *timeline,730uint64_t value)731{732assert(timeline->highest_pending < value);733734if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {735uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64);736struct anv_timeline **new_signal_timelines =737vk_realloc(submit->alloc,738submit->signal_timelines, new_len * sizeof(*submit->signal_timelines),7398, submit->alloc_scope);740if (new_signal_timelines == NULL)741return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);742743submit->signal_timelines = new_signal_timelines;744745uint64_t *new_signal_timeline_values =746vk_realloc(submit->alloc,747submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values),7488, submit->alloc_scope);749if (new_signal_timeline_values == NULL)750return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);751752submit->signal_timeline_values = new_signal_timeline_values;753754submit->signal_timeline_array_length = new_len;755}756757submit->signal_timelines[submit->signal_timeline_count] = timeline;758submit->signal_timeline_values[submit->signal_timeline_count] = value;759760submit->signal_timeline_count++;761762return VK_SUCCESS;763}764765static struct anv_queue_submit *766anv_queue_submit_alloc(struct anv_device *device)767{768const VkAllocationCallbacks *alloc = &device->vk.alloc;769VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;770771struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope);772if (!submit)773return NULL;774775submit->alloc = alloc;776submit->alloc_scope = alloc_scope;777submit->in_fence = -1;778submit->out_fence = -1;779submit->perf_query_pass = -1;780781return submit;782}783784VkResult785anv_queue_submit_simple_batch(struct anv_queue *queue,786struct anv_batch *batch)787{788if (queue->device->no_hw)789return VK_SUCCESS;790791struct anv_device *device = queue->device;792struct anv_queue_submit *submit = anv_queue_submit_alloc(device);793if (!submit)794return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);795796bool has_syncobj_wait = device->physical->has_syncobj_wait;797VkResult result;798uint32_t syncobj;799struct anv_bo *batch_bo, *sync_bo;800801if (has_syncobj_wait) {802syncobj = anv_gem_syncobj_create(device, 0);803if (!syncobj) {804result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);805goto err_free_submit;806}807808result = anv_queue_submit_add_syncobj(submit, device, syncobj,809I915_EXEC_FENCE_SIGNAL, 0);810} else {811result = anv_device_alloc_bo(device, "simple-batch-sync", 4096,812ANV_BO_ALLOC_EXTERNAL |813ANV_BO_ALLOC_IMPLICIT_SYNC,8140 /* explicit_address */,815&sync_bo);816if (result != VK_SUCCESS)817goto err_free_submit;818819result = anv_queue_submit_add_fence_bo(submit, sync_bo, true /* signal */);820}821822if (result != VK_SUCCESS)823goto err_destroy_sync_primitive;824825if (batch) {826uint32_t size = align_u32(batch->next - batch->start, 8);827result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);828if (result != VK_SUCCESS)829goto err_destroy_sync_primitive;830831memcpy(batch_bo->map, batch->start, size);832if (!device->info.has_llc)833intel_flush_range(batch_bo->map, size);834835submit->simple_bo = batch_bo;836submit->simple_bo_size = size;837}838839result = anv_queue_submit_post(queue, &submit, true);840841if (result == VK_SUCCESS) {842if (has_syncobj_wait) {843if (anv_gem_syncobj_wait(device, &syncobj, 1,844anv_get_absolute_timeout(INT64_MAX), true))845result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");846anv_gem_syncobj_destroy(device, syncobj);847} else {848result = anv_device_wait(device, sync_bo,849anv_get_relative_timeout(INT64_MAX));850anv_device_release_bo(device, sync_bo);851}852}853854if (batch)855anv_bo_pool_free(&device->batch_bo_pool, batch_bo);856857if (submit)858anv_queue_submit_free(device, submit);859860return result;861862err_destroy_sync_primitive:863if (has_syncobj_wait)864anv_gem_syncobj_destroy(device, syncobj);865else866anv_device_release_bo(device, sync_bo);867err_free_submit:868if (submit)869anv_queue_submit_free(device, submit);870871return result;872}873874/* Transfer ownership of temporary semaphores from the VkSemaphore object to875* the anv_queue_submit object. Those temporary semaphores are then freed in876* anv_queue_submit_free() once the driver is finished with them.877*/878static VkResult879maybe_transfer_temporary_semaphore(struct anv_queue_submit *submit,880struct anv_semaphore *semaphore,881struct anv_semaphore_impl **out_impl)882{883struct anv_semaphore_impl *impl = &semaphore->temporary;884885if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {886*out_impl = &semaphore->permanent;887return VK_SUCCESS;888}889890/* BO backed timeline semaphores cannot be temporary. */891assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE);892893/*894* There is a requirement to reset semaphore to their permanent state after895* submission. From the Vulkan 1.0.53 spec:896*897* "If the import is temporary, the implementation must restore the898* semaphore to its prior permanent state after submitting the next899* semaphore wait operation."900*901* In the case we defer the actual submission to a thread because of the902* wait-before-submit behavior required for timeline semaphores, we need to903* make copies of the temporary syncobj to ensure they stay alive until we904* do the actual execbuffer ioctl.905*/906if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {907uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);908/* Make sure that if the realloc fails, we still have the old semaphore909* array around to properly clean things up on failure.910*/911struct anv_semaphore_impl *new_array =912vk_realloc(submit->alloc,913submit->temporary_semaphores,914new_len * sizeof(*submit->temporary_semaphores),9158, submit->alloc_scope);916if (new_array == NULL)917return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);918919submit->temporary_semaphores = new_array;920submit->temporary_semaphore_array_length = new_len;921}922923/* Copy anv_semaphore_impl into anv_queue_submit. */924submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;925*out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];926927/* Clear the incoming semaphore */928impl->type = ANV_SEMAPHORE_TYPE_NONE;929930return VK_SUCCESS;931}932933static VkResult934anv_queue_submit_add_in_semaphores(struct anv_queue_submit *submit,935struct anv_device *device,936const VkSemaphore *in_semaphores,937const uint64_t *in_values,938uint32_t num_in_semaphores)939{940ASSERTED struct anv_physical_device *pdevice = device->physical;941VkResult result;942943for (uint32_t i = 0; i < num_in_semaphores; i++) {944ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);945struct anv_semaphore_impl *impl;946947result = maybe_transfer_temporary_semaphore(submit, semaphore, &impl);948if (result != VK_SUCCESS)949return result;950951switch (impl->type) {952case ANV_SEMAPHORE_TYPE_BO:953assert(!pdevice->has_syncobj);954result = anv_queue_submit_add_fence_bo(submit, impl->bo, false /* signal */);955if (result != VK_SUCCESS)956return result;957break;958959case ANV_SEMAPHORE_TYPE_WSI_BO:960/* When using a window-system buffer as a semaphore, always enable961* EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or962* compositor's read of the buffer and enforces that we don't start963* rendering until they are finished. This is exactly the964* synchronization we want with vkAcquireNextImage.965*/966result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);967if (result != VK_SUCCESS)968return result;969break;970971case ANV_SEMAPHORE_TYPE_SYNC_FILE:972assert(!pdevice->has_syncobj);973if (submit->in_fence == -1) {974submit->in_fence = impl->fd;975if (submit->in_fence == -1)976return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);977impl->fd = -1;978} else {979int merge = anv_gem_sync_file_merge(device, submit->in_fence, impl->fd);980if (merge == -1)981return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);982close(impl->fd);983close(submit->in_fence);984impl->fd = -1;985submit->in_fence = merge;986}987break;988989case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {990result = anv_queue_submit_add_syncobj(submit, device,991impl->syncobj,992I915_EXEC_FENCE_WAIT,9930);994if (result != VK_SUCCESS)995return result;996break;997}998999case ANV_SEMAPHORE_TYPE_TIMELINE:1000assert(in_values);1001if (in_values[i] == 0)1002break;1003result = anv_queue_submit_add_timeline_wait(submit, device,1004&impl->timeline,1005in_values[i]);1006if (result != VK_SUCCESS)1007return result;1008break;10091010case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:1011assert(in_values);1012if (in_values[i] == 0)1013break;1014result = anv_queue_submit_add_syncobj(submit, device,1015impl->syncobj,1016I915_EXEC_FENCE_WAIT,1017in_values[i]);1018if (result != VK_SUCCESS)1019return result;1020break;10211022default:1023break;1024}1025}10261027return VK_SUCCESS;1028}10291030static VkResult1031anv_queue_submit_add_out_semaphores(struct anv_queue_submit *submit,1032struct anv_device *device,1033const VkSemaphore *out_semaphores,1034const uint64_t *out_values,1035uint32_t num_out_semaphores)1036{1037ASSERTED struct anv_physical_device *pdevice = device->physical;1038VkResult result;10391040for (uint32_t i = 0; i < num_out_semaphores; i++) {1041ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);10421043/* Under most circumstances, out fences won't be temporary. However,1044* the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:1045*1046* "If the import is temporary, the implementation must restore the1047* semaphore to its prior permanent state after submitting the next1048* semaphore wait operation."1049*1050* The spec says nothing whatsoever about signal operations on1051* temporarily imported semaphores so it appears they are allowed.1052* There are also CTS tests that require this to work.1053*/1054struct anv_semaphore_impl *impl =1055semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?1056&semaphore->temporary : &semaphore->permanent;10571058switch (impl->type) {1059case ANV_SEMAPHORE_TYPE_BO:1060assert(!pdevice->has_syncobj);1061result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);1062if (result != VK_SUCCESS)1063return result;1064break;10651066case ANV_SEMAPHORE_TYPE_SYNC_FILE:1067assert(!pdevice->has_syncobj);1068result = anv_queue_submit_add_sync_fd_fence(submit, semaphore);1069if (result != VK_SUCCESS)1070return result;1071break;10721073case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {1074/*1075* Reset the content of the syncobj so it doesn't contain a1076* previously signaled dma-fence, until one is added by EXECBUFFER by1077* the submission thread.1078*/1079anv_gem_syncobj_reset(device, impl->syncobj);10801081result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,1082I915_EXEC_FENCE_SIGNAL,10830);1084if (result != VK_SUCCESS)1085return result;1086break;1087}10881089case ANV_SEMAPHORE_TYPE_TIMELINE:1090assert(out_values);1091if (out_values[i] == 0)1092break;1093result = anv_queue_submit_add_timeline_signal(submit, device,1094&impl->timeline,1095out_values[i]);1096if (result != VK_SUCCESS)1097return result;1098break;10991100case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:1101assert(out_values);1102if (out_values[i] == 0)1103break;1104result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,1105I915_EXEC_FENCE_SIGNAL,1106out_values[i]);1107if (result != VK_SUCCESS)1108return result;1109break;11101111default:1112break;1113}1114}11151116return VK_SUCCESS;1117}11181119static VkResult1120anv_queue_submit_add_fence(struct anv_queue_submit *submit,1121struct anv_device *device,1122struct anv_fence *fence)1123{1124/* Under most circumstances, out fences won't be temporary. However, the1125* spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:1126*1127* "If the import is temporary, the implementation must restore the1128* semaphore to its prior permanent state after submitting the next1129* semaphore wait operation."1130*1131* The spec says nothing whatsoever about signal operations on temporarily1132* imported semaphores so it appears they are allowed. There are also CTS1133* tests that require this to work.1134*/1135struct anv_fence_impl *impl =1136fence->temporary.type != ANV_FENCE_TYPE_NONE ?1137&fence->temporary : &fence->permanent;11381139VkResult result;11401141switch (impl->type) {1142case ANV_FENCE_TYPE_BO:1143assert(!device->has_thread_submit);1144result = anv_queue_submit_add_fence_bo(submit, impl->bo.bo, true /* signal */);1145if (result != VK_SUCCESS)1146return result;1147break;11481149case ANV_FENCE_TYPE_SYNCOBJ: {1150/*1151* For the same reason we reset the signaled binary syncobj above, also1152* reset the fence's syncobj so that they don't contain a signaled1153* dma-fence.1154*/1155anv_gem_syncobj_reset(device, impl->syncobj);11561157result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,1158I915_EXEC_FENCE_SIGNAL,11590);1160if (result != VK_SUCCESS)1161return result;1162break;1163}11641165default:1166unreachable("Invalid fence type");1167}11681169return VK_SUCCESS;1170}11711172static void1173anv_post_queue_fence_update(struct anv_device *device, struct anv_fence *fence)1174{1175if (fence->permanent.type == ANV_FENCE_TYPE_BO) {1176assert(!device->has_thread_submit);1177/* If we have permanent BO fence, the only type of temporary possible1178* would be BO_WSI (because BO fences are not shareable). The Vulkan spec1179* also requires that the fence passed to vkQueueSubmit() be :1180*1181* * unsignaled1182* * not be associated with any other queue command that has not yet1183* completed execution on that queue1184*1185* So the only acceptable type for the temporary is NONE.1186*/1187assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);11881189/* Once the execbuf has returned, we need to set the fence state to1190* SUBMITTED. We can't do this before calling execbuf because1191* anv_GetFenceStatus does take the global device lock before checking1192* fence->state.1193*1194* We set the fence state to SUBMITTED regardless of whether or not the1195* execbuf succeeds because we need to ensure that vkWaitForFences() and1196* vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or1197* VK_SUCCESS) in a finite amount of time even if execbuf fails.1198*/1199fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;1200}1201}12021203static VkResult1204anv_queue_submit_add_cmd_buffer(struct anv_queue_submit *submit,1205struct anv_cmd_buffer *cmd_buffer,1206int perf_pass)1207{1208if (submit->cmd_buffer_count >= submit->cmd_buffer_array_length) {1209uint32_t new_len = MAX2(submit->cmd_buffer_array_length * 2, 4);1210struct anv_cmd_buffer **new_cmd_buffers =1211vk_realloc(submit->alloc,1212submit->cmd_buffers, new_len * sizeof(*submit->cmd_buffers),12138, submit->alloc_scope);1214if (new_cmd_buffers == NULL)1215return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);12161217submit->cmd_buffers = new_cmd_buffers;1218submit->cmd_buffer_array_length = new_len;1219}12201221submit->cmd_buffers[submit->cmd_buffer_count++] = cmd_buffer;1222/* Only update the perf_query_pool if there is one. We can decide to batch1223* 2 command buffers if the second one doesn't use a query pool, but we1224* can't drop the already chosen one.1225*/1226if (cmd_buffer->perf_query_pool)1227submit->perf_query_pool = cmd_buffer->perf_query_pool;1228submit->perf_query_pass = perf_pass;12291230return VK_SUCCESS;1231}12321233static bool1234anv_queue_submit_can_add_cmd_buffer(const struct anv_queue_submit *submit,1235const struct anv_cmd_buffer *cmd_buffer,1236int perf_pass)1237{1238/* If first command buffer, no problem. */1239if (submit->cmd_buffer_count == 0)1240return true;12411242/* Can we chain the last buffer into the next one? */1243if (!anv_cmd_buffer_is_chainable(submit->cmd_buffers[submit->cmd_buffer_count - 1]))1244return false;12451246/* A change of perf query pools between VkSubmitInfo elements means we1247* can't batch things up.1248*/1249if (cmd_buffer->perf_query_pool &&1250submit->perf_query_pool &&1251submit->perf_query_pool != cmd_buffer->perf_query_pool)1252return false;12531254/* A change of perf pass also prevents batching things up.1255*/1256if (submit->perf_query_pass != -1 &&1257submit->perf_query_pass != perf_pass)1258return false;12591260return true;1261}12621263static bool1264anv_queue_submit_can_add_submit(const struct anv_queue_submit *submit,1265uint32_t n_wait_semaphores,1266uint32_t n_signal_semaphores,1267int perf_pass)1268{1269/* We can add to an empty anv_queue_submit. */1270if (submit->cmd_buffer_count == 0 &&1271submit->fence_count == 0 &&1272submit->sync_fd_semaphore_count == 0 &&1273submit->wait_timeline_count == 0 &&1274submit->signal_timeline_count == 0 &&1275submit->fence_bo_count == 0)1276return true;12771278/* Different perf passes will require different EXECBUF ioctls. */1279if (perf_pass != submit->perf_query_pass)1280return false;12811282/* If the current submit is signaling anything, we can't add anything. */1283if (submit->signal_timeline_count ||1284submit->sync_fd_semaphore_count)1285return false;12861287/* If a submit is waiting on anything, anything that happened before needs1288* to be submitted.1289*/1290if (n_wait_semaphores)1291return false;12921293return true;1294}12951296static VkResult1297anv_queue_submit_post_and_alloc_new(struct anv_queue *queue,1298struct anv_queue_submit **submit)1299{1300VkResult result = anv_queue_submit_post(queue, submit, false);1301if (result != VK_SUCCESS)1302return result;13031304*submit = anv_queue_submit_alloc(queue->device);1305if (!*submit)1306return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);1307return VK_SUCCESS;1308}13091310VkResult anv_QueueSubmit(1311VkQueue _queue,1312uint32_t submitCount,1313const VkSubmitInfo* pSubmits,1314VkFence _fence)1315{1316ANV_FROM_HANDLE(anv_queue, queue, _queue);1317ANV_FROM_HANDLE(anv_fence, fence, _fence);1318struct anv_device *device = queue->device;13191320if (device->no_hw)1321return VK_SUCCESS;13221323/* Query for device status prior to submitting. Technically, we don't need1324* to do this. However, if we have a client that's submitting piles of1325* garbage, we would rather break as early as possible to keep the GPU1326* hanging contained. If we don't check here, we'll either be waiting for1327* the kernel to kick us or we'll have to wait until the client waits on a1328* fence before we actually know whether or not we've hung.1329*/1330VkResult result = anv_device_query_status(device);1331if (result != VK_SUCCESS)1332return result;13331334struct anv_queue_submit *submit = anv_queue_submit_alloc(device);1335if (!submit)1336return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);13371338for (uint32_t i = 0; i < submitCount; i++) {1339const struct wsi_memory_signal_submit_info *mem_signal_info =1340vk_find_struct_const(pSubmits[i].pNext,1341WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);1342struct anv_bo *wsi_signal_bo =1343mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ?1344anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL;13451346const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =1347vk_find_struct_const(pSubmits[i].pNext,1348TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);1349const VkPerformanceQuerySubmitInfoKHR *perf_info =1350vk_find_struct_const(pSubmits[i].pNext,1351PERFORMANCE_QUERY_SUBMIT_INFO_KHR);1352const int perf_pass = perf_info ? perf_info->counterPassIndex : 0;1353const uint64_t *wait_values =1354timeline_info && timeline_info->waitSemaphoreValueCount ?1355timeline_info->pWaitSemaphoreValues : NULL;1356const uint64_t *signal_values =1357timeline_info && timeline_info->signalSemaphoreValueCount ?1358timeline_info->pSignalSemaphoreValues : NULL;13591360if (!anv_queue_submit_can_add_submit(submit,1361pSubmits[i].waitSemaphoreCount,1362pSubmits[i].signalSemaphoreCount,1363perf_pass)) {1364result = anv_queue_submit_post_and_alloc_new(queue, &submit);1365if (result != VK_SUCCESS)1366goto out;1367}13681369/* Wait semaphores */1370result = anv_queue_submit_add_in_semaphores(submit,1371device,1372pSubmits[i].pWaitSemaphores,1373wait_values,1374pSubmits[i].waitSemaphoreCount);1375if (result != VK_SUCCESS)1376goto out;13771378/* Command buffers */1379for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {1380ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,1381pSubmits[i].pCommandBuffers[j]);1382assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);1383assert(!anv_batch_has_error(&cmd_buffer->batch));1384anv_measure_submit(cmd_buffer);13851386/* If we can't add an additional command buffer to the existing1387* anv_queue_submit, post it and create a new one.1388*/1389if (!anv_queue_submit_can_add_cmd_buffer(submit, cmd_buffer, perf_pass)) {1390result = anv_queue_submit_post_and_alloc_new(queue, &submit);1391if (result != VK_SUCCESS)1392goto out;1393}13941395result = anv_queue_submit_add_cmd_buffer(submit, cmd_buffer, perf_pass);1396if (result != VK_SUCCESS)1397goto out;1398}13991400/* Signal semaphores */1401result = anv_queue_submit_add_out_semaphores(submit,1402device,1403pSubmits[i].pSignalSemaphores,1404signal_values,1405pSubmits[i].signalSemaphoreCount);1406if (result != VK_SUCCESS)1407goto out;14081409/* WSI BO */1410if (wsi_signal_bo) {1411result = anv_queue_submit_add_fence_bo(submit, wsi_signal_bo,1412true /* signal */);1413if (result != VK_SUCCESS)1414goto out;1415}1416}14171418if (fence) {1419result = anv_queue_submit_add_fence(submit, device, fence);1420if (result != VK_SUCCESS)1421goto out;1422}14231424result = anv_queue_submit_post(queue, &submit, false);1425if (result != VK_SUCCESS)1426goto out;14271428if (fence)1429anv_post_queue_fence_update(device, fence);14301431out:1432if (submit)1433anv_queue_submit_free(device, submit);14341435if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {1436/* In the case that something has gone wrong we may end up with an1437* inconsistent state from which it may not be trivial to recover.1438* For example, we might have computed address relocations and1439* any future attempt to re-submit this job will need to know about1440* this and avoid computing relocation addresses again.1441*1442* To avoid this sort of issues, we assume that if something was1443* wrong during submission we must already be in a really bad situation1444* anyway (such us being out of memory) and return1445* VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to1446* submit the same job again to this device.1447*1448* We skip doing this on VK_ERROR_DEVICE_LOST because1449* anv_device_set_lost() would have been called already by a callee of1450* anv_queue_submit().1451*/1452result = anv_device_set_lost(device, "vkQueueSubmit() failed");1453}14541455return result;1456}14571458VkResult anv_QueueWaitIdle(1459VkQueue _queue)1460{1461ANV_FROM_HANDLE(anv_queue, queue, _queue);14621463if (anv_device_is_lost(queue->device))1464return VK_ERROR_DEVICE_LOST;14651466return anv_queue_submit_simple_batch(queue, NULL);1467}14681469VkResult anv_CreateFence(1470VkDevice _device,1471const VkFenceCreateInfo* pCreateInfo,1472const VkAllocationCallbacks* pAllocator,1473VkFence* pFence)1474{1475ANV_FROM_HANDLE(anv_device, device, _device);1476struct anv_fence *fence;14771478assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);14791480fence = vk_object_zalloc(&device->vk, pAllocator, sizeof(*fence),1481VK_OBJECT_TYPE_FENCE);1482if (fence == NULL)1483return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);14841485if (device->physical->has_syncobj_wait) {1486fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;14871488uint32_t create_flags = 0;1489if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)1490create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;14911492fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);1493if (!fence->permanent.syncobj)1494return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);1495} else {1496fence->permanent.type = ANV_FENCE_TYPE_BO;14971498VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,1499&fence->permanent.bo.bo);1500if (result != VK_SUCCESS)1501return result;15021503if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {1504fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;1505} else {1506fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;1507}1508}15091510*pFence = anv_fence_to_handle(fence);15111512return VK_SUCCESS;1513}15141515static void1516anv_fence_impl_cleanup(struct anv_device *device,1517struct anv_fence_impl *impl)1518{1519switch (impl->type) {1520case ANV_FENCE_TYPE_NONE:1521/* Dummy. Nothing to do */1522break;15231524case ANV_FENCE_TYPE_BO:1525anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);1526break;15271528case ANV_FENCE_TYPE_WSI_BO:1529anv_device_release_bo(device, impl->bo.bo);1530break;15311532case ANV_FENCE_TYPE_SYNCOBJ:1533anv_gem_syncobj_destroy(device, impl->syncobj);1534break;15351536case ANV_FENCE_TYPE_WSI:1537impl->fence_wsi->destroy(impl->fence_wsi);1538break;15391540default:1541unreachable("Invalid fence type");1542}15431544impl->type = ANV_FENCE_TYPE_NONE;1545}15461547void1548anv_fence_reset_temporary(struct anv_device *device,1549struct anv_fence *fence)1550{1551if (fence->temporary.type == ANV_FENCE_TYPE_NONE)1552return;15531554anv_fence_impl_cleanup(device, &fence->temporary);1555}15561557void anv_DestroyFence(1558VkDevice _device,1559VkFence _fence,1560const VkAllocationCallbacks* pAllocator)1561{1562ANV_FROM_HANDLE(anv_device, device, _device);1563ANV_FROM_HANDLE(anv_fence, fence, _fence);15641565if (!fence)1566return;15671568anv_fence_impl_cleanup(device, &fence->temporary);1569anv_fence_impl_cleanup(device, &fence->permanent);15701571vk_object_free(&device->vk, pAllocator, fence);1572}15731574VkResult anv_ResetFences(1575VkDevice _device,1576uint32_t fenceCount,1577const VkFence* pFences)1578{1579ANV_FROM_HANDLE(anv_device, device, _device);15801581for (uint32_t i = 0; i < fenceCount; i++) {1582ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);15831584/* From the Vulkan 1.0.53 spec:1585*1586* "If any member of pFences currently has its payload imported with1587* temporary permanence, that fence’s prior permanent payload is1588* first restored. The remaining operations described therefore1589* operate on the restored payload.1590*/1591anv_fence_reset_temporary(device, fence);15921593struct anv_fence_impl *impl = &fence->permanent;15941595switch (impl->type) {1596case ANV_FENCE_TYPE_BO:1597impl->bo.state = ANV_BO_FENCE_STATE_RESET;1598break;15991600case ANV_FENCE_TYPE_SYNCOBJ:1601anv_gem_syncobj_reset(device, impl->syncobj);1602break;16031604default:1605unreachable("Invalid fence type");1606}1607}16081609return VK_SUCCESS;1610}16111612VkResult anv_GetFenceStatus(1613VkDevice _device,1614VkFence _fence)1615{1616ANV_FROM_HANDLE(anv_device, device, _device);1617ANV_FROM_HANDLE(anv_fence, fence, _fence);16181619if (anv_device_is_lost(device))1620return VK_ERROR_DEVICE_LOST;16211622struct anv_fence_impl *impl =1623fence->temporary.type != ANV_FENCE_TYPE_NONE ?1624&fence->temporary : &fence->permanent;16251626switch (impl->type) {1627case ANV_FENCE_TYPE_BO:1628case ANV_FENCE_TYPE_WSI_BO:1629switch (impl->bo.state) {1630case ANV_BO_FENCE_STATE_RESET:1631/* If it hasn't even been sent off to the GPU yet, it's not ready */1632return VK_NOT_READY;16331634case ANV_BO_FENCE_STATE_SIGNALED:1635/* It's been signaled, return success */1636return VK_SUCCESS;16371638case ANV_BO_FENCE_STATE_SUBMITTED: {1639VkResult result = anv_device_bo_busy(device, impl->bo.bo);1640if (result == VK_SUCCESS) {1641impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;1642return VK_SUCCESS;1643} else {1644return result;1645}1646}1647default:1648unreachable("Invalid fence status");1649}16501651case ANV_FENCE_TYPE_SYNCOBJ: {1652if (device->has_thread_submit) {1653uint64_t binary_value = 0;1654int ret = anv_gem_syncobj_timeline_wait(device, &impl->syncobj,1655&binary_value, 1, 0,1656true /* wait_all */,1657false /* wait_materialize */);1658if (ret == -1) {1659if (errno == ETIME) {1660return VK_NOT_READY;1661} else {1662/* We don't know the real error. */1663return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");1664}1665} else {1666return VK_SUCCESS;1667}1668} else {1669int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, false);1670if (ret == -1) {1671if (errno == ETIME) {1672return VK_NOT_READY;1673} else {1674/* We don't know the real error. */1675return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");1676}1677} else {1678return VK_SUCCESS;1679}1680}1681}16821683default:1684unreachable("Invalid fence type");1685}1686}16871688static VkResult1689anv_wait_for_syncobj_fences(struct anv_device *device,1690uint32_t fenceCount,1691const VkFence *pFences,1692bool waitAll,1693uint64_t abs_timeout_ns)1694{1695uint32_t *syncobjs = vk_zalloc(&device->vk.alloc,1696sizeof(*syncobjs) * fenceCount, 8,1697VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);1698if (!syncobjs)1699return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);17001701for (uint32_t i = 0; i < fenceCount; i++) {1702ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);1703assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);17041705struct anv_fence_impl *impl =1706fence->temporary.type != ANV_FENCE_TYPE_NONE ?1707&fence->temporary : &fence->permanent;17081709assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);1710syncobjs[i] = impl->syncobj;1711}17121713int ret = 0;1714/* The gem_syncobj_wait ioctl may return early due to an inherent1715* limitation in the way it computes timeouts. Loop until we've actually1716* passed the timeout.1717*/1718do {1719ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,1720abs_timeout_ns, waitAll);1721} while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);17221723vk_free(&device->vk.alloc, syncobjs);17241725if (ret == -1) {1726if (errno == ETIME) {1727return VK_TIMEOUT;1728} else {1729/* We don't know the real error. */1730return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");1731}1732} else {1733return VK_SUCCESS;1734}1735}17361737static VkResult1738anv_wait_for_bo_fences(struct anv_device *device,1739uint32_t fenceCount,1740const VkFence *pFences,1741bool waitAll,1742uint64_t abs_timeout_ns)1743{1744VkResult result = VK_SUCCESS;1745uint32_t pending_fences = fenceCount;1746while (pending_fences) {1747pending_fences = 0;1748bool signaled_fences = false;1749for (uint32_t i = 0; i < fenceCount; i++) {1750ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);17511752struct anv_fence_impl *impl =1753fence->temporary.type != ANV_FENCE_TYPE_NONE ?1754&fence->temporary : &fence->permanent;1755assert(impl->type == ANV_FENCE_TYPE_BO ||1756impl->type == ANV_FENCE_TYPE_WSI_BO);17571758switch (impl->bo.state) {1759case ANV_BO_FENCE_STATE_RESET:1760/* This fence hasn't been submitted yet, we'll catch it the next1761* time around. Yes, this may mean we dead-loop but, short of1762* lots of locking and a condition variable, there's not much that1763* we can do about that.1764*/1765pending_fences++;1766continue;17671768case ANV_BO_FENCE_STATE_SIGNALED:1769/* This fence is not pending. If waitAll isn't set, we can return1770* early. Otherwise, we have to keep going.1771*/1772if (!waitAll) {1773result = VK_SUCCESS;1774goto done;1775}1776continue;17771778case ANV_BO_FENCE_STATE_SUBMITTED:1779/* These are the fences we really care about. Go ahead and wait1780* on it until we hit a timeout.1781*/1782result = anv_device_wait(device, impl->bo.bo,1783anv_get_relative_timeout(abs_timeout_ns));1784switch (result) {1785case VK_SUCCESS:1786impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;1787signaled_fences = true;1788if (!waitAll)1789goto done;1790break;17911792case VK_TIMEOUT:1793goto done;17941795default:1796return result;1797}1798}1799}18001801if (pending_fences && !signaled_fences) {1802/* If we've hit this then someone decided to vkWaitForFences before1803* they've actually submitted any of them to a queue. This is a1804* fairly pessimal case, so it's ok to lock here and use a standard1805* pthreads condition variable.1806*/1807pthread_mutex_lock(&device->mutex);18081809/* It's possible that some of the fences have changed state since the1810* last time we checked. Now that we have the lock, check for1811* pending fences again and don't wait if it's changed.1812*/1813uint32_t now_pending_fences = 0;1814for (uint32_t i = 0; i < fenceCount; i++) {1815ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);1816if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)1817now_pending_fences++;1818}1819assert(now_pending_fences <= pending_fences);18201821if (now_pending_fences == pending_fences) {1822struct timespec abstime = {1823.tv_sec = abs_timeout_ns / NSEC_PER_SEC,1824.tv_nsec = abs_timeout_ns % NSEC_PER_SEC,1825};18261827ASSERTED int ret;1828ret = pthread_cond_timedwait(&device->queue_submit,1829&device->mutex, &abstime);1830assert(ret != EINVAL);1831if (anv_gettime_ns() >= abs_timeout_ns) {1832pthread_mutex_unlock(&device->mutex);1833result = VK_TIMEOUT;1834goto done;1835}1836}18371838pthread_mutex_unlock(&device->mutex);1839}1840}18411842done:1843if (anv_device_is_lost(device))1844return VK_ERROR_DEVICE_LOST;18451846return result;1847}18481849static VkResult1850anv_wait_for_wsi_fence(struct anv_device *device,1851struct anv_fence_impl *impl,1852uint64_t abs_timeout)1853{1854return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);1855}18561857static VkResult1858anv_wait_for_fences(struct anv_device *device,1859uint32_t fenceCount,1860const VkFence *pFences,1861bool waitAll,1862uint64_t abs_timeout)1863{1864VkResult result = VK_SUCCESS;18651866if (fenceCount <= 1 || waitAll) {1867for (uint32_t i = 0; i < fenceCount; i++) {1868ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);1869struct anv_fence_impl *impl =1870fence->temporary.type != ANV_FENCE_TYPE_NONE ?1871&fence->temporary : &fence->permanent;18721873switch (impl->type) {1874case ANV_FENCE_TYPE_BO:1875assert(!device->physical->has_syncobj_wait);1876FALLTHROUGH;1877case ANV_FENCE_TYPE_WSI_BO:1878result = anv_wait_for_bo_fences(device, 1, &pFences[i],1879true, abs_timeout);1880break;1881case ANV_FENCE_TYPE_SYNCOBJ:1882result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],1883true, abs_timeout);1884break;1885case ANV_FENCE_TYPE_WSI:1886result = anv_wait_for_wsi_fence(device, impl, abs_timeout);1887break;1888case ANV_FENCE_TYPE_NONE:1889result = VK_SUCCESS;1890break;1891}1892if (result != VK_SUCCESS)1893return result;1894}1895} else {1896do {1897for (uint32_t i = 0; i < fenceCount; i++) {1898if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)1899return VK_SUCCESS;1900}1901} while (anv_gettime_ns() < abs_timeout);1902result = VK_TIMEOUT;1903}1904return result;1905}19061907static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)1908{1909for (uint32_t i = 0; i < fenceCount; ++i) {1910ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);1911struct anv_fence_impl *impl =1912fence->temporary.type != ANV_FENCE_TYPE_NONE ?1913&fence->temporary : &fence->permanent;1914if (impl->type != ANV_FENCE_TYPE_SYNCOBJ)1915return false;1916}1917return true;1918}19191920static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)1921{1922for (uint32_t i = 0; i < fenceCount; ++i) {1923ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);1924struct anv_fence_impl *impl =1925fence->temporary.type != ANV_FENCE_TYPE_NONE ?1926&fence->temporary : &fence->permanent;1927if (impl->type != ANV_FENCE_TYPE_BO &&1928impl->type != ANV_FENCE_TYPE_WSI_BO)1929return false;1930}1931return true;1932}19331934VkResult anv_WaitForFences(1935VkDevice _device,1936uint32_t fenceCount,1937const VkFence* pFences,1938VkBool32 waitAll,1939uint64_t timeout)1940{1941ANV_FROM_HANDLE(anv_device, device, _device);19421943if (device->no_hw)1944return VK_SUCCESS;19451946if (anv_device_is_lost(device))1947return VK_ERROR_DEVICE_LOST;19481949uint64_t abs_timeout = anv_get_absolute_timeout(timeout);1950if (anv_all_fences_syncobj(fenceCount, pFences)) {1951return anv_wait_for_syncobj_fences(device, fenceCount, pFences,1952waitAll, abs_timeout);1953} else if (anv_all_fences_bo(fenceCount, pFences)) {1954return anv_wait_for_bo_fences(device, fenceCount, pFences,1955waitAll, abs_timeout);1956} else {1957return anv_wait_for_fences(device, fenceCount, pFences,1958waitAll, abs_timeout);1959}1960}19611962void anv_GetPhysicalDeviceExternalFenceProperties(1963VkPhysicalDevice physicalDevice,1964const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,1965VkExternalFenceProperties* pExternalFenceProperties)1966{1967ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);19681969switch (pExternalFenceInfo->handleType) {1970case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:1971case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:1972if (device->has_syncobj_wait) {1973pExternalFenceProperties->exportFromImportedHandleTypes =1974VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |1975VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;1976pExternalFenceProperties->compatibleHandleTypes =1977VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |1978VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;1979pExternalFenceProperties->externalFenceFeatures =1980VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |1981VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;1982return;1983}1984break;19851986default:1987break;1988}19891990pExternalFenceProperties->exportFromImportedHandleTypes = 0;1991pExternalFenceProperties->compatibleHandleTypes = 0;1992pExternalFenceProperties->externalFenceFeatures = 0;1993}19941995VkResult anv_ImportFenceFdKHR(1996VkDevice _device,1997const VkImportFenceFdInfoKHR* pImportFenceFdInfo)1998{1999ANV_FROM_HANDLE(anv_device, device, _device);2000ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);2001int fd = pImportFenceFdInfo->fd;20022003assert(pImportFenceFdInfo->sType ==2004VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);20052006struct anv_fence_impl new_impl = {2007.type = ANV_FENCE_TYPE_NONE,2008};20092010switch (pImportFenceFdInfo->handleType) {2011case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:2012new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;20132014new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);2015if (!new_impl.syncobj)2016return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);20172018break;20192020case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {2021/* Sync files are a bit tricky. Because we want to continue using the2022* syncobj implementation of WaitForFences, we don't use the sync file2023* directly but instead import it into a syncobj.2024*/2025new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;20262027/* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the2028* special value -1 for fd is treated like a valid sync file descriptor2029* referring to an object that has already signaled. The import2030* operation will succeed and the VkFence will have a temporarily2031* imported payload as if a valid file descriptor had been provided."2032*/2033uint32_t create_flags = 0;2034if (fd == -1)2035create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;20362037new_impl.syncobj = anv_gem_syncobj_create(device, create_flags);2038if (!new_impl.syncobj)2039return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);20402041if (fd != -1 &&2042anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {2043anv_gem_syncobj_destroy(device, new_impl.syncobj);2044return vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,2045"syncobj sync file import failed: %m");2046}2047break;2048}20492050default:2051return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);2052}20532054/* From the Vulkan 1.0.53 spec:2055*2056* "Importing a fence payload from a file descriptor transfers2057* ownership of the file descriptor from the application to the2058* Vulkan implementation. The application must not perform any2059* operations on the file descriptor after a successful import."2060*2061* If the import fails, we leave the file descriptor open.2062*/2063if (fd != -1)2064close(fd);20652066if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {2067anv_fence_impl_cleanup(device, &fence->temporary);2068fence->temporary = new_impl;2069} else {2070anv_fence_impl_cleanup(device, &fence->permanent);2071fence->permanent = new_impl;2072}20732074return VK_SUCCESS;2075}20762077/* The sideband payload of the DRM syncobj was incremented when the2078* application called vkQueueSubmit(). Here we wait for a fence with the same2079* value to materialize so that we can exporting (typically as a SyncFD).2080*/2081static VkResult2082wait_syncobj_materialize(struct anv_device *device,2083uint32_t syncobj,2084int *fd)2085{2086if (!device->has_thread_submit)2087return VK_SUCCESS;20882089uint64_t binary_value = 0;2090/* We might need to wait until the fence materializes before we can2091* export to a sync FD when we use a thread for submission.2092*/2093if (anv_gem_syncobj_timeline_wait(device, &syncobj, &binary_value, 1,2094anv_get_absolute_timeout(5ull * NSEC_PER_SEC),2095true /* wait_all */,2096true /* wait_materialize */))2097return anv_device_set_lost(device, "anv_gem_syncobj_timeline_wait failed: %m");20982099return VK_SUCCESS;2100}21012102VkResult anv_GetFenceFdKHR(2103VkDevice _device,2104const VkFenceGetFdInfoKHR* pGetFdInfo,2105int* pFd)2106{2107ANV_FROM_HANDLE(anv_device, device, _device);2108ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);21092110assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);21112112struct anv_fence_impl *impl =2113fence->temporary.type != ANV_FENCE_TYPE_NONE ?2114&fence->temporary : &fence->permanent;21152116assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);2117switch (pGetFdInfo->handleType) {2118case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {2119int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);2120if (fd < 0)2121return vk_error(VK_ERROR_TOO_MANY_OBJECTS);21222123*pFd = fd;2124break;2125}21262127case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {2128VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);2129if (result != VK_SUCCESS)2130return result;21312132int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);2133if (fd < 0)2134return vk_error(VK_ERROR_TOO_MANY_OBJECTS);21352136*pFd = fd;2137break;2138}21392140default:2141unreachable("Invalid fence export handle type");2142}21432144/* From the Vulkan 1.0.53 spec:2145*2146* "Export operations have the same transference as the specified handle2147* type’s import operations. [...] If the fence was using a2148* temporarily imported payload, the fence’s prior permanent payload2149* will be restored.2150*/2151if (impl == &fence->temporary)2152anv_fence_impl_cleanup(device, impl);21532154return VK_SUCCESS;2155}21562157// Queue semaphore functions21582159static VkSemaphoreTypeKHR2160get_semaphore_type(const void *pNext, uint64_t *initial_value)2161{2162const VkSemaphoreTypeCreateInfoKHR *type_info =2163vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);21642165if (!type_info)2166return VK_SEMAPHORE_TYPE_BINARY_KHR;21672168if (initial_value)2169*initial_value = type_info->initialValue;2170return type_info->semaphoreType;2171}21722173static VkResult2174binary_semaphore_create(struct anv_device *device,2175struct anv_semaphore_impl *impl,2176bool exportable)2177{2178if (device->physical->has_syncobj) {2179impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;2180impl->syncobj = anv_gem_syncobj_create(device, 0);2181if (!impl->syncobj)2182return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);2183return VK_SUCCESS;2184} else {2185impl->type = ANV_SEMAPHORE_TYPE_BO;2186VkResult result =2187anv_device_alloc_bo(device, "binary-semaphore", 4096,2188ANV_BO_ALLOC_EXTERNAL |2189ANV_BO_ALLOC_IMPLICIT_SYNC,21900 /* explicit_address */,2191&impl->bo);2192/* If we're going to use this as a fence, we need to *not* have the2193* EXEC_OBJECT_ASYNC bit set.2194*/2195assert(!(impl->bo->flags & EXEC_OBJECT_ASYNC));2196return result;2197}2198}21992200static VkResult2201timeline_semaphore_create(struct anv_device *device,2202struct anv_semaphore_impl *impl,2203uint64_t initial_value)2204{2205if (device->has_thread_submit) {2206impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE;2207impl->syncobj = anv_gem_syncobj_create(device, 0);2208if (!impl->syncobj)2209return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);2210if (initial_value) {2211if (anv_gem_syncobj_timeline_signal(device,2212&impl->syncobj,2213&initial_value, 1)) {2214anv_gem_syncobj_destroy(device, impl->syncobj);2215return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);2216}2217}2218} else {2219impl->type = ANV_SEMAPHORE_TYPE_TIMELINE;2220anv_timeline_init(device, &impl->timeline, initial_value);2221}22222223return VK_SUCCESS;2224}22252226VkResult anv_CreateSemaphore(2227VkDevice _device,2228const VkSemaphoreCreateInfo* pCreateInfo,2229const VkAllocationCallbacks* pAllocator,2230VkSemaphore* pSemaphore)2231{2232ANV_FROM_HANDLE(anv_device, device, _device);2233struct anv_semaphore *semaphore;22342235assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);22362237uint64_t timeline_value = 0;2238VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);22392240semaphore = vk_object_alloc(&device->vk, NULL, sizeof(*semaphore),2241VK_OBJECT_TYPE_SEMAPHORE);2242if (semaphore == NULL)2243return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);22442245p_atomic_set(&semaphore->refcount, 1);22462247const VkExportSemaphoreCreateInfo *export =2248vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);2249VkExternalSemaphoreHandleTypeFlags handleTypes =2250export ? export->handleTypes : 0;2251VkResult result;22522253if (handleTypes == 0) {2254if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)2255result = binary_semaphore_create(device, &semaphore->permanent, false);2256else2257result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);2258if (result != VK_SUCCESS) {2259vk_object_free(&device->vk, pAllocator, semaphore);2260return result;2261}2262} else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {2263assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);2264if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)2265result = binary_semaphore_create(device, &semaphore->permanent, true);2266else2267result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);2268if (result != VK_SUCCESS) {2269vk_object_free(&device->vk, pAllocator, semaphore);2270return result;2271}2272} else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {2273assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);2274assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);2275if (device->physical->has_syncobj) {2276semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;2277semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);2278if (!semaphore->permanent.syncobj) {2279vk_object_free(&device->vk, pAllocator, semaphore);2280return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);2281}2282} else {2283semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;2284semaphore->permanent.fd = -1;2285}2286} else {2287assert(!"Unknown handle type");2288vk_object_free(&device->vk, pAllocator, semaphore);2289return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);2290}22912292semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;22932294*pSemaphore = anv_semaphore_to_handle(semaphore);22952296return VK_SUCCESS;2297}22982299static void2300anv_semaphore_impl_cleanup(struct anv_device *device,2301struct anv_semaphore_impl *impl)2302{2303switch (impl->type) {2304case ANV_SEMAPHORE_TYPE_NONE:2305case ANV_SEMAPHORE_TYPE_DUMMY:2306/* Dummy. Nothing to do */2307break;23082309case ANV_SEMAPHORE_TYPE_BO:2310case ANV_SEMAPHORE_TYPE_WSI_BO:2311anv_device_release_bo(device, impl->bo);2312break;23132314case ANV_SEMAPHORE_TYPE_SYNC_FILE:2315if (impl->fd >= 0)2316close(impl->fd);2317break;23182319case ANV_SEMAPHORE_TYPE_TIMELINE:2320anv_timeline_finish(device, &impl->timeline);2321break;23222323case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:2324case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:2325anv_gem_syncobj_destroy(device, impl->syncobj);2326break;23272328default:2329unreachable("Invalid semaphore type");2330}23312332impl->type = ANV_SEMAPHORE_TYPE_NONE;2333}23342335void2336anv_semaphore_reset_temporary(struct anv_device *device,2337struct anv_semaphore *semaphore)2338{2339if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)2340return;23412342anv_semaphore_impl_cleanup(device, &semaphore->temporary);2343}23442345static struct anv_semaphore *2346anv_semaphore_ref(struct anv_semaphore *semaphore)2347{2348assert(semaphore->refcount);2349p_atomic_inc(&semaphore->refcount);2350return semaphore;2351}23522353static void2354anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore)2355{2356if (!p_atomic_dec_zero(&semaphore->refcount))2357return;23582359anv_semaphore_impl_cleanup(device, &semaphore->temporary);2360anv_semaphore_impl_cleanup(device, &semaphore->permanent);23612362vk_object_free(&device->vk, NULL, semaphore);2363}23642365void anv_DestroySemaphore(2366VkDevice _device,2367VkSemaphore _semaphore,2368const VkAllocationCallbacks* pAllocator)2369{2370ANV_FROM_HANDLE(anv_device, device, _device);2371ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);23722373if (semaphore == NULL)2374return;23752376anv_semaphore_unref(device, semaphore);2377}23782379void anv_GetPhysicalDeviceExternalSemaphoreProperties(2380VkPhysicalDevice physicalDevice,2381const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,2382VkExternalSemaphoreProperties* pExternalSemaphoreProperties)2383{2384ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);23852386VkSemaphoreTypeKHR sem_type =2387get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);23882389switch (pExternalSemaphoreInfo->handleType) {2390case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:2391/* Timeline semaphores are not exportable, unless we have threaded2392* submission.2393*/2394if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && !device->has_thread_submit)2395break;2396pExternalSemaphoreProperties->exportFromImportedHandleTypes =2397VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;2398pExternalSemaphoreProperties->compatibleHandleTypes =2399VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;2400pExternalSemaphoreProperties->externalSemaphoreFeatures =2401VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |2402VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;2403return;24042405case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:2406if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)2407break;2408if (!device->has_exec_fence)2409break;2410pExternalSemaphoreProperties->exportFromImportedHandleTypes =2411VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;2412pExternalSemaphoreProperties->compatibleHandleTypes =2413VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;2414pExternalSemaphoreProperties->externalSemaphoreFeatures =2415VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |2416VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;2417return;24182419default:2420break;2421}24222423pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;2424pExternalSemaphoreProperties->compatibleHandleTypes = 0;2425pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;2426}24272428VkResult anv_ImportSemaphoreFdKHR(2429VkDevice _device,2430const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)2431{2432ANV_FROM_HANDLE(anv_device, device, _device);2433ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);2434int fd = pImportSemaphoreFdInfo->fd;24352436struct anv_semaphore_impl new_impl = {2437.type = ANV_SEMAPHORE_TYPE_NONE,2438};24392440switch (pImportSemaphoreFdInfo->handleType) {2441case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:2442if (device->physical->has_syncobj) {2443/* When importing non temporarily, reuse the semaphore's existing2444* type. The Linux/DRM implementation allows to interchangeably use2445* binary & timeline semaphores and we have no way to differenciate2446* them.2447*/2448if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT)2449new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;2450else2451new_impl.type = semaphore->permanent.type;24522453new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);2454if (!new_impl.syncobj)2455return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);2456} else {2457new_impl.type = ANV_SEMAPHORE_TYPE_BO;24582459VkResult result = anv_device_import_bo(device, fd,2460ANV_BO_ALLOC_EXTERNAL |2461ANV_BO_ALLOC_IMPLICIT_SYNC,24620 /* client_address */,2463&new_impl.bo);2464if (result != VK_SUCCESS)2465return result;24662467if (new_impl.bo->size < 4096) {2468anv_device_release_bo(device, new_impl.bo);2469return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);2470}24712472/* If we're going to use this as a fence, we need to *not* have the2473* EXEC_OBJECT_ASYNC bit set.2474*/2475assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));2476}24772478/* From the Vulkan spec:2479*2480* "Importing semaphore state from a file descriptor transfers2481* ownership of the file descriptor from the application to the2482* Vulkan implementation. The application must not perform any2483* operations on the file descriptor after a successful import."2484*2485* If the import fails, we leave the file descriptor open.2486*/2487close(fd);2488break;24892490case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:2491if (device->physical->has_syncobj) {2492uint32_t create_flags = 0;24932494if (fd == -1)2495create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;24962497new_impl = (struct anv_semaphore_impl) {2498.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,2499.syncobj = anv_gem_syncobj_create(device, create_flags),2500};25012502if (!new_impl.syncobj)2503return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);25042505if (fd != -1) {2506if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {2507anv_gem_syncobj_destroy(device, new_impl.syncobj);2508return vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,2509"syncobj sync file import failed: %m");2510}2511/* Ownership of the FD is transfered to Anv. Since we don't need it2512* anymore because the associated fence has been put into a syncobj,2513* we must close the FD.2514*/2515close(fd);2516}2517} else {2518new_impl = (struct anv_semaphore_impl) {2519.type = ANV_SEMAPHORE_TYPE_SYNC_FILE,2520.fd = fd,2521};2522}2523break;25242525default:2526return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);2527}25282529if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {2530anv_semaphore_impl_cleanup(device, &semaphore->temporary);2531semaphore->temporary = new_impl;2532} else {2533anv_semaphore_impl_cleanup(device, &semaphore->permanent);2534semaphore->permanent = new_impl;2535}25362537return VK_SUCCESS;2538}25392540VkResult anv_GetSemaphoreFdKHR(2541VkDevice _device,2542const VkSemaphoreGetFdInfoKHR* pGetFdInfo,2543int* pFd)2544{2545ANV_FROM_HANDLE(anv_device, device, _device);2546ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);2547VkResult result;2548int fd;25492550assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);25512552struct anv_semaphore_impl *impl =2553semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?2554&semaphore->temporary : &semaphore->permanent;25552556switch (impl->type) {2557case ANV_SEMAPHORE_TYPE_BO:2558result = anv_device_export_bo(device, impl->bo, pFd);2559if (result != VK_SUCCESS)2560return result;2561break;25622563case ANV_SEMAPHORE_TYPE_SYNC_FILE: {2564/* There's a potential race here with vkQueueSubmit if you are trying2565* to export a semaphore Fd while the queue submit is still happening.2566* This can happen if we see all dependencies get resolved via timeline2567* semaphore waits completing before the execbuf completes and we2568* process the resulting out fence. To work around this, take a lock2569* around grabbing the fd.2570*/2571pthread_mutex_lock(&device->mutex);25722573/* From the Vulkan 1.0.53 spec:2574*2575* "...exporting a semaphore payload to a handle with copy2576* transference has the same side effects on the source2577* semaphore’s payload as executing a semaphore wait operation."2578*2579* In other words, it may still be a SYNC_FD semaphore, but it's now2580* considered to have been waited on and no longer has a sync file2581* attached.2582*/2583int fd = impl->fd;2584impl->fd = -1;25852586pthread_mutex_unlock(&device->mutex);25872588/* There are two reasons why this could happen:2589*2590* 1) The user is trying to export without submitting something that2591* signals the semaphore. If this is the case, it's their bug so2592* what we return here doesn't matter.2593*2594* 2) The kernel didn't give us a file descriptor. The most likely2595* reason for this is running out of file descriptors.2596*/2597if (fd < 0)2598return vk_error(VK_ERROR_TOO_MANY_OBJECTS);25992600*pFd = fd;2601return VK_SUCCESS;2602}26032604case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:2605if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {2606VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);2607if (result != VK_SUCCESS)2608return result;26092610fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);2611} else {2612assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);2613fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);2614}2615if (fd < 0)2616return vk_error(VK_ERROR_TOO_MANY_OBJECTS);2617*pFd = fd;2618break;26192620case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:2621assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);2622fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);2623if (fd < 0)2624return vk_error(VK_ERROR_TOO_MANY_OBJECTS);2625*pFd = fd;2626break;26272628default:2629return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);2630}26312632/* From the Vulkan 1.0.53 spec:2633*2634* "Export operations have the same transference as the specified handle2635* type’s import operations. [...] If the semaphore was using a2636* temporarily imported payload, the semaphore’s prior permanent payload2637* will be restored.2638*/2639if (impl == &semaphore->temporary)2640anv_semaphore_impl_cleanup(device, impl);26412642return VK_SUCCESS;2643}26442645VkResult anv_GetSemaphoreCounterValue(2646VkDevice _device,2647VkSemaphore _semaphore,2648uint64_t* pValue)2649{2650ANV_FROM_HANDLE(anv_device, device, _device);2651ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);26522653struct anv_semaphore_impl *impl =2654semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?2655&semaphore->temporary : &semaphore->permanent;26562657switch (impl->type) {2658case ANV_SEMAPHORE_TYPE_TIMELINE: {2659pthread_mutex_lock(&device->mutex);2660anv_timeline_gc_locked(device, &impl->timeline);2661*pValue = impl->timeline.highest_past;2662pthread_mutex_unlock(&device->mutex);2663return VK_SUCCESS;2664}26652666case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {2667int ret = anv_gem_syncobj_timeline_query(device, &impl->syncobj, pValue, 1);26682669if (ret != 0)2670return anv_device_set_lost(device, "unable to query timeline syncobj");26712672return VK_SUCCESS;2673}26742675default:2676unreachable("Invalid semaphore type");2677}2678}26792680static VkResult2681anv_timeline_wait_locked(struct anv_device *device,2682struct anv_timeline *timeline,2683uint64_t serial, uint64_t abs_timeout_ns)2684{2685/* Wait on the queue_submit condition variable until the timeline has a2686* time point pending that's at least as high as serial.2687*/2688while (timeline->highest_pending < serial) {2689struct timespec abstime = {2690.tv_sec = abs_timeout_ns / NSEC_PER_SEC,2691.tv_nsec = abs_timeout_ns % NSEC_PER_SEC,2692};26932694UNUSED int ret = pthread_cond_timedwait(&device->queue_submit,2695&device->mutex, &abstime);2696assert(ret != EINVAL);2697if (anv_gettime_ns() >= abs_timeout_ns &&2698timeline->highest_pending < serial)2699return VK_TIMEOUT;2700}27012702while (1) {2703VkResult result = anv_timeline_gc_locked(device, timeline);2704if (result != VK_SUCCESS)2705return result;27062707if (timeline->highest_past >= serial)2708return VK_SUCCESS;27092710/* If we got here, our earliest time point has a busy BO */2711struct anv_timeline_point *point =2712list_first_entry(&timeline->points,2713struct anv_timeline_point, link);27142715/* Drop the lock while we wait. */2716point->waiting++;2717pthread_mutex_unlock(&device->mutex);27182719result = anv_device_wait(device, point->bo,2720anv_get_relative_timeout(abs_timeout_ns));27212722/* Pick the mutex back up */2723pthread_mutex_lock(&device->mutex);2724point->waiting--;27252726/* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */2727if (result != VK_SUCCESS)2728return result;2729}2730}27312732static VkResult2733anv_timelines_wait(struct anv_device *device,2734struct anv_timeline **timelines,2735const uint64_t *serials,2736uint32_t n_timelines,2737bool wait_all,2738uint64_t abs_timeout_ns)2739{2740if (!wait_all && n_timelines > 1) {2741pthread_mutex_lock(&device->mutex);27422743while (1) {2744VkResult result;2745for (uint32_t i = 0; i < n_timelines; i++) {2746result =2747anv_timeline_wait_locked(device, timelines[i], serials[i], 0);2748if (result != VK_TIMEOUT)2749break;2750}27512752if (result != VK_TIMEOUT ||2753anv_gettime_ns() >= abs_timeout_ns) {2754pthread_mutex_unlock(&device->mutex);2755return result;2756}27572758/* If none of them are ready do a short wait so we don't completely2759* spin while holding the lock. The 10us is completely arbitrary.2760*/2761uint64_t abs_short_wait_ns =2762anv_get_absolute_timeout(2763MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000));2764struct timespec abstime = {2765.tv_sec = abs_short_wait_ns / NSEC_PER_SEC,2766.tv_nsec = abs_short_wait_ns % NSEC_PER_SEC,2767};2768ASSERTED int ret;2769ret = pthread_cond_timedwait(&device->queue_submit,2770&device->mutex, &abstime);2771assert(ret != EINVAL);2772}2773} else {2774VkResult result = VK_SUCCESS;2775pthread_mutex_lock(&device->mutex);2776for (uint32_t i = 0; i < n_timelines; i++) {2777result =2778anv_timeline_wait_locked(device, timelines[i],2779serials[i], abs_timeout_ns);2780if (result != VK_SUCCESS)2781break;2782}2783pthread_mutex_unlock(&device->mutex);2784return result;2785}2786}27872788VkResult anv_WaitSemaphores(2789VkDevice _device,2790const VkSemaphoreWaitInfoKHR* pWaitInfo,2791uint64_t timeout)2792{2793ANV_FROM_HANDLE(anv_device, device, _device);2794uint32_t *handles;2795struct anv_timeline **timelines;27962797VK_MULTIALLOC(ma);27982799VK_MULTIALLOC_DECL(&ma, uint64_t, values, pWaitInfo->semaphoreCount);2800if (device->has_thread_submit) {2801vk_multialloc_add(&ma, &handles, uint32_t, pWaitInfo->semaphoreCount);2802} else {2803vk_multialloc_add(&ma, &timelines, struct anv_timeline *,2804pWaitInfo->semaphoreCount);2805}28062807if (!vk_multialloc_alloc(&ma, &device->vk.alloc,2808VK_SYSTEM_ALLOCATION_SCOPE_COMMAND))2809return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);28102811uint32_t handle_count = 0;2812for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {2813ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]);2814struct anv_semaphore_impl *impl =2815semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?2816&semaphore->temporary : &semaphore->permanent;28172818if (pWaitInfo->pValues[i] == 0)2819continue;28202821if (device->has_thread_submit) {2822assert(impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE);2823handles[handle_count] = impl->syncobj;2824} else {2825assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE);2826timelines[handle_count] = &impl->timeline;2827}2828values[handle_count] = pWaitInfo->pValues[i];2829handle_count++;2830}28312832VkResult result = VK_SUCCESS;2833if (handle_count > 0) {2834if (device->has_thread_submit) {2835int ret =2836anv_gem_syncobj_timeline_wait(device,2837handles, values, handle_count,2838anv_get_absolute_timeout(timeout),2839!(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),2840false);2841if (ret != 0)2842result = errno == ETIME ? VK_TIMEOUT :2843anv_device_set_lost(device, "unable to wait on timeline syncobj");2844} else {2845result =2846anv_timelines_wait(device, timelines, values, handle_count,2847!(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),2848anv_get_absolute_timeout(timeout));2849}2850}28512852vk_free(&device->vk.alloc, values);28532854return result;2855}28562857VkResult anv_SignalSemaphore(2858VkDevice _device,2859const VkSemaphoreSignalInfoKHR* pSignalInfo)2860{2861ANV_FROM_HANDLE(anv_device, device, _device);2862ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore);28632864struct anv_semaphore_impl *impl =2865semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?2866&semaphore->temporary : &semaphore->permanent;28672868switch (impl->type) {2869case ANV_SEMAPHORE_TYPE_TIMELINE: {2870pthread_mutex_lock(&device->mutex);28712872VkResult result = anv_timeline_gc_locked(device, &impl->timeline);28732874assert(pSignalInfo->value > impl->timeline.highest_pending);28752876impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value;28772878if (result == VK_SUCCESS)2879result = anv_device_submit_deferred_locked(device);28802881pthread_cond_broadcast(&device->queue_submit);2882pthread_mutex_unlock(&device->mutex);2883return result;2884}28852886case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {2887/* Timeline semaphores are created with a value of 0, so signaling on 02888* is a waste of time.2889*/2890if (pSignalInfo->value == 0)2891return VK_SUCCESS;28922893int ret = anv_gem_syncobj_timeline_signal(device, &impl->syncobj,2894&pSignalInfo->value, 1);28952896return ret == 0 ? VK_SUCCESS :2897anv_device_set_lost(device, "unable to signal timeline syncobj");2898}28992900default:2901unreachable("Invalid semaphore type");2902}2903}290429052906