2017-02-15 16:48:47 -08:00
|
|
|
|
/*
|
|
|
|
|
|
* Copyright © 2015 Intel Corporation
|
|
|
|
|
|
*
|
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
*
|
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
|
* Software.
|
|
|
|
|
|
*
|
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* This file implements VkQueue, VkFence, and VkSemaphore
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
#include <errno.h>
|
2017-02-15 17:25:46 -08:00
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
#include "anv_private.h"
|
2017-06-06 12:31:05 +01:00
|
|
|
|
#include "vk_util.h"
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
|
|
|
|
|
#include "genxml/gen7_pack.h"
|
|
|
|
|
|
|
2019-08-07 16:46:45 +03:00
|
|
|
|
uint64_t anv_gettime_ns(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct timespec current;
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, ¤t);
|
|
|
|
|
|
return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t anv_get_absolute_timeout(uint64_t timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (timeout == 0)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
uint64_t current_time = anv_gettime_ns();
|
|
|
|
|
|
uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
|
|
|
|
|
|
|
|
|
|
|
|
timeout = MIN2(max_timeout, timeout);
|
|
|
|
|
|
|
|
|
|
|
|
return (current_time + timeout);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int64_t anv_get_relative_timeout(uint64_t abs_timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint64_t now = anv_gettime_ns();
|
|
|
|
|
|
|
|
|
|
|
|
/* We don't want negative timeouts.
|
|
|
|
|
|
*
|
|
|
|
|
|
* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is
|
|
|
|
|
|
* supposed to block indefinitely timeouts < 0. Unfortunately,
|
|
|
|
|
|
* this was broken for a couple of kernel releases. Since there's
|
|
|
|
|
|
* no way to know whether or not the kernel we're using is one of
|
|
|
|
|
|
* the broken ones, the best we can do is to clamp the timeout to
|
|
|
|
|
|
* INT64_MAX. This limits the maximum timeout from 584 years to
|
|
|
|
|
|
* 292 years - likely not a big deal.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (abs_timeout < now)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t rel_timeout = abs_timeout - now;
|
|
|
|
|
|
if (rel_timeout > (uint64_t) INT64_MAX)
|
|
|
|
|
|
rel_timeout = INT64_MAX;
|
|
|
|
|
|
|
|
|
|
|
|
return rel_timeout;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
static struct anv_semaphore *anv_semaphore_ref(struct anv_semaphore *semaphore);
|
|
|
|
|
|
static void anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore);
|
|
|
|
|
|
static void anv_semaphore_impl_cleanup(struct anv_device *device,
|
|
|
|
|
|
struct anv_semaphore_impl *impl);
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
anv_queue_submit_free(struct anv_device *device,
|
|
|
|
|
|
struct anv_queue_submit *submit)
|
2017-02-15 16:48:47 -08:00
|
|
|
|
{
|
2019-09-30 12:30:20 +03:00
|
|
|
|
const VkAllocationCallbacks *alloc = submit->alloc;
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++)
|
|
|
|
|
|
anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]);
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++)
|
|
|
|
|
|
anv_semaphore_unref(device, submit->sync_fd_semaphores[i]);
|
|
|
|
|
|
/* Execbuf does not consume the in_fence. It's our job to close it. */
|
|
|
|
|
|
if (submit->in_fence != -1)
|
|
|
|
|
|
close(submit->in_fence);
|
|
|
|
|
|
if (submit->out_fence != -1)
|
|
|
|
|
|
close(submit->out_fence);
|
|
|
|
|
|
vk_free(alloc, submit->fences);
|
|
|
|
|
|
vk_free(alloc, submit->temporary_semaphores);
|
2018-10-16 17:44:31 -05:00
|
|
|
|
vk_free(alloc, submit->wait_timelines);
|
|
|
|
|
|
vk_free(alloc, submit->wait_timeline_values);
|
|
|
|
|
|
vk_free(alloc, submit->signal_timelines);
|
|
|
|
|
|
vk_free(alloc, submit->signal_timeline_values);
|
2019-09-30 12:30:20 +03:00
|
|
|
|
vk_free(alloc, submit->fence_bos);
|
|
|
|
|
|
vk_free(alloc, submit);
|
|
|
|
|
|
}
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
static bool
|
|
|
|
|
|
anv_queue_submit_ready_locked(struct anv_queue_submit *submit)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
|
|
|
|
|
|
if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
static VkResult
|
2018-10-16 17:44:31 -05:00
|
|
|
|
anv_timeline_init(struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline,
|
|
|
|
|
|
uint64_t initial_value)
|
2019-09-30 12:30:20 +03:00
|
|
|
|
{
|
2018-10-16 17:44:31 -05:00
|
|
|
|
timeline->highest_past =
|
|
|
|
|
|
timeline->highest_pending = initial_value;
|
|
|
|
|
|
list_inithead(&timeline->points);
|
|
|
|
|
|
list_inithead(&timeline->free_points);
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
anv_timeline_finish(struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline)
|
|
|
|
|
|
{
|
|
|
|
|
|
list_for_each_entry_safe(struct anv_timeline_point, point,
|
|
|
|
|
|
&timeline->free_points, link) {
|
|
|
|
|
|
list_del(&point->link);
|
|
|
|
|
|
anv_device_release_bo(device, point->bo);
|
|
|
|
|
|
vk_free(&device->alloc, point);
|
|
|
|
|
|
}
|
|
|
|
|
|
list_for_each_entry_safe(struct anv_timeline_point, point,
|
|
|
|
|
|
&timeline->points, link) {
|
|
|
|
|
|
list_del(&point->link);
|
|
|
|
|
|
anv_device_release_bo(device, point->bo);
|
|
|
|
|
|
vk_free(&device->alloc, point);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_timeline_add_point_locked(struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline,
|
|
|
|
|
|
uint64_t value,
|
|
|
|
|
|
struct anv_timeline_point **point)
|
|
|
|
|
|
{
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
if (list_is_empty(&timeline->free_points)) {
|
|
|
|
|
|
*point =
|
|
|
|
|
|
vk_zalloc(&device->alloc, sizeof(**point),
|
|
|
|
|
|
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
|
|
|
|
|
|
if (!(*point))
|
|
|
|
|
|
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
if (result == VK_SUCCESS) {
|
|
|
|
|
|
result = anv_device_alloc_bo(device, 4096,
|
|
|
|
|
|
ANV_BO_ALLOC_EXTERNAL |
|
|
|
|
|
|
ANV_BO_ALLOC_IMPLICIT_SYNC,
|
2019-12-02 15:22:38 -06:00
|
|
|
|
0 /* explicit_address */,
|
2018-10-16 17:44:31 -05:00
|
|
|
|
&(*point)->bo);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
vk_free(&device->alloc, *point);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
*point = list_first_entry(&timeline->free_points,
|
|
|
|
|
|
struct anv_timeline_point, link);
|
|
|
|
|
|
list_del(&(*point)->link);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (result == VK_SUCCESS) {
|
|
|
|
|
|
(*point)->serial = value;
|
|
|
|
|
|
list_addtail(&(*point)->link, &timeline->points);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_timeline_gc_locked(struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline)
|
|
|
|
|
|
{
|
|
|
|
|
|
list_for_each_entry_safe(struct anv_timeline_point, point,
|
|
|
|
|
|
&timeline->points, link) {
|
|
|
|
|
|
/* timeline->higest_pending is only incremented once submission has
|
|
|
|
|
|
* happened. If this point has a greater serial, it means the point
|
|
|
|
|
|
* hasn't been submitted yet.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (point->serial > timeline->highest_pending)
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
/* If someone is waiting on this time point, consider it busy and don't
|
|
|
|
|
|
* try to recycle it. There's a slim possibility that it's no longer
|
|
|
|
|
|
* busy by the time we look at it but we would be recycling it out from
|
|
|
|
|
|
* under a waiter and that can lead to weird races.
|
|
|
|
|
|
*
|
|
|
|
|
|
* We walk the list in-order so if this time point is still busy so is
|
|
|
|
|
|
* every following time point
|
|
|
|
|
|
*/
|
|
|
|
|
|
assert(point->waiting >= 0);
|
|
|
|
|
|
if (point->waiting)
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
/* Garbage collect any signaled point. */
|
|
|
|
|
|
VkResult result = anv_device_bo_busy(device, point->bo);
|
|
|
|
|
|
if (result == VK_NOT_READY) {
|
|
|
|
|
|
/* We walk the list in-order so if this time point is still busy so
|
|
|
|
|
|
* is every following time point
|
|
|
|
|
|
*/
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
} else if (result != VK_SUCCESS) {
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert(timeline->highest_past < point->serial);
|
|
|
|
|
|
timeline->highest_past = point->serial;
|
|
|
|
|
|
|
|
|
|
|
|
list_del(&point->link);
|
|
|
|
|
|
list_add(&point->link, &timeline->free_points);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
|
|
|
|
|
|
struct anv_bo *bo,
|
|
|
|
|
|
bool signal);
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_timeline_locked(struct anv_queue *queue,
|
|
|
|
|
|
struct anv_queue_submit *submit)
|
|
|
|
|
|
{
|
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
|
|
|
|
|
|
struct anv_timeline *timeline = submit->wait_timelines[i];
|
|
|
|
|
|
uint64_t wait_value = submit->wait_timeline_values[i];
|
|
|
|
|
|
|
|
|
|
|
|
if (timeline->highest_past >= wait_value)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) {
|
|
|
|
|
|
if (point->serial < wait_value)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
result = anv_queue_submit_add_fence_bo(submit, point->bo, false);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
|
|
|
|
|
|
struct anv_timeline *timeline = submit->signal_timelines[i];
|
|
|
|
|
|
uint64_t signal_value = submit->signal_timeline_values[i];
|
|
|
|
|
|
struct anv_timeline_point *point;
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_timeline_add_point_locked(queue->device, timeline,
|
|
|
|
|
|
signal_value, &point);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_queue_submit_add_fence_bo(submit, point->bo, true);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_queue_execbuf_locked(queue, submit);
|
2019-09-30 12:30:20 +03:00
|
|
|
|
|
|
|
|
|
|
if (result == VK_SUCCESS) {
|
2018-10-16 17:44:31 -05:00
|
|
|
|
/* Update the pending values in the timeline objects. */
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
|
|
|
|
|
|
struct anv_timeline *timeline = submit->signal_timelines[i];
|
|
|
|
|
|
uint64_t signal_value = submit->signal_timeline_values[i];
|
|
|
|
|
|
|
|
|
|
|
|
assert(signal_value > timeline->highest_pending);
|
|
|
|
|
|
timeline->highest_pending = signal_value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
/* Update signaled semaphores backed by syncfd. */
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {
|
|
|
|
|
|
struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];
|
|
|
|
|
|
/* Out fences can't have temporary state because that would imply
|
|
|
|
|
|
* that we imported a sync file and are trying to signal it.
|
|
|
|
|
|
*/
|
|
|
|
|
|
assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
|
|
|
|
|
|
struct anv_semaphore_impl *impl = &semaphore->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
|
|
|
|
|
|
impl->fd = dup(submit->out_fence);
|
|
|
|
|
|
}
|
2018-10-16 17:44:31 -05:00
|
|
|
|
} else {
|
|
|
|
|
|
/* Unblock any waiter by signaling the points, the application will get
|
|
|
|
|
|
* a device lost error code.
|
|
|
|
|
|
*/
|
|
|
|
|
|
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
|
|
|
|
|
|
struct anv_timeline *timeline = submit->signal_timelines[i];
|
|
|
|
|
|
uint64_t signal_value = submit->signal_timeline_values[i];
|
|
|
|
|
|
|
|
|
|
|
|
assert(signal_value > timeline->highest_pending);
|
|
|
|
|
|
timeline->highest_past = timeline->highest_pending = signal_value;
|
|
|
|
|
|
}
|
2018-06-01 14:05:53 -07:00
|
|
|
|
}
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
return result;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance)
|
|
|
|
|
|
{
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
/* Go through all the queued submissions and submit then until we find one
|
|
|
|
|
|
* that's waiting on a point that hasn't materialized yet.
|
|
|
|
|
|
*/
|
|
|
|
|
|
list_for_each_entry_safe(struct anv_queue_submit, submit,
|
|
|
|
|
|
&queue->queued_submits, link) {
|
|
|
|
|
|
if (!anv_queue_submit_ready_locked(submit))
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
(*advance)++;
|
|
|
|
|
|
list_del(&submit->link);
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_queue_submit_timeline_locked(queue, submit);
|
|
|
|
|
|
|
|
|
|
|
|
anv_queue_submit_free(queue->device, submit);
|
|
|
|
|
|
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_device_submit_deferred_locked(struct anv_device *device)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t advance = 0;
|
|
|
|
|
|
return anv_queue_submit_deferred_locked(&device->queue, &advance);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
_anv_queue_submit(struct anv_queue *queue, struct anv_queue_submit **_submit)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct anv_queue_submit *submit = *_submit;
|
|
|
|
|
|
|
|
|
|
|
|
/* Wait before signal behavior means we might keep alive the
|
|
|
|
|
|
* anv_queue_submit object a bit longer, so transfer the ownership to the
|
|
|
|
|
|
* anv_queue.
|
|
|
|
|
|
*/
|
|
|
|
|
|
*_submit = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&queue->device->mutex);
|
|
|
|
|
|
list_addtail(&submit->link, &queue->queued_submits);
|
|
|
|
|
|
VkResult result = anv_device_submit_deferred_locked(queue->device);
|
|
|
|
|
|
pthread_mutex_unlock(&queue->device->mutex);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-08-23 12:30:42 +02:00
|
|
|
|
VkResult
|
|
|
|
|
|
anv_queue_init(struct anv_device *device, struct anv_queue *queue)
|
|
|
|
|
|
{
|
|
|
|
|
|
queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
|
|
|
|
|
|
queue->device = device;
|
|
|
|
|
|
queue->flags = 0;
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
list_inithead(&queue->queued_submits);
|
|
|
|
|
|
|
2019-08-23 12:30:42 +02:00
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
anv_queue_finish(struct anv_queue *queue)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
|
|
|
|
|
|
struct anv_bo *bo,
|
|
|
|
|
|
bool signal)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (submit->fence_bo_count >= submit->fence_bo_array_length) {
|
|
|
|
|
|
uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64);
|
|
|
|
|
|
|
|
|
|
|
|
submit->fence_bos =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->fence_bos, new_len * sizeof(*submit->fence_bos),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (submit->fence_bos == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->fence_bo_array_length = new_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Take advantage that anv_bo are allocated at 8 byte alignement so we can
|
|
|
|
|
|
* use the lowest bit to store whether this is a BO we need to signal.
|
|
|
|
|
|
*/
|
|
|
|
|
|
submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal);
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_add_syncobj(struct anv_queue_submit* submit,
|
|
|
|
|
|
struct anv_device *device,
|
|
|
|
|
|
uint32_t handle, uint32_t flags)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert(flags != 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (submit->fence_count >= submit->fence_array_length) {
|
|
|
|
|
|
uint32_t new_len = MAX2(submit->fence_array_length * 2, 64);
|
|
|
|
|
|
|
|
|
|
|
|
submit->fences =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->fences, new_len * sizeof(*submit->fences),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (submit->fences == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->fence_array_length = new_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
submit->fences[submit->fence_count++] = (struct drm_i915_gem_exec_fence) {
|
|
|
|
|
|
.handle = handle,
|
|
|
|
|
|
.flags = flags,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_add_sync_fd_fence(struct anv_queue_submit *submit,
|
|
|
|
|
|
struct anv_semaphore *semaphore)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (submit->sync_fd_semaphore_count >= submit->sync_fd_semaphore_array_length) {
|
|
|
|
|
|
uint32_t new_len = MAX2(submit->sync_fd_semaphore_array_length * 2, 64);
|
|
|
|
|
|
struct anv_semaphore **new_semaphores =
|
|
|
|
|
|
vk_realloc(submit->alloc, submit->sync_fd_semaphores,
|
|
|
|
|
|
new_len * sizeof(*submit->sync_fd_semaphores), 8,
|
|
|
|
|
|
submit->alloc_scope);
|
|
|
|
|
|
if (new_semaphores == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->sync_fd_semaphores = new_semaphores;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
submit->sync_fd_semaphores[submit->sync_fd_semaphore_count++] =
|
|
|
|
|
|
anv_semaphore_ref(semaphore);
|
|
|
|
|
|
submit->need_out_fence = true;
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_add_timeline_wait(struct anv_queue_submit* submit,
|
|
|
|
|
|
struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline,
|
|
|
|
|
|
uint64_t value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
|
|
|
|
|
|
uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
|
|
|
|
|
|
|
|
|
|
|
|
submit->wait_timelines =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->wait_timelines, new_len * sizeof(*submit->wait_timelines),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (submit->wait_timelines == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->wait_timeline_values =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (submit->wait_timeline_values == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->wait_timeline_array_length = new_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
submit->wait_timelines[submit->wait_timeline_count] = timeline;
|
|
|
|
|
|
submit->wait_timeline_values[submit->wait_timeline_count] = value;
|
|
|
|
|
|
|
|
|
|
|
|
submit->wait_timeline_count++;
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit_add_timeline_signal(struct anv_queue_submit* submit,
|
|
|
|
|
|
struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline,
|
|
|
|
|
|
uint64_t value)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert(timeline->highest_pending < value);
|
|
|
|
|
|
|
|
|
|
|
|
if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {
|
|
|
|
|
|
uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64);
|
|
|
|
|
|
|
|
|
|
|
|
submit->signal_timelines =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->signal_timelines, new_len * sizeof(*submit->signal_timelines),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (submit->signal_timelines == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->signal_timeline_values =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (submit->signal_timeline_values == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->signal_timeline_array_length = new_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
submit->signal_timelines[submit->signal_timeline_count] = timeline;
|
|
|
|
|
|
submit->signal_timeline_values[submit->signal_timeline_count] = value;
|
|
|
|
|
|
|
|
|
|
|
|
submit->signal_timeline_count++;
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
static struct anv_queue_submit *
|
|
|
|
|
|
anv_queue_submit_alloc(struct anv_device *device)
|
|
|
|
|
|
{
|
|
|
|
|
|
const VkAllocationCallbacks *alloc = &device->alloc;
|
2018-10-16 17:44:31 -05:00
|
|
|
|
VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
|
2019-09-30 12:30:20 +03:00
|
|
|
|
|
|
|
|
|
|
struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope);
|
|
|
|
|
|
if (!submit)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
submit->alloc = alloc;
|
|
|
|
|
|
submit->alloc_scope = alloc_scope;
|
|
|
|
|
|
submit->in_fence = -1;
|
|
|
|
|
|
submit->out_fence = -1;
|
|
|
|
|
|
|
|
|
|
|
|
return submit;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
VkResult
|
2019-08-23 13:48:28 +02:00
|
|
|
|
anv_queue_submit_simple_batch(struct anv_queue *queue,
|
|
|
|
|
|
struct anv_batch *batch)
|
2017-02-15 16:48:47 -08:00
|
|
|
|
{
|
2019-08-23 13:48:28 +02:00
|
|
|
|
struct anv_device *device = queue->device;
|
2019-09-30 12:30:20 +03:00
|
|
|
|
struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
|
|
|
|
|
|
if (!submit)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
bool has_syncobj_wait = device->instance->physicalDevice.has_syncobj_wait;
|
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
uint32_t syncobj;
|
|
|
|
|
|
struct anv_bo *batch_bo, *sync_bo;
|
|
|
|
|
|
|
|
|
|
|
|
if (has_syncobj_wait) {
|
|
|
|
|
|
syncobj = anv_gem_syncobj_create(device, 0);
|
|
|
|
|
|
if (!syncobj) {
|
|
|
|
|
|
result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
|
|
|
|
goto err_free_submit;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_queue_submit_add_syncobj(submit, device, syncobj,
|
|
|
|
|
|
I915_EXEC_FENCE_SIGNAL);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
result = anv_device_alloc_bo(device, 4096,
|
|
|
|
|
|
ANV_BO_ALLOC_EXTERNAL |
|
|
|
|
|
|
ANV_BO_ALLOC_IMPLICIT_SYNC,
|
2019-12-02 15:22:38 -06:00
|
|
|
|
0 /* explicit_address */,
|
2019-09-30 12:30:20 +03:00
|
|
|
|
&sync_bo);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto err_free_submit;
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_queue_submit_add_fence_bo(submit, sync_bo, true /* signal */);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto err_destroy_sync_primitive;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2019-08-23 20:14:34 +03:00
|
|
|
|
if (batch) {
|
2019-09-30 12:30:20 +03:00
|
|
|
|
uint32_t size = align_u32(batch->next - batch->start, 8);
|
|
|
|
|
|
result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);
|
2019-08-23 20:14:34 +03:00
|
|
|
|
if (result != VK_SUCCESS)
|
2019-09-30 12:30:20 +03:00
|
|
|
|
goto err_destroy_sync_primitive;
|
2019-08-23 20:14:34 +03:00
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
memcpy(batch_bo->map, batch->start, size);
|
2019-08-23 20:14:34 +03:00
|
|
|
|
if (!device->info.has_llc)
|
2019-09-30 12:30:20 +03:00
|
|
|
|
gen_flush_range(batch_bo->map, size);
|
|
|
|
|
|
|
|
|
|
|
|
submit->simple_bo = batch_bo;
|
|
|
|
|
|
submit->simple_bo_size = size;
|
2019-08-23 20:14:34 +03:00
|
|
|
|
}
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
result = _anv_queue_submit(queue, &submit);
|
|
|
|
|
|
|
|
|
|
|
|
if (result == VK_SUCCESS) {
|
|
|
|
|
|
if (has_syncobj_wait) {
|
|
|
|
|
|
if (anv_gem_syncobj_wait(device, &syncobj, 1,
|
|
|
|
|
|
anv_get_absolute_timeout(INT64_MAX), true))
|
|
|
|
|
|
result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");
|
|
|
|
|
|
anv_gem_syncobj_destroy(device, syncobj);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
result = anv_device_wait(device, sync_bo,
|
|
|
|
|
|
anv_get_relative_timeout(INT64_MAX));
|
|
|
|
|
|
anv_device_release_bo(device, sync_bo);
|
|
|
|
|
|
}
|
2019-10-28 15:42:20 -05:00
|
|
|
|
}
|
2019-02-23 23:27:17 +00:00
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
if (batch)
|
|
|
|
|
|
anv_bo_pool_free(&device->batch_bo_pool, batch_bo);
|
|
|
|
|
|
|
|
|
|
|
|
if (submit)
|
|
|
|
|
|
anv_queue_submit_free(device, submit);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
|
|
err_destroy_sync_primitive:
|
|
|
|
|
|
if (has_syncobj_wait)
|
|
|
|
|
|
anv_gem_syncobj_destroy(device, syncobj);
|
|
|
|
|
|
else
|
|
|
|
|
|
anv_device_release_bo(device, sync_bo);
|
|
|
|
|
|
err_free_submit:
|
|
|
|
|
|
if (submit)
|
|
|
|
|
|
anv_queue_submit_free(device, submit);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Transfer ownership of temporary semaphores from the VkSemaphore object to
|
|
|
|
|
|
* the anv_queue_submit object. Those temporary semaphores are then freed in
|
|
|
|
|
|
* anv_queue_submit_free() once the driver is finished with them.
|
|
|
|
|
|
*/
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
maybe_transfer_temporary_semaphore(struct anv_queue_submit *submit,
|
|
|
|
|
|
struct anv_semaphore *semaphore,
|
|
|
|
|
|
struct anv_semaphore_impl **out_impl)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct anv_semaphore_impl *impl = &semaphore->temporary;
|
|
|
|
|
|
|
|
|
|
|
|
if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {
|
|
|
|
|
|
*out_impl = &semaphore->permanent;
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
/* BO backed timeline semaphores cannot be temporary. */
|
|
|
|
|
|
assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE);
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
/*
|
|
|
|
|
|
* There is a requirement to reset semaphore to their permanent state after
|
|
|
|
|
|
* submission. From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "If the import is temporary, the implementation must restore the
|
|
|
|
|
|
* semaphore to its prior permanent state after submitting the next
|
|
|
|
|
|
* semaphore wait operation."
|
|
|
|
|
|
*
|
|
|
|
|
|
* In the case we defer the actual submission to a thread because of the
|
|
|
|
|
|
* wait-before-submit behavior required for timeline semaphores, we need to
|
|
|
|
|
|
* make copies of the temporary syncobj to ensure they stay alive until we
|
|
|
|
|
|
* do the actual execbuffer ioctl.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {
|
|
|
|
|
|
uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);
|
|
|
|
|
|
/* Make sure that if the realloc fails, we still have the old semaphore
|
|
|
|
|
|
* array around to properly clean things up on failure.
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct anv_semaphore_impl *new_array =
|
|
|
|
|
|
vk_realloc(submit->alloc,
|
|
|
|
|
|
submit->temporary_semaphores,
|
|
|
|
|
|
new_len * sizeof(*submit->temporary_semaphores),
|
|
|
|
|
|
8, submit->alloc_scope);
|
|
|
|
|
|
if (new_array == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->temporary_semaphores = new_array;
|
|
|
|
|
|
submit->temporary_semaphore_array_length = new_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Copy anv_semaphore_impl into anv_queue_submit. */
|
|
|
|
|
|
submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;
|
|
|
|
|
|
*out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];
|
|
|
|
|
|
|
|
|
|
|
|
/* Clear the incoming semaphore */
|
|
|
|
|
|
impl->type = ANV_SEMAPHORE_TYPE_NONE;
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_queue_submit(struct anv_queue *queue,
|
|
|
|
|
|
struct anv_cmd_buffer *cmd_buffer,
|
|
|
|
|
|
const VkSemaphore *in_semaphores,
|
2018-10-16 15:58:14 -05:00
|
|
|
|
const uint64_t *in_values,
|
2019-09-30 12:30:20 +03:00
|
|
|
|
uint32_t num_in_semaphores,
|
|
|
|
|
|
const VkSemaphore *out_semaphores,
|
2018-10-16 15:58:14 -05:00
|
|
|
|
const uint64_t *out_values,
|
2019-09-30 12:30:20 +03:00
|
|
|
|
uint32_t num_out_semaphores,
|
|
|
|
|
|
VkFence _fence)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, _fence);
|
|
|
|
|
|
struct anv_device *device = queue->device;
|
|
|
|
|
|
UNUSED struct anv_physical_device *pdevice = &device->instance->physicalDevice;
|
|
|
|
|
|
struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
|
|
|
|
|
|
if (!submit)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
submit->cmd_buffer = cmd_buffer;
|
|
|
|
|
|
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < num_in_semaphores; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
|
|
|
|
|
|
struct anv_semaphore_impl *impl;
|
|
|
|
|
|
|
|
|
|
|
|
result = maybe_transfer_temporary_semaphore(submit, semaphore, &impl);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_BO:
|
|
|
|
|
|
assert(!pdevice->has_syncobj);
|
|
|
|
|
|
result = anv_queue_submit_add_fence_bo(submit, impl->bo, false /* signal */);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_SYNC_FILE:
|
|
|
|
|
|
assert(!pdevice->has_syncobj);
|
|
|
|
|
|
if (submit->in_fence == -1) {
|
|
|
|
|
|
submit->in_fence = impl->fd;
|
|
|
|
|
|
if (submit->in_fence == -1) {
|
|
|
|
|
|
result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
}
|
|
|
|
|
|
impl->fd = -1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
int merge = anv_gem_sync_file_merge(device, submit->in_fence, impl->fd);
|
|
|
|
|
|
if (merge == -1) {
|
|
|
|
|
|
result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
}
|
|
|
|
|
|
close(impl->fd);
|
|
|
|
|
|
close(submit->in_fence);
|
|
|
|
|
|
impl->fd = -1;
|
|
|
|
|
|
submit->in_fence = merge;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
|
|
|
|
|
|
result = anv_queue_submit_add_syncobj(submit, device,
|
|
|
|
|
|
impl->syncobj,
|
|
|
|
|
|
I915_EXEC_FENCE_WAIT);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
case ANV_SEMAPHORE_TYPE_TIMELINE:
|
|
|
|
|
|
result = anv_queue_submit_add_timeline_wait(submit, device,
|
|
|
|
|
|
&impl->timeline,
|
|
|
|
|
|
in_values ? in_values[i] : 0);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < num_out_semaphores; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
|
|
|
|
|
|
|
|
|
|
|
|
/* Under most circumstances, out fences won't be temporary. However,
|
|
|
|
|
|
* the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "If the import is temporary, the implementation must restore the
|
|
|
|
|
|
* semaphore to its prior permanent state after submitting the next
|
|
|
|
|
|
* semaphore wait operation."
|
|
|
|
|
|
*
|
|
|
|
|
|
* The spec says nothing whatsoever about signal operations on
|
|
|
|
|
|
* temporarily imported semaphores so it appears they are allowed.
|
|
|
|
|
|
* There are also CTS tests that require this to work.
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct anv_semaphore_impl *impl =
|
|
|
|
|
|
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
|
|
|
|
|
|
&semaphore->temporary : &semaphore->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_BO:
|
|
|
|
|
|
assert(!pdevice->has_syncobj);
|
|
|
|
|
|
result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_SYNC_FILE:
|
|
|
|
|
|
assert(!pdevice->has_syncobj);
|
|
|
|
|
|
result = anv_queue_submit_add_sync_fd_fence(submit, semaphore);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
|
|
|
|
|
|
result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
|
|
|
|
|
|
I915_EXEC_FENCE_SIGNAL);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
case ANV_SEMAPHORE_TYPE_TIMELINE:
|
|
|
|
|
|
result = anv_queue_submit_add_timeline_signal(submit, device,
|
|
|
|
|
|
&impl->timeline,
|
|
|
|
|
|
out_values ? out_values[i] : 0);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (fence) {
|
|
|
|
|
|
/* Under most circumstances, out fences won't be temporary. However,
|
|
|
|
|
|
* the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "If the import is temporary, the implementation must restore the
|
|
|
|
|
|
* semaphore to its prior permanent state after submitting the next
|
|
|
|
|
|
* semaphore wait operation."
|
|
|
|
|
|
*
|
|
|
|
|
|
* The spec says nothing whatsoever about signal operations on
|
|
|
|
|
|
* temporarily imported semaphores so it appears they are allowed.
|
|
|
|
|
|
* There are also CTS tests that require this to work.
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct anv_fence_impl *impl =
|
|
|
|
|
|
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
|
|
|
|
|
|
&fence->temporary : &fence->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_FENCE_TYPE_BO:
|
|
|
|
|
|
result = anv_queue_submit_add_fence_bo(submit, impl->bo.bo, true /* signal */);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ANV_FENCE_TYPE_SYNCOBJ: {
|
|
|
|
|
|
/*
|
|
|
|
|
|
* For the same reason we reset the signaled binary syncobj above,
|
|
|
|
|
|
* also reset the fence's syncobj so that they don't contain a
|
|
|
|
|
|
* signaled dma-fence.
|
|
|
|
|
|
*/
|
|
|
|
|
|
result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
|
|
|
|
|
|
I915_EXEC_FENCE_SIGNAL);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto error;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid fence type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = _anv_queue_submit(queue, &submit);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
if (result != VK_SUCCESS)
|
2019-09-30 12:30:20 +03:00
|
|
|
|
goto error;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
if (fence && fence->permanent.type == ANV_FENCE_TYPE_BO) {
|
|
|
|
|
|
/* BO fences can't be shared, so they can't be temporary. */
|
|
|
|
|
|
assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
/* Once the execbuf has returned, we need to set the fence state to
|
|
|
|
|
|
* SUBMITTED. We can't do this before calling execbuf because
|
|
|
|
|
|
* anv_GetFenceStatus does take the global device lock before checking
|
|
|
|
|
|
* fence->state.
|
|
|
|
|
|
*
|
|
|
|
|
|
* We set the fence state to SUBMITTED regardless of whether or not the
|
|
|
|
|
|
* execbuf succeeds because we need to ensure that vkWaitForFences() and
|
|
|
|
|
|
* vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
|
|
|
|
|
|
* VK_SUCCESS) in a finite amount of time even if execbuf fails.
|
|
|
|
|
|
*/
|
|
|
|
|
|
fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
|
if (submit)
|
|
|
|
|
|
anv_queue_submit_free(device, submit);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_QueueSubmit(
|
|
|
|
|
|
VkQueue _queue,
|
|
|
|
|
|
uint32_t submitCount,
|
|
|
|
|
|
const VkSubmitInfo* pSubmits,
|
2017-08-03 11:46:09 -07:00
|
|
|
|
VkFence fence)
|
2017-02-15 16:48:47 -08:00
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_queue, queue, _queue);
|
|
|
|
|
|
|
|
|
|
|
|
/* Query for device status prior to submitting. Technically, we don't need
|
|
|
|
|
|
* to do this. However, if we have a client that's submitting piles of
|
|
|
|
|
|
* garbage, we would rather break as early as possible to keep the GPU
|
|
|
|
|
|
* hanging contained. If we don't check here, we'll either be waiting for
|
|
|
|
|
|
* the kernel to kick us or we'll have to wait until the client waits on a
|
|
|
|
|
|
* fence before we actually know whether or not we've hung.
|
|
|
|
|
|
*/
|
2019-09-30 12:30:20 +03:00
|
|
|
|
VkResult result = anv_device_query_status(queue->device);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
2017-08-03 11:46:09 -07:00
|
|
|
|
if (fence && submitCount == 0) {
|
|
|
|
|
|
/* If we don't have any command buffers, we need to submit a dummy
|
|
|
|
|
|
* batch to give GEM something to wait on. We could, potentially,
|
|
|
|
|
|
* come up with something more efficient but this shouldn't be a
|
|
|
|
|
|
* common case.
|
|
|
|
|
|
*/
|
2018-10-16 15:58:14 -05:00
|
|
|
|
result = anv_queue_submit(queue, NULL, NULL, NULL, 0, NULL, NULL, 0, fence);
|
2017-08-03 11:46:09 -07:00
|
|
|
|
goto out;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
for (uint32_t i = 0; i < submitCount; i++) {
|
2017-08-03 11:46:09 -07:00
|
|
|
|
/* Fence for this submit. NULL for all but the last one */
|
2017-08-31 08:52:27 +03:00
|
|
|
|
VkFence submit_fence = (i == submitCount - 1) ? fence : VK_NULL_HANDLE;
|
2017-08-03 11:46:09 -07:00
|
|
|
|
|
2018-10-16 15:58:14 -05:00
|
|
|
|
const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =
|
|
|
|
|
|
vk_find_struct_const(pSubmits[i].pNext,
|
|
|
|
|
|
TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);
|
|
|
|
|
|
const uint64_t *wait_values =
|
|
|
|
|
|
timeline_info && timeline_info->waitSemaphoreValueCount ?
|
|
|
|
|
|
timeline_info->pWaitSemaphoreValues : NULL;
|
|
|
|
|
|
const uint64_t *signal_values =
|
|
|
|
|
|
timeline_info && timeline_info->signalSemaphoreValueCount ?
|
|
|
|
|
|
timeline_info->pSignalSemaphoreValues : NULL;
|
|
|
|
|
|
|
2017-02-27 16:34:13 -08:00
|
|
|
|
if (pSubmits[i].commandBufferCount == 0) {
|
|
|
|
|
|
/* If we don't have any command buffers, we need to submit a dummy
|
|
|
|
|
|
* batch to give GEM something to wait on. We could, potentially,
|
|
|
|
|
|
* come up with something more efficient but this shouldn't be a
|
|
|
|
|
|
* common case.
|
|
|
|
|
|
*/
|
2019-09-30 12:30:20 +03:00
|
|
|
|
result = anv_queue_submit(queue, NULL,
|
|
|
|
|
|
pSubmits[i].pWaitSemaphores,
|
2018-10-16 15:58:14 -05:00
|
|
|
|
wait_values,
|
2019-09-30 12:30:20 +03:00
|
|
|
|
pSubmits[i].waitSemaphoreCount,
|
|
|
|
|
|
pSubmits[i].pSignalSemaphores,
|
2018-10-16 15:58:14 -05:00
|
|
|
|
signal_values,
|
2019-09-30 12:30:20 +03:00
|
|
|
|
pSubmits[i].signalSemaphoreCount,
|
|
|
|
|
|
submit_fence);
|
2017-02-27 16:34:13 -08:00
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
|
|
|
|
|
|
pSubmits[i].pCommandBuffers[j]);
|
|
|
|
|
|
assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
|
|
|
|
|
|
assert(!anv_batch_has_error(&cmd_buffer->batch));
|
|
|
|
|
|
|
2017-08-03 11:46:09 -07:00
|
|
|
|
/* Fence for this execbuf. NULL for all but the last one */
|
|
|
|
|
|
VkFence execbuf_fence =
|
2017-08-31 08:52:27 +03:00
|
|
|
|
(j == pSubmits[i].commandBufferCount - 1) ?
|
|
|
|
|
|
submit_fence : VK_NULL_HANDLE;
|
2017-08-03 11:46:09 -07:00
|
|
|
|
|
2017-02-15 17:25:46 -08:00
|
|
|
|
const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
|
2018-10-16 15:58:14 -05:00
|
|
|
|
const uint64_t *in_values = NULL, *out_values = NULL;
|
2017-02-15 17:25:46 -08:00
|
|
|
|
uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
|
|
|
|
|
|
if (j == 0) {
|
|
|
|
|
|
/* Only the first batch gets the in semaphores */
|
|
|
|
|
|
in_semaphores = pSubmits[i].pWaitSemaphores;
|
2018-10-16 15:58:14 -05:00
|
|
|
|
in_values = wait_values;
|
2017-02-15 17:25:46 -08:00
|
|
|
|
num_in_semaphores = pSubmits[i].waitSemaphoreCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (j == pSubmits[i].commandBufferCount - 1) {
|
|
|
|
|
|
/* Only the last batch gets the out semaphores */
|
|
|
|
|
|
out_semaphores = pSubmits[i].pSignalSemaphores;
|
2018-10-16 15:58:14 -05:00
|
|
|
|
out_values = signal_values;
|
2017-02-15 17:25:46 -08:00
|
|
|
|
num_out_semaphores = pSubmits[i].signalSemaphoreCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-30 12:30:20 +03:00
|
|
|
|
result = anv_queue_submit(queue, cmd_buffer,
|
2018-10-16 15:58:14 -05:00
|
|
|
|
in_semaphores, in_values, num_in_semaphores,
|
|
|
|
|
|
out_semaphores, out_values, num_out_semaphores,
|
2019-09-30 12:30:20 +03:00
|
|
|
|
execbuf_fence);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
goto out;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
out:
|
2019-09-30 12:30:20 +03:00
|
|
|
|
if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {
|
2017-02-15 16:48:47 -08:00
|
|
|
|
/* In the case that something has gone wrong we may end up with an
|
|
|
|
|
|
* inconsistent state from which it may not be trivial to recover.
|
|
|
|
|
|
* For example, we might have computed address relocations and
|
|
|
|
|
|
* any future attempt to re-submit this job will need to know about
|
|
|
|
|
|
* this and avoid computing relocation addresses again.
|
|
|
|
|
|
*
|
|
|
|
|
|
* To avoid this sort of issues, we assume that if something was
|
|
|
|
|
|
* wrong during submission we must already be in a really bad situation
|
|
|
|
|
|
* anyway (such us being out of memory) and return
|
|
|
|
|
|
* VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
|
|
|
|
|
|
* submit the same job again to this device.
|
2019-09-30 12:30:20 +03:00
|
|
|
|
*
|
|
|
|
|
|
* We skip doing this on VK_ERROR_DEVICE_LOST because
|
|
|
|
|
|
* anv_device_set_lost() would have been called already by a callee of
|
|
|
|
|
|
* anv_queue_submit().
|
2017-02-15 16:48:47 -08:00
|
|
|
|
*/
|
2019-09-30 12:30:20 +03:00
|
|
|
|
result = anv_device_set_lost(queue->device, "vkQueueSubmit() failed");
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_QueueWaitIdle(
|
|
|
|
|
|
VkQueue _queue)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_queue, queue, _queue);
|
|
|
|
|
|
|
2019-08-23 13:48:28 +02:00
|
|
|
|
if (anv_device_is_lost(queue->device))
|
|
|
|
|
|
return VK_ERROR_DEVICE_LOST;
|
|
|
|
|
|
|
|
|
|
|
|
return anv_queue_submit_simple_batch(queue, NULL);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_CreateFence(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkFenceCreateInfo* pCreateInfo,
|
|
|
|
|
|
const VkAllocationCallbacks* pAllocator,
|
|
|
|
|
|
VkFence* pFence)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
struct anv_fence *fence;
|
|
|
|
|
|
|
|
|
|
|
|
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
fence = vk_zalloc2(&device->alloc, pAllocator, sizeof(*fence), 8,
|
|
|
|
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
|
|
|
|
if (fence == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
2017-08-04 13:08:35 -07:00
|
|
|
|
if (device->instance->physicalDevice.has_syncobj_wait) {
|
|
|
|
|
|
fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
|
2017-08-03 14:19:44 -07:00
|
|
|
|
|
2017-08-04 13:08:35 -07:00
|
|
|
|
uint32_t create_flags = 0;
|
|
|
|
|
|
if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
|
|
|
|
|
|
create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2017-08-04 13:08:35 -07:00
|
|
|
|
fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
|
|
|
|
|
|
if (!fence->permanent.syncobj)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
} else {
|
2017-08-04 13:08:35 -07:00
|
|
|
|
fence->permanent.type = ANV_FENCE_TYPE_BO;
|
|
|
|
|
|
|
2019-10-28 15:42:20 -05:00
|
|
|
|
VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,
|
|
|
|
|
|
&fence->permanent.bo.bo);
|
2017-08-04 13:08:35 -07:00
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
|
|
if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
|
|
|
|
|
|
fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
|
|
|
|
|
|
}
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
*pFence = anv_fence_to_handle(fence);
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
static void
|
|
|
|
|
|
anv_fence_impl_cleanup(struct anv_device *device,
|
|
|
|
|
|
struct anv_fence_impl *impl)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_FENCE_TYPE_NONE:
|
|
|
|
|
|
/* Dummy. Nothing to do */
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
2017-08-03 14:19:44 -07:00
|
|
|
|
|
|
|
|
|
|
case ANV_FENCE_TYPE_BO:
|
2019-10-28 15:42:20 -05:00
|
|
|
|
anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
2017-08-04 13:08:35 -07:00
|
|
|
|
|
|
|
|
|
|
case ANV_FENCE_TYPE_SYNCOBJ:
|
|
|
|
|
|
anv_gem_syncobj_destroy(device, impl->syncobj);
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
2017-06-15 21:00:56 -07:00
|
|
|
|
case ANV_FENCE_TYPE_WSI:
|
|
|
|
|
|
impl->fence_wsi->destroy(impl->fence_wsi);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2018-05-26 12:08:22 -07:00
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid fence type");
|
2017-08-03 14:19:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-26 12:08:22 -07:00
|
|
|
|
impl->type = ANV_FENCE_TYPE_NONE;
|
2017-08-03 14:19:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
void anv_DestroyFence(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
VkFence _fence,
|
|
|
|
|
|
const VkAllocationCallbacks* pAllocator)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, _fence);
|
|
|
|
|
|
|
|
|
|
|
|
if (!fence)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
anv_fence_impl_cleanup(device, &fence->temporary);
|
|
|
|
|
|
anv_fence_impl_cleanup(device, &fence->permanent);
|
|
|
|
|
|
|
|
|
|
|
|
vk_free2(&device->alloc, pAllocator, fence);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_ResetFences(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
uint32_t fenceCount,
|
|
|
|
|
|
const VkFence* pFences)
|
|
|
|
|
|
{
|
2017-08-04 13:08:35 -07:00
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
for (uint32_t i = 0; i < fenceCount; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
2017-08-03 14:19:44 -07:00
|
|
|
|
|
2017-08-08 12:25:38 -07:00
|
|
|
|
/* From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "If any member of pFences currently has its payload imported with
|
|
|
|
|
|
* temporary permanence, that fence’s prior permanent payload is
|
|
|
|
|
|
* first restored. The remaining operations described therefore
|
|
|
|
|
|
* operate on the restored payload.
|
|
|
|
|
|
*/
|
2018-05-26 12:08:22 -07:00
|
|
|
|
if (fence->temporary.type != ANV_FENCE_TYPE_NONE)
|
2017-08-08 12:25:38 -07:00
|
|
|
|
anv_fence_impl_cleanup(device, &fence->temporary);
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
struct anv_fence_impl *impl = &fence->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_FENCE_TYPE_BO:
|
2017-08-04 12:59:45 -07:00
|
|
|
|
impl->bo.state = ANV_BO_FENCE_STATE_RESET;
|
2017-08-03 14:19:44 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
2017-08-04 13:08:35 -07:00
|
|
|
|
case ANV_FENCE_TYPE_SYNCOBJ:
|
|
|
|
|
|
anv_gem_syncobj_reset(device, impl->syncobj);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid fence type");
|
|
|
|
|
|
}
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_GetFenceStatus(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
VkFence _fence)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, _fence);
|
|
|
|
|
|
|
2018-03-13 11:50:33 -07:00
|
|
|
|
if (anv_device_is_lost(device))
|
2017-02-15 16:48:47 -08:00
|
|
|
|
return VK_ERROR_DEVICE_LOST;
|
|
|
|
|
|
|
2017-08-08 12:25:38 -07:00
|
|
|
|
struct anv_fence_impl *impl =
|
|
|
|
|
|
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
|
|
|
|
|
|
&fence->temporary : &fence->permanent;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_FENCE_TYPE_BO:
|
2017-08-08 12:25:38 -07:00
|
|
|
|
/* BO fences don't support import/export */
|
|
|
|
|
|
assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
|
2017-08-03 14:19:44 -07:00
|
|
|
|
switch (impl->bo.state) {
|
2017-08-04 12:59:45 -07:00
|
|
|
|
case ANV_BO_FENCE_STATE_RESET:
|
2017-08-03 14:19:44 -07:00
|
|
|
|
/* If it hasn't even been sent off to the GPU yet, it's not ready */
|
|
|
|
|
|
return VK_NOT_READY;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2017-08-04 12:59:45 -07:00
|
|
|
|
case ANV_BO_FENCE_STATE_SIGNALED:
|
2017-08-03 14:19:44 -07:00
|
|
|
|
/* It's been signaled, return success */
|
2017-02-15 16:48:47 -08:00
|
|
|
|
return VK_SUCCESS;
|
2017-08-03 14:19:44 -07:00
|
|
|
|
|
2017-08-04 12:59:45 -07:00
|
|
|
|
case ANV_BO_FENCE_STATE_SUBMITTED: {
|
2019-10-28 15:42:20 -05:00
|
|
|
|
VkResult result = anv_device_bo_busy(device, impl->bo.bo);
|
2017-08-03 14:19:44 -07:00
|
|
|
|
if (result == VK_SUCCESS) {
|
2017-08-04 12:59:45 -07:00
|
|
|
|
impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
|
2017-08-03 14:19:44 -07:00
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
2017-08-03 14:19:44 -07:00
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid fence status");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-04 13:08:35 -07:00
|
|
|
|
case ANV_FENCE_TYPE_SYNCOBJ: {
|
|
|
|
|
|
int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
|
|
if (errno == ETIME) {
|
|
|
|
|
|
return VK_NOT_READY;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/* We don't know the real error. */
|
2018-10-26 08:32:39 -05:00
|
|
|
|
return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
|
2017-08-04 13:08:35 -07:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
default:
|
2017-08-03 14:19:44 -07:00
|
|
|
|
unreachable("Invalid fence type");
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-04 13:08:35 -07:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_wait_for_syncobj_fences(struct anv_device *device,
|
|
|
|
|
|
uint32_t fenceCount,
|
|
|
|
|
|
const VkFence *pFences,
|
|
|
|
|
|
bool waitAll,
|
2018-06-05 23:18:56 -06:00
|
|
|
|
uint64_t abs_timeout_ns)
|
2017-08-04 13:08:35 -07:00
|
|
|
|
{
|
|
|
|
|
|
uint32_t *syncobjs = vk_zalloc(&device->alloc,
|
|
|
|
|
|
sizeof(*syncobjs) * fenceCount, 8,
|
|
|
|
|
|
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
|
|
|
|
|
|
if (!syncobjs)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
|
|
|
|
|
assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_fence_impl *impl =
|
|
|
|
|
|
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
|
|
|
|
|
|
&fence->temporary : &fence->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
|
|
|
|
|
|
syncobjs[i] = impl->syncobj;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The gem_syncobj_wait ioctl may return early due to an inherent
|
|
|
|
|
|
* limitation in the way it computes timeouts. Loop until we've actually
|
|
|
|
|
|
* passed the timeout.
|
|
|
|
|
|
*/
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
do {
|
|
|
|
|
|
ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
|
|
|
|
|
|
abs_timeout_ns, waitAll);
|
2019-08-07 16:46:45 +03:00
|
|
|
|
} while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);
|
2017-08-04 13:08:35 -07:00
|
|
|
|
|
|
|
|
|
|
vk_free(&device->alloc, syncobjs);
|
|
|
|
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
|
|
if (errno == ETIME) {
|
|
|
|
|
|
return VK_TIMEOUT;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/* We don't know the real error. */
|
2018-10-26 08:32:39 -05:00
|
|
|
|
return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
|
2017-08-04 13:08:35 -07:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_wait_for_bo_fences(struct anv_device *device,
|
|
|
|
|
|
uint32_t fenceCount,
|
|
|
|
|
|
const VkFence *pFences,
|
|
|
|
|
|
bool waitAll,
|
2018-10-16 16:59:37 -05:00
|
|
|
|
uint64_t abs_timeout_ns)
|
2017-02-15 16:48:47 -08:00
|
|
|
|
{
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
uint32_t pending_fences = fenceCount;
|
|
|
|
|
|
while (pending_fences) {
|
|
|
|
|
|
pending_fences = 0;
|
|
|
|
|
|
bool signaled_fences = false;
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
2017-08-03 14:19:44 -07:00
|
|
|
|
|
|
|
|
|
|
/* This function assumes that all fences are BO fences and that they
|
|
|
|
|
|
* have no temporary state. Since BO fences will never be exported,
|
|
|
|
|
|
* this should be a safe assumption.
|
|
|
|
|
|
*/
|
|
|
|
|
|
assert(fence->permanent.type == ANV_FENCE_TYPE_BO);
|
|
|
|
|
|
assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
|
|
|
|
|
|
struct anv_fence_impl *impl = &fence->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->bo.state) {
|
2017-08-04 12:59:45 -07:00
|
|
|
|
case ANV_BO_FENCE_STATE_RESET:
|
2017-02-15 16:48:47 -08:00
|
|
|
|
/* This fence hasn't been submitted yet, we'll catch it the next
|
|
|
|
|
|
* time around. Yes, this may mean we dead-loop but, short of
|
|
|
|
|
|
* lots of locking and a condition variable, there's not much that
|
|
|
|
|
|
* we can do about that.
|
|
|
|
|
|
*/
|
|
|
|
|
|
pending_fences++;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2017-08-04 12:59:45 -07:00
|
|
|
|
case ANV_BO_FENCE_STATE_SIGNALED:
|
2017-02-15 16:48:47 -08:00
|
|
|
|
/* This fence is not pending. If waitAll isn't set, we can return
|
|
|
|
|
|
* early. Otherwise, we have to keep going.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (!waitAll) {
|
|
|
|
|
|
result = VK_SUCCESS;
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
}
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2017-08-04 12:59:45 -07:00
|
|
|
|
case ANV_BO_FENCE_STATE_SUBMITTED:
|
2017-02-15 16:48:47 -08:00
|
|
|
|
/* These are the fences we really care about. Go ahead and wait
|
|
|
|
|
|
* on it until we hit a timeout.
|
|
|
|
|
|
*/
|
2019-10-28 15:42:20 -05:00
|
|
|
|
result = anv_device_wait(device, impl->bo.bo,
|
2018-10-16 16:59:37 -05:00
|
|
|
|
anv_get_relative_timeout(abs_timeout_ns));
|
2017-02-15 16:48:47 -08:00
|
|
|
|
switch (result) {
|
|
|
|
|
|
case VK_SUCCESS:
|
2017-08-04 12:59:45 -07:00
|
|
|
|
impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
signaled_fences = true;
|
|
|
|
|
|
if (!waitAll)
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case VK_TIMEOUT:
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pending_fences && !signaled_fences) {
|
|
|
|
|
|
/* If we've hit this then someone decided to vkWaitForFences before
|
|
|
|
|
|
* they've actually submitted any of them to a queue. This is a
|
|
|
|
|
|
* fairly pessimal case, so it's ok to lock here and use a standard
|
|
|
|
|
|
* pthreads condition variable.
|
|
|
|
|
|
*/
|
|
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
|
|
|
|
|
|
|
|
|
|
|
/* It's possible that some of the fences have changed state since the
|
|
|
|
|
|
* last time we checked. Now that we have the lock, check for
|
|
|
|
|
|
* pending fences again and don't wait if it's changed.
|
|
|
|
|
|
*/
|
|
|
|
|
|
uint32_t now_pending_fences = 0;
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
2017-08-04 12:59:45 -07:00
|
|
|
|
if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
|
2017-02-15 16:48:47 -08:00
|
|
|
|
now_pending_fences++;
|
|
|
|
|
|
}
|
|
|
|
|
|
assert(now_pending_fences <= pending_fences);
|
|
|
|
|
|
|
|
|
|
|
|
if (now_pending_fences == pending_fences) {
|
2018-10-16 16:59:37 -05:00
|
|
|
|
struct timespec abstime = {
|
|
|
|
|
|
.tv_sec = abs_timeout_ns / NSEC_PER_SEC,
|
|
|
|
|
|
.tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
|
|
|
|
|
|
};
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2019-06-19 12:47:19 +01:00
|
|
|
|
ASSERTED int ret;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
ret = pthread_cond_timedwait(&device->queue_submit,
|
|
|
|
|
|
&device->mutex, &abstime);
|
|
|
|
|
|
assert(ret != EINVAL);
|
2019-08-07 16:46:45 +03:00
|
|
|
|
if (anv_gettime_ns() >= abs_timeout_ns) {
|
2017-02-15 16:48:47 -08:00
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
result = VK_TIMEOUT;
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
done:
|
2018-03-13 11:50:33 -07:00
|
|
|
|
if (anv_device_is_lost(device))
|
2017-02-15 16:48:47 -08:00
|
|
|
|
return VK_ERROR_DEVICE_LOST;
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-15 21:00:56 -07:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_wait_for_wsi_fence(struct anv_device *device,
|
|
|
|
|
|
const VkFence _fence,
|
|
|
|
|
|
uint64_t abs_timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, _fence);
|
|
|
|
|
|
struct anv_fence_impl *impl = &fence->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-06-05 23:18:56 -06:00
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_wait_for_fences(struct anv_device *device,
|
|
|
|
|
|
uint32_t fenceCount,
|
|
|
|
|
|
const VkFence *pFences,
|
|
|
|
|
|
bool waitAll,
|
|
|
|
|
|
uint64_t abs_timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
if (fenceCount <= 1 || waitAll) {
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
|
|
|
|
|
switch (fence->permanent.type) {
|
|
|
|
|
|
case ANV_FENCE_TYPE_BO:
|
2018-10-16 16:59:37 -05:00
|
|
|
|
result = anv_wait_for_bo_fences(device, 1, &pFences[i],
|
|
|
|
|
|
true, abs_timeout);
|
2018-06-05 23:18:56 -06:00
|
|
|
|
break;
|
|
|
|
|
|
case ANV_FENCE_TYPE_SYNCOBJ:
|
|
|
|
|
|
result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],
|
|
|
|
|
|
true, abs_timeout);
|
|
|
|
|
|
break;
|
2017-06-15 21:00:56 -07:00
|
|
|
|
case ANV_FENCE_TYPE_WSI:
|
|
|
|
|
|
result = anv_wait_for_wsi_fence(device, pFences[i], abs_timeout);
|
|
|
|
|
|
break;
|
2018-06-05 23:18:56 -06:00
|
|
|
|
case ANV_FENCE_TYPE_NONE:
|
|
|
|
|
|
result = VK_SUCCESS;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
do {
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; i++) {
|
|
|
|
|
|
if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
2019-08-07 16:46:45 +03:00
|
|
|
|
} while (anv_gettime_ns() < abs_timeout);
|
2018-06-05 23:18:56 -06:00
|
|
|
|
result = VK_TIMEOUT;
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; ++i) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
|
|
|
|
|
if (fence->permanent.type != ANV_FENCE_TYPE_SYNCOBJ)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (uint32_t i = 0; i < fenceCount; ++i) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
|
|
|
|
|
|
if (fence->permanent.type != ANV_FENCE_TYPE_BO)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-03 14:19:44 -07:00
|
|
|
|
VkResult anv_WaitForFences(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
uint32_t fenceCount,
|
|
|
|
|
|
const VkFence* pFences,
|
|
|
|
|
|
VkBool32 waitAll,
|
|
|
|
|
|
uint64_t timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
|
2018-03-13 11:50:33 -07:00
|
|
|
|
if (anv_device_is_lost(device))
|
2017-08-03 14:19:44 -07:00
|
|
|
|
return VK_ERROR_DEVICE_LOST;
|
|
|
|
|
|
|
2018-10-16 16:59:37 -05:00
|
|
|
|
uint64_t abs_timeout = anv_get_absolute_timeout(timeout);
|
2018-06-05 23:18:56 -06:00
|
|
|
|
if (anv_all_fences_syncobj(fenceCount, pFences)) {
|
2017-08-04 13:08:35 -07:00
|
|
|
|
return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
|
2018-10-16 16:59:37 -05:00
|
|
|
|
waitAll, abs_timeout);
|
2018-06-05 23:18:56 -06:00
|
|
|
|
} else if (anv_all_fences_bo(fenceCount, pFences)) {
|
2017-08-04 13:08:35 -07:00
|
|
|
|
return anv_wait_for_bo_fences(device, fenceCount, pFences,
|
2018-10-16 16:59:37 -05:00
|
|
|
|
waitAll, abs_timeout);
|
2018-06-05 23:18:56 -06:00
|
|
|
|
} else {
|
|
|
|
|
|
return anv_wait_for_fences(device, fenceCount, pFences,
|
2018-10-16 16:59:37 -05:00
|
|
|
|
waitAll, abs_timeout);
|
2017-08-04 13:08:35 -07:00
|
|
|
|
}
|
2017-08-03 14:19:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-20 12:18:10 -07:00
|
|
|
|
void anv_GetPhysicalDeviceExternalFenceProperties(
|
2017-08-08 12:25:38 -07:00
|
|
|
|
VkPhysicalDevice physicalDevice,
|
2019-01-08 18:04:54 +00:00
|
|
|
|
const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
|
|
|
|
|
|
VkExternalFenceProperties* pExternalFenceProperties)
|
2017-08-08 12:25:38 -07:00
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
|
|
|
|
|
|
|
|
|
|
|
|
switch (pExternalFenceInfo->handleType) {
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
|
|
|
|
|
|
case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
|
2017-08-08 12:25:38 -07:00
|
|
|
|
if (device->has_syncobj_wait) {
|
|
|
|
|
|
pExternalFenceProperties->exportFromImportedHandleTypes =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
|
|
|
|
|
|
VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
|
2017-08-08 12:25:38 -07:00
|
|
|
|
pExternalFenceProperties->compatibleHandleTypes =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
|
|
|
|
|
|
VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
|
2017-08-08 12:25:38 -07:00
|
|
|
|
pExternalFenceProperties->externalFenceFeatures =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |
|
|
|
|
|
|
VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;
|
2017-08-08 12:25:38 -07:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pExternalFenceProperties->exportFromImportedHandleTypes = 0;
|
|
|
|
|
|
pExternalFenceProperties->compatibleHandleTypes = 0;
|
|
|
|
|
|
pExternalFenceProperties->externalFenceFeatures = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_ImportFenceFdKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
|
|
|
|
|
|
int fd = pImportFenceFdInfo->fd;
|
|
|
|
|
|
|
|
|
|
|
|
assert(pImportFenceFdInfo->sType ==
|
|
|
|
|
|
VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_fence_impl new_impl = {
|
|
|
|
|
|
.type = ANV_FENCE_TYPE_NONE,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
switch (pImportFenceFdInfo->handleType) {
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
|
2017-08-08 12:25:38 -07:00
|
|
|
|
new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
|
|
|
|
|
|
|
|
|
|
|
|
new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
|
|
|
|
|
|
if (!new_impl.syncobj)
|
2017-09-20 13:16:26 -07:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
2017-08-08 12:25:38 -07:00
|
|
|
|
|
2017-08-08 15:17:31 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
|
2017-08-08 15:17:31 -07:00
|
|
|
|
/* Sync files are a bit tricky. Because we want to continue using the
|
|
|
|
|
|
* syncobj implementation of WaitForFences, we don't use the sync file
|
|
|
|
|
|
* directly but instead import it into a syncobj.
|
2017-08-08 12:25:38 -07:00
|
|
|
|
*/
|
2017-08-08 15:17:31 -07:00
|
|
|
|
new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
|
|
|
|
|
|
|
|
|
|
|
|
new_impl.syncobj = anv_gem_syncobj_create(device, 0);
|
|
|
|
|
|
if (!new_impl.syncobj)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
|
|
|
|
|
|
anv_gem_syncobj_destroy(device, new_impl.syncobj);
|
2017-08-25 09:55:39 +03:00
|
|
|
|
return vk_errorf(device->instance, NULL,
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_ERROR_INVALID_EXTERNAL_HANDLE,
|
2017-08-08 15:17:31 -07:00
|
|
|
|
"syncobj sync file import failed: %m");
|
|
|
|
|
|
}
|
2017-08-08 12:25:38 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
2017-09-20 13:16:26 -07:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
2017-08-08 12:25:38 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-08 15:17:31 -07:00
|
|
|
|
/* From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "Importing a fence payload from a file descriptor transfers
|
|
|
|
|
|
* ownership of the file descriptor from the application to the
|
|
|
|
|
|
* Vulkan implementation. The application must not perform any
|
|
|
|
|
|
* operations on the file descriptor after a successful import."
|
|
|
|
|
|
*
|
|
|
|
|
|
* If the import fails, we leave the file descriptor open.
|
|
|
|
|
|
*/
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
2017-09-20 13:16:26 -07:00
|
|
|
|
if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {
|
2017-08-08 12:25:38 -07:00
|
|
|
|
anv_fence_impl_cleanup(device, &fence->temporary);
|
|
|
|
|
|
fence->temporary = new_impl;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
anv_fence_impl_cleanup(device, &fence->permanent);
|
|
|
|
|
|
fence->permanent = new_impl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_GetFenceFdKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkFenceGetFdInfoKHR* pGetFdInfo,
|
|
|
|
|
|
int* pFd)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
|
|
|
|
|
|
|
|
|
|
|
|
assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_fence_impl *impl =
|
|
|
|
|
|
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
|
|
|
|
|
|
&fence->temporary : &fence->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
|
|
|
|
|
|
switch (pGetFdInfo->handleType) {
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {
|
2017-08-08 12:25:38 -07:00
|
|
|
|
int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
|
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
|
|
|
|
|
|
|
|
*pFd = fd;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
|
2017-08-08 15:17:31 -07:00
|
|
|
|
int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
|
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
|
|
|
|
|
|
|
|
*pFd = fd;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-08 12:25:38 -07:00
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid fence export handle type");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "Export operations have the same transference as the specified handle
|
|
|
|
|
|
* type’s import operations. [...] If the fence was using a
|
|
|
|
|
|
* temporarily imported payload, the fence’s prior permanent payload
|
|
|
|
|
|
* will be restored.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (impl == &fence->temporary)
|
|
|
|
|
|
anv_fence_impl_cleanup(device, impl);
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
// Queue semaphore functions
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
static VkSemaphoreTypeKHR
|
|
|
|
|
|
get_semaphore_type(const void *pNext, uint64_t *initial_value)
|
|
|
|
|
|
{
|
|
|
|
|
|
const VkSemaphoreTypeCreateInfoKHR *type_info =
|
|
|
|
|
|
vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
|
|
|
|
|
|
|
|
|
|
|
|
if (!type_info)
|
|
|
|
|
|
return VK_SEMAPHORE_TYPE_BINARY_KHR;
|
|
|
|
|
|
|
|
|
|
|
|
if (initial_value)
|
|
|
|
|
|
*initial_value = type_info->initialValue;
|
|
|
|
|
|
return type_info->semaphoreType;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
binary_semaphore_create(struct anv_device *device,
|
|
|
|
|
|
struct anv_semaphore_impl *impl,
|
|
|
|
|
|
bool exportable)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (device->instance->physicalDevice.has_syncobj) {
|
|
|
|
|
|
impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
|
|
|
|
|
|
impl->syncobj = anv_gem_syncobj_create(device, 0);
|
|
|
|
|
|
if (!impl->syncobj)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
impl->type = ANV_SEMAPHORE_TYPE_BO;
|
|
|
|
|
|
VkResult result =
|
|
|
|
|
|
anv_device_alloc_bo(device, 4096,
|
|
|
|
|
|
ANV_BO_ALLOC_EXTERNAL |
|
|
|
|
|
|
ANV_BO_ALLOC_IMPLICIT_SYNC,
|
2019-12-02 15:22:38 -06:00
|
|
|
|
0 /* explicit_address */,
|
2018-10-16 17:44:31 -05:00
|
|
|
|
&impl->bo);
|
|
|
|
|
|
/* If we're going to use this as a fence, we need to *not* have the
|
|
|
|
|
|
* EXEC_OBJECT_ASYNC bit set.
|
|
|
|
|
|
*/
|
|
|
|
|
|
assert(!(impl->bo->flags & EXEC_OBJECT_ASYNC));
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
timeline_semaphore_create(struct anv_device *device,
|
|
|
|
|
|
struct anv_semaphore_impl *impl,
|
|
|
|
|
|
uint64_t initial_value)
|
|
|
|
|
|
{
|
|
|
|
|
|
impl->type = ANV_SEMAPHORE_TYPE_TIMELINE;
|
|
|
|
|
|
anv_timeline_init(device, &impl->timeline, initial_value);
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
VkResult anv_CreateSemaphore(
|
2017-02-15 15:35:38 -08:00
|
|
|
|
VkDevice _device,
|
2017-02-15 16:48:47 -08:00
|
|
|
|
const VkSemaphoreCreateInfo* pCreateInfo,
|
|
|
|
|
|
const VkAllocationCallbacks* pAllocator,
|
|
|
|
|
|
VkSemaphore* pSemaphore)
|
|
|
|
|
|
{
|
2017-02-15 15:35:38 -08:00
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
struct anv_semaphore *semaphore;
|
|
|
|
|
|
|
|
|
|
|
|
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
uint64_t timeline_value = 0;
|
|
|
|
|
|
VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
|
|
|
|
|
|
|
2019-10-26 18:59:59 +03:00
|
|
|
|
semaphore = vk_alloc(&device->alloc, sizeof(*semaphore), 8,
|
|
|
|
|
|
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
|
2017-02-15 15:35:38 -08:00
|
|
|
|
if (semaphore == NULL)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
2019-10-26 18:59:59 +03:00
|
|
|
|
p_atomic_set(&semaphore->refcount, 1);
|
|
|
|
|
|
|
2019-01-08 18:04:54 +00:00
|
|
|
|
const VkExportSemaphoreCreateInfo *export =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
|
2019-01-08 18:04:54 +00:00
|
|
|
|
VkExternalSemaphoreHandleTypeFlags handleTypes =
|
2017-07-13 15:14:31 -07:00
|
|
|
|
export ? export->handleTypes : 0;
|
2018-10-16 17:44:31 -05:00
|
|
|
|
VkResult result;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
|
|
|
|
|
|
if (handleTypes == 0) {
|
2018-10-16 17:44:31 -05:00
|
|
|
|
if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
|
|
|
|
|
|
result = binary_semaphore_create(device, &semaphore->permanent, false);
|
|
|
|
|
|
else
|
|
|
|
|
|
result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
|
|
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
|
|
vk_free2(&device->alloc, pAllocator, semaphore);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2017-09-20 13:16:26 -07:00
|
|
|
|
} else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
|
|
|
|
|
|
assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
|
2018-10-16 17:44:31 -05:00
|
|
|
|
assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
|
|
|
|
|
|
result = binary_semaphore_create(device, &semaphore->permanent, true);
|
|
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
|
|
vk_free2(&device->alloc, pAllocator, semaphore);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
|
|
|
|
|
|
assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);
|
|
|
|
|
|
assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
|
2017-04-10 18:36:42 -07:00
|
|
|
|
if (device->instance->physicalDevice.has_syncobj) {
|
|
|
|
|
|
semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
|
2017-08-25 11:35:27 -07:00
|
|
|
|
semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
|
2017-04-10 18:36:42 -07:00
|
|
|
|
if (!semaphore->permanent.syncobj) {
|
|
|
|
|
|
vk_free2(&device->alloc, pAllocator, semaphore);
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
}
|
2019-04-21 01:01:55 +01:00
|
|
|
|
} else {
|
|
|
|
|
|
semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
|
|
|
|
|
|
semaphore->permanent.fd = -1;
|
|
|
|
|
|
}
|
2017-07-13 15:14:31 -07:00
|
|
|
|
} else {
|
|
|
|
|
|
assert(!"Unknown handle type");
|
|
|
|
|
|
vk_free2(&device->alloc, pAllocator, semaphore);
|
2017-09-20 13:16:26 -07:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
2017-07-13 15:14:31 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 15:35:38 -08:00
|
|
|
|
semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
2017-02-15 15:35:38 -08:00
|
|
|
|
*pSemaphore = anv_semaphore_to_handle(semaphore);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 17:25:46 -08:00
|
|
|
|
static void
|
|
|
|
|
|
anv_semaphore_impl_cleanup(struct anv_device *device,
|
|
|
|
|
|
struct anv_semaphore_impl *impl)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_NONE:
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_DUMMY:
|
|
|
|
|
|
/* Dummy. Nothing to do */
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
2017-02-15 17:25:46 -08:00
|
|
|
|
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_BO:
|
2019-10-25 17:45:28 -05:00
|
|
|
|
anv_device_release_bo(device, impl->bo);
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
2017-05-10 14:28:33 -07:00
|
|
|
|
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_SYNC_FILE:
|
|
|
|
|
|
close(impl->fd);
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
2017-04-10 18:36:42 -07:00
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
case ANV_SEMAPHORE_TYPE_TIMELINE:
|
|
|
|
|
|
anv_timeline_finish(device, &impl->timeline);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2017-04-10 18:36:42 -07:00
|
|
|
|
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
|
|
|
|
|
|
anv_gem_syncobj_destroy(device, impl->syncobj);
|
2018-05-26 12:08:22 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid semaphore type");
|
2017-02-15 17:25:46 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-26 12:08:22 -07:00
|
|
|
|
impl->type = ANV_SEMAPHORE_TYPE_NONE;
|
2017-02-15 17:25:46 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-07-13 15:14:31 -07:00
|
|
|
|
void
|
|
|
|
|
|
anv_semaphore_reset_temporary(struct anv_device *device,
|
|
|
|
|
|
struct anv_semaphore *semaphore)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-26 18:59:59 +03:00
|
|
|
|
static struct anv_semaphore *
|
|
|
|
|
|
anv_semaphore_ref(struct anv_semaphore *semaphore)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert(semaphore->refcount);
|
|
|
|
|
|
p_atomic_inc(&semaphore->refcount);
|
|
|
|
|
|
return semaphore;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!p_atomic_dec_zero(&semaphore->refcount))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
|
|
|
|
|
|
anv_semaphore_impl_cleanup(device, &semaphore->permanent);
|
|
|
|
|
|
vk_free(&device->alloc, semaphore);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-15 16:48:47 -08:00
|
|
|
|
void anv_DestroySemaphore(
|
2017-02-15 15:35:38 -08:00
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
VkSemaphore _semaphore,
|
2017-02-15 16:48:47 -08:00
|
|
|
|
const VkAllocationCallbacks* pAllocator)
|
|
|
|
|
|
{
|
2017-02-15 15:35:38 -08:00
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
|
|
|
|
|
|
|
|
|
|
|
|
if (semaphore == NULL)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2019-10-26 18:59:59 +03:00
|
|
|
|
anv_semaphore_unref(device, semaphore);
|
2017-02-15 16:48:47 -08:00
|
|
|
|
}
|
2017-07-13 15:14:31 -07:00
|
|
|
|
|
2017-09-20 12:18:10 -07:00
|
|
|
|
void anv_GetPhysicalDeviceExternalSemaphoreProperties(
|
2017-07-13 15:14:31 -07:00
|
|
|
|
VkPhysicalDevice physicalDevice,
|
2019-01-08 18:04:54 +00:00
|
|
|
|
const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
|
|
|
|
|
|
VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
|
2017-07-13 15:14:31 -07:00
|
|
|
|
{
|
2017-05-10 14:28:33 -07:00
|
|
|
|
ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
|
|
|
|
|
|
|
2018-10-16 17:44:31 -05:00
|
|
|
|
VkSemaphoreTypeKHR sem_type =
|
|
|
|
|
|
get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
|
|
|
|
|
|
|
2017-07-13 15:14:31 -07:00
|
|
|
|
switch (pExternalSemaphoreInfo->handleType) {
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
|
2018-10-16 17:44:31 -05:00
|
|
|
|
/* Timeline semaphores are not exportable. */
|
|
|
|
|
|
if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
|
|
|
|
|
|
break;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
pExternalSemaphoreProperties->exportFromImportedHandleTypes =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
pExternalSemaphoreProperties->compatibleHandleTypes =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
pExternalSemaphoreProperties->externalSemaphoreFeatures =
|
2017-09-20 13:16:26 -07:00
|
|
|
|
VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
|
|
|
|
|
|
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
|
2017-05-10 14:28:33 -07:00
|
|
|
|
return;
|
|
|
|
|
|
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
|
2018-10-16 17:44:31 -05:00
|
|
|
|
if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
|
|
|
|
|
|
break;
|
|
|
|
|
|
if (!device->has_exec_fence)
|
|
|
|
|
|
break;
|
|
|
|
|
|
pExternalSemaphoreProperties->exportFromImportedHandleTypes =
|
|
|
|
|
|
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
|
|
|
|
|
|
pExternalSemaphoreProperties->compatibleHandleTypes =
|
|
|
|
|
|
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
|
|
|
|
|
|
pExternalSemaphoreProperties->externalSemaphoreFeatures =
|
|
|
|
|
|
VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
|
|
|
|
|
|
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
|
|
|
|
|
|
return;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
|
|
|
|
|
|
default:
|
2017-05-10 14:28:33 -07:00
|
|
|
|
break;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
}
|
2017-05-10 14:28:33 -07:00
|
|
|
|
|
|
|
|
|
|
pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
|
|
|
|
|
|
pExternalSemaphoreProperties->compatibleHandleTypes = 0;
|
|
|
|
|
|
pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_ImportSemaphoreFdKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
|
|
|
|
|
|
int fd = pImportSemaphoreFdInfo->fd;
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_semaphore_impl new_impl = {
|
|
|
|
|
|
.type = ANV_SEMAPHORE_TYPE_NONE,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
switch (pImportSemaphoreFdInfo->handleType) {
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
|
2017-04-10 18:36:42 -07:00
|
|
|
|
if (device->instance->physicalDevice.has_syncobj) {
|
|
|
|
|
|
new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
|
|
|
|
|
|
|
|
|
|
|
|
new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
|
|
|
|
|
|
if (!new_impl.syncobj)
|
2017-09-20 13:16:26 -07:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
2017-04-10 18:36:42 -07:00
|
|
|
|
} else {
|
|
|
|
|
|
new_impl.type = ANV_SEMAPHORE_TYPE_BO;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
|
2019-10-25 17:45:28 -05:00
|
|
|
|
VkResult result = anv_device_import_bo(device, fd,
|
|
|
|
|
|
ANV_BO_ALLOC_EXTERNAL |
|
|
|
|
|
|
ANV_BO_ALLOC_IMPLICIT_SYNC,
|
|
|
|
|
|
&new_impl.bo);
|
2017-04-10 18:36:42 -07:00
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
|
anv: Move size check from anv_bo_cache_import() to caller (v2)
This change prepares for VK_ANDROID_native_buffer. When the user imports
a gralloc hande into a VkImage using VK_ANDROID_native_buffer, the user
provides no size. The driver must infer the size from the internals of
the gralloc buffer.
The patch is essentially a refactor patch, but it does change behavior
in some edge cases, described below. In what follows, the "nominal size"
of the bo refers to anv_bo::size, which may not match the bo's "actual
size" according to the kernel.
Post-patch, the nominal size of the bo returned from
anv_bo_cache_import() is always the size of imported dma-buf according
to lseek(). Pre-patch, the bo's nominal size was difficult to predict.
If the imported dma-buf's gem handle was not resident in the cache, then
the bo's nominal size was align(VkMemoryAllocateInfo::allocationSize,
4096). If it *was* resident, then the bo's nominal size was whatever
the cache returned. As a consequence, the first cache insert decided the
bo's nominal size, which could be significantly smaller compared to the
dma-buf's actual size, as the nominal size was determined by
VkMemoryAllocationInfo::allocationSize and not lseek().
I believe this patch cleans up that messy behavior. For an imported or
exported VkDeviceMemory, anv_bo::size should now be the true size of the
bo, if I correctly understand the problem (which I possibly don't).
v2:
- Preserve behavior of aligning size to 4096 before checking. [for
jekstrand]
- Check size with < instead of <=, to match behavior of commit c0a4f56
"anv: bo_cache: allow importing a BO larger than needed". [for
chadv]
2017-09-12 14:05:08 -07:00
|
|
|
|
if (new_impl.bo->size < 4096) {
|
2019-10-25 17:45:28 -05:00
|
|
|
|
anv_device_release_bo(device, new_impl.bo);
|
2019-01-08 18:04:54 +00:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
anv: Move size check from anv_bo_cache_import() to caller (v2)
This change prepares for VK_ANDROID_native_buffer. When the user imports
a gralloc hande into a VkImage using VK_ANDROID_native_buffer, the user
provides no size. The driver must infer the size from the internals of
the gralloc buffer.
The patch is essentially a refactor patch, but it does change behavior
in some edge cases, described below. In what follows, the "nominal size"
of the bo refers to anv_bo::size, which may not match the bo's "actual
size" according to the kernel.
Post-patch, the nominal size of the bo returned from
anv_bo_cache_import() is always the size of imported dma-buf according
to lseek(). Pre-patch, the bo's nominal size was difficult to predict.
If the imported dma-buf's gem handle was not resident in the cache, then
the bo's nominal size was align(VkMemoryAllocateInfo::allocationSize,
4096). If it *was* resident, then the bo's nominal size was whatever
the cache returned. As a consequence, the first cache insert decided the
bo's nominal size, which could be significantly smaller compared to the
dma-buf's actual size, as the nominal size was determined by
VkMemoryAllocationInfo::allocationSize and not lseek().
I believe this patch cleans up that messy behavior. For an imported or
exported VkDeviceMemory, anv_bo::size should now be the true size of the
bo, if I correctly understand the problem (which I possibly don't).
v2:
- Preserve behavior of aligning size to 4096 before checking. [for
jekstrand]
- Check size with < instead of <=, to match behavior of commit c0a4f56
"anv: bo_cache: allow importing a BO larger than needed". [for
chadv]
2017-09-12 14:05:08 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-10 18:36:42 -07:00
|
|
|
|
/* If we're going to use this as a fence, we need to *not* have the
|
|
|
|
|
|
* EXEC_OBJECT_ASYNC bit set.
|
|
|
|
|
|
*/
|
|
|
|
|
|
assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
|
|
|
|
|
|
}
|
2017-09-11 16:41:21 -07:00
|
|
|
|
|
|
|
|
|
|
/* From the Vulkan spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "Importing semaphore state from a file descriptor transfers
|
|
|
|
|
|
* ownership of the file descriptor from the application to the
|
|
|
|
|
|
* Vulkan implementation. The application must not perform any
|
|
|
|
|
|
* operations on the file descriptor after a successful import."
|
|
|
|
|
|
*
|
|
|
|
|
|
* If the import fails, we leave the file descriptor open.
|
|
|
|
|
|
*/
|
|
|
|
|
|
close(fd);
|
2017-07-13 15:14:31 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
2017-09-20 13:16:26 -07:00
|
|
|
|
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
|
2019-04-21 01:01:55 +01:00
|
|
|
|
if (device->instance->physicalDevice.has_syncobj) {
|
|
|
|
|
|
new_impl = (struct anv_semaphore_impl) {
|
|
|
|
|
|
.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
|
|
|
|
|
|
.syncobj = anv_gem_syncobj_create(device, 0),
|
|
|
|
|
|
};
|
|
|
|
|
|
if (!new_impl.syncobj)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
|
|
|
|
|
|
anv_gem_syncobj_destroy(device, new_impl.syncobj);
|
|
|
|
|
|
return vk_errorf(device->instance, NULL,
|
|
|
|
|
|
VK_ERROR_INVALID_EXTERNAL_HANDLE,
|
|
|
|
|
|
"syncobj sync file import failed: %m");
|
|
|
|
|
|
}
|
|
|
|
|
|
/* Ownership of the FD is transfered to Anv. Since we don't need it
|
|
|
|
|
|
* anymore because the associated fence has been put into a syncobj,
|
|
|
|
|
|
* we must close the FD.
|
|
|
|
|
|
*/
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
new_impl = (struct anv_semaphore_impl) {
|
|
|
|
|
|
.type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
|
|
|
|
|
|
.fd = fd,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2017-05-10 14:28:33 -07:00
|
|
|
|
break;
|
|
|
|
|
|
|
2017-07-13 15:14:31 -07:00
|
|
|
|
default:
|
2017-09-20 13:16:26 -07:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
2017-07-13 15:14:31 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-20 13:16:26 -07:00
|
|
|
|
if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
|
2017-07-13 15:14:31 -07:00
|
|
|
|
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
|
|
|
|
|
|
semaphore->temporary = new_impl;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
anv_semaphore_impl_cleanup(device, &semaphore->permanent);
|
|
|
|
|
|
semaphore->permanent = new_impl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_GetSemaphoreFdKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
|
|
|
|
|
|
int* pFd)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
|
|
|
|
|
|
VkResult result;
|
2017-04-10 18:36:42 -07:00
|
|
|
|
int fd;
|
2017-07-13 15:14:31 -07:00
|
|
|
|
|
|
|
|
|
|
assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_semaphore_impl *impl =
|
|
|
|
|
|
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
|
|
|
|
|
|
&semaphore->temporary : &semaphore->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_BO:
|
2019-10-25 17:45:28 -05:00
|
|
|
|
result = anv_device_export_bo(device, impl->bo, pFd);
|
2017-07-13 15:14:31 -07:00
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2019-11-11 10:58:44 -06:00
|
|
|
|
case ANV_SEMAPHORE_TYPE_SYNC_FILE: {
|
|
|
|
|
|
/* There's a potential race here with vkQueueSubmit if you are trying
|
|
|
|
|
|
* to export a semaphore Fd while the queue submit is still happening.
|
|
|
|
|
|
* This can happen if we see all dependencies get resolved via timeline
|
|
|
|
|
|
* semaphore waits completing before the execbuf completes and we
|
|
|
|
|
|
* process the resulting out fence. To work around this, take a lock
|
|
|
|
|
|
* around grabbing the fd.
|
2017-05-10 14:28:33 -07:00
|
|
|
|
*/
|
2019-11-11 10:58:44 -06:00
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
2017-05-10 14:28:33 -07:00
|
|
|
|
|
|
|
|
|
|
/* From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "...exporting a semaphore payload to a handle with copy
|
|
|
|
|
|
* transference has the same side effects on the source
|
|
|
|
|
|
* semaphore’s payload as executing a semaphore wait operation."
|
|
|
|
|
|
*
|
|
|
|
|
|
* In other words, it may still be a SYNC_FD semaphore, but it's now
|
|
|
|
|
|
* considered to have been waited on and no longer has a sync file
|
|
|
|
|
|
* attached.
|
|
|
|
|
|
*/
|
2019-11-11 10:58:44 -06:00
|
|
|
|
int fd = impl->fd;
|
2017-05-10 14:28:33 -07:00
|
|
|
|
impl->fd = -1;
|
2019-11-11 10:58:44 -06:00
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
|
|
|
|
|
|
/* There are two reasons why this could happen:
|
|
|
|
|
|
*
|
|
|
|
|
|
* 1) The user is trying to export without submitting something that
|
|
|
|
|
|
* signals the semaphore. If this is the case, it's their bug so
|
|
|
|
|
|
* what we return here doesn't matter.
|
|
|
|
|
|
*
|
|
|
|
|
|
* 2) The kernel didn't give us a file descriptor. The most likely
|
|
|
|
|
|
* reason for this is running out of file descriptors.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
|
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
|
|
|
|
|
|
|
|
*pFd = fd;
|
2017-05-10 14:28:33 -07:00
|
|
|
|
return VK_SUCCESS;
|
2019-11-11 10:58:44 -06:00
|
|
|
|
}
|
2017-05-10 14:28:33 -07:00
|
|
|
|
|
2017-04-10 18:36:42 -07:00
|
|
|
|
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
|
2019-04-21 01:01:55 +01:00
|
|
|
|
if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)
|
|
|
|
|
|
fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
|
|
|
|
|
|
else {
|
|
|
|
|
|
assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
|
|
|
|
|
|
fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
|
|
|
|
|
|
}
|
2017-04-10 18:36:42 -07:00
|
|
|
|
if (fd < 0)
|
|
|
|
|
|
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
|
|
*pFd = fd;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2017-07-13 15:14:31 -07:00
|
|
|
|
default:
|
2017-09-20 13:16:26 -07:00
|
|
|
|
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
2017-07-13 15:14:31 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* From the Vulkan 1.0.53 spec:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "Export operations have the same transference as the specified handle
|
|
|
|
|
|
* type’s import operations. [...] If the semaphore was using a
|
|
|
|
|
|
* temporarily imported payload, the semaphore’s prior permanent payload
|
|
|
|
|
|
* will be restored.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (impl == &semaphore->temporary)
|
|
|
|
|
|
anv_semaphore_impl_cleanup(device, impl);
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
2018-10-16 17:44:31 -05:00
|
|
|
|
|
|
|
|
|
|
VkResult anv_GetSemaphoreCounterValueKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
VkSemaphore _semaphore,
|
|
|
|
|
|
uint64_t* pValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_semaphore_impl *impl =
|
|
|
|
|
|
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
|
|
|
|
|
|
&semaphore->temporary : &semaphore->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_TIMELINE: {
|
|
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
|
|
|
|
|
*pValue = impl->timeline.highest_past;
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid semaphore type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_timeline_wait_locked(struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline *timeline,
|
|
|
|
|
|
uint64_t serial, uint64_t abs_timeout_ns)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Wait on the queue_submit condition variable until the timeline has a
|
|
|
|
|
|
* time point pending that's at least as high as serial.
|
|
|
|
|
|
*/
|
|
|
|
|
|
while (timeline->highest_pending < serial) {
|
|
|
|
|
|
struct timespec abstime = {
|
|
|
|
|
|
.tv_sec = abs_timeout_ns / NSEC_PER_SEC,
|
|
|
|
|
|
.tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int ret = pthread_cond_timedwait(&device->queue_submit,
|
|
|
|
|
|
&device->mutex, &abstime);
|
|
|
|
|
|
assert(ret != EINVAL);
|
|
|
|
|
|
if (anv_gettime_ns() >= abs_timeout_ns &&
|
|
|
|
|
|
timeline->highest_pending < serial)
|
|
|
|
|
|
return VK_TIMEOUT;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
VkResult result = anv_timeline_gc_locked(device, timeline);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
|
|
if (timeline->highest_past >= serial)
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
/* If we got here, our earliest time point has a busy BO */
|
|
|
|
|
|
struct anv_timeline_point *point =
|
|
|
|
|
|
list_first_entry(&timeline->points,
|
|
|
|
|
|
struct anv_timeline_point, link);
|
|
|
|
|
|
|
|
|
|
|
|
/* Drop the lock while we wait. */
|
|
|
|
|
|
point->waiting++;
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
|
|
|
|
|
|
result = anv_device_wait(device, point->bo,
|
|
|
|
|
|
anv_get_relative_timeout(abs_timeout_ns));
|
|
|
|
|
|
|
|
|
|
|
|
/* Pick the mutex back up */
|
|
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
|
|
|
|
|
point->waiting--;
|
|
|
|
|
|
|
|
|
|
|
|
/* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
|
anv_timelines_wait(struct anv_device *device,
|
|
|
|
|
|
struct anv_timeline **timelines,
|
|
|
|
|
|
const uint64_t *serials,
|
|
|
|
|
|
uint32_t n_timelines,
|
|
|
|
|
|
bool wait_all,
|
|
|
|
|
|
uint64_t abs_timeout_ns)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!wait_all && n_timelines > 1) {
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
|
|
|
|
|
for (uint32_t i = 0; i < n_timelines; i++) {
|
|
|
|
|
|
result =
|
|
|
|
|
|
anv_timeline_wait_locked(device, timelines[i], serials[i], 0);
|
|
|
|
|
|
if (result != VK_TIMEOUT)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (result != VK_TIMEOUT ||
|
|
|
|
|
|
anv_gettime_ns() >= abs_timeout_ns) {
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* If none of them are ready do a short wait so we don't completely
|
|
|
|
|
|
* spin while holding the lock. The 10us is completely arbitrary.
|
|
|
|
|
|
*/
|
|
|
|
|
|
uint64_t abs_short_wait_ns =
|
|
|
|
|
|
anv_get_absolute_timeout(
|
|
|
|
|
|
MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000));
|
|
|
|
|
|
struct timespec abstime = {
|
|
|
|
|
|
.tv_sec = abs_short_wait_ns / NSEC_PER_SEC,
|
|
|
|
|
|
.tv_nsec = abs_short_wait_ns % NSEC_PER_SEC,
|
|
|
|
|
|
};
|
|
|
|
|
|
ASSERTED int ret;
|
|
|
|
|
|
ret = pthread_cond_timedwait(&device->queue_submit,
|
|
|
|
|
|
&device->mutex, &abstime);
|
|
|
|
|
|
assert(ret != EINVAL);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
|
|
|
|
|
for (uint32_t i = 0; i < n_timelines; i++) {
|
|
|
|
|
|
result =
|
|
|
|
|
|
anv_timeline_wait_locked(device, timelines[i],
|
|
|
|
|
|
serials[i], abs_timeout_ns);
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_WaitSemaphoresKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkSemaphoreWaitInfoKHR* pWaitInfo,
|
|
|
|
|
|
uint64_t timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_timeline **timelines =
|
|
|
|
|
|
vk_alloc(&device->alloc,
|
|
|
|
|
|
pWaitInfo->semaphoreCount * sizeof(*timelines),
|
|
|
|
|
|
8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
|
|
|
|
|
|
if (!timelines)
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t *values = vk_alloc(&device->alloc,
|
|
|
|
|
|
pWaitInfo->semaphoreCount * sizeof(*values),
|
|
|
|
|
|
8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
|
|
|
|
|
|
if (!values) {
|
|
|
|
|
|
vk_free(&device->alloc, timelines);
|
|
|
|
|
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t handle_count = 0;
|
|
|
|
|
|
for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]);
|
|
|
|
|
|
struct anv_semaphore_impl *impl =
|
|
|
|
|
|
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
|
|
|
|
|
|
&semaphore->temporary : &semaphore->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE);
|
|
|
|
|
|
|
|
|
|
|
|
if (pWaitInfo->pValues[i] == 0)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
timelines[handle_count] = &impl->timeline;
|
|
|
|
|
|
values[handle_count] = pWaitInfo->pValues[i];
|
|
|
|
|
|
handle_count++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult result = VK_SUCCESS;
|
|
|
|
|
|
if (handle_count > 0) {
|
|
|
|
|
|
result = anv_timelines_wait(device, timelines, values, handle_count,
|
|
|
|
|
|
!(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
|
|
|
|
|
|
timeout);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vk_free(&device->alloc, timelines);
|
|
|
|
|
|
vk_free(&device->alloc, values);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult anv_SignalSemaphoreKHR(
|
|
|
|
|
|
VkDevice _device,
|
|
|
|
|
|
const VkSemaphoreSignalInfoKHR* pSignalInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_device, device, _device);
|
|
|
|
|
|
ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore);
|
|
|
|
|
|
|
|
|
|
|
|
struct anv_semaphore_impl *impl =
|
|
|
|
|
|
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
|
|
|
|
|
|
&semaphore->temporary : &semaphore->permanent;
|
|
|
|
|
|
|
|
|
|
|
|
switch (impl->type) {
|
|
|
|
|
|
case ANV_SEMAPHORE_TYPE_TIMELINE: {
|
|
|
|
|
|
pthread_mutex_lock(&device->mutex);
|
|
|
|
|
|
|
|
|
|
|
|
VkResult result = anv_timeline_gc_locked(device, &impl->timeline);
|
|
|
|
|
|
|
|
|
|
|
|
assert(pSignalInfo->value > impl->timeline.highest_pending);
|
|
|
|
|
|
|
|
|
|
|
|
impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value;
|
|
|
|
|
|
|
|
|
|
|
|
if (result == VK_SUCCESS)
|
|
|
|
|
|
result = anv_device_submit_deferred_locked(device);
|
|
|
|
|
|
|
|
|
|
|
|
pthread_cond_broadcast(&device->queue_submit);
|
|
|
|
|
|
pthread_mutex_unlock(&device->mutex);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
unreachable("Invalid semaphore type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|