2021-06-24 12:09:35 +01:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © Microsoft 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "dzn_private.h"
|
|
|
|
|
|
|
|
|
|
#include "vk_alloc.h"
|
|
|
|
|
#include "vk_debug_report.h"
|
|
|
|
|
#include "vk_util.h"
|
|
|
|
|
|
|
|
|
|
#include "util/macros.h"
|
|
|
|
|
#include "util/os_time.h"
|
|
|
|
|
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
#include <sys/eventfd.h>
|
|
|
|
|
#include <libsync.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-06-24 12:09:35 +01:00
|
|
|
|
static VkResult
|
|
|
|
|
dzn_sync_init(struct vk_device *device,
|
|
|
|
|
struct vk_sync *sync,
|
|
|
|
|
uint64_t initial_value)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
|
|
|
|
|
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
|
|
|
|
assert(!(sync->flags & VK_SYNC_IS_SHAREABLE));
|
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
if (FAILED(ID3D12Device1_CreateFence(ddev->dev, initial_value,
|
|
|
|
|
D3D12_FENCE_FLAG_NONE,
|
2022-04-06 14:04:34 +01:00
|
|
|
|
&IID_ID3D12Fence,
|
2022-04-21 13:35:29 +01:00
|
|
|
|
(void **)&dsync->fence)))
|
2021-06-24 12:09:35 +01:00
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dzn_sync_finish(struct vk_device *device,
|
|
|
|
|
struct vk_sync *sync)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
ID3D12Fence_Release(dsync->fence);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
dzn_sync_signal(struct vk_device *device,
|
|
|
|
|
struct vk_sync *sync,
|
|
|
|
|
uint64_t value)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
|
|
|
|
if (!(sync->flags & VK_SYNC_IS_TIMELINE))
|
|
|
|
|
value = 1;
|
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
if (FAILED(ID3D12Fence_Signal(dsync->fence, value)))
|
2021-06-24 12:09:35 +01:00
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
dzn_sync_get_value(struct vk_device *device,
|
|
|
|
|
struct vk_sync *sync,
|
|
|
|
|
uint64_t *value)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
*value = ID3D12Fence_GetCompletedValue(dsync->fence);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
dzn_sync_reset(struct vk_device *device,
|
|
|
|
|
struct vk_sync *sync)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
if (FAILED(ID3D12Fence_Signal(dsync->fence, 0)))
|
2021-06-24 12:09:35 +01:00
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
dzn_sync_move(struct vk_device *device,
|
|
|
|
|
struct vk_sync *dst,
|
|
|
|
|
struct vk_sync *src)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
|
|
|
|
|
struct dzn_sync *ddst = container_of(dst, struct dzn_sync, vk);
|
|
|
|
|
struct dzn_sync *dsrc = container_of(src, struct dzn_sync, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
ID3D12Fence *new_fence;
|
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
if (FAILED(ID3D12Device1_CreateFence(ddev->dev, 0,
|
|
|
|
|
D3D12_FENCE_FLAG_NONE,
|
2022-04-06 14:04:34 +01:00
|
|
|
|
&IID_ID3D12Fence,
|
2022-04-21 13:35:29 +01:00
|
|
|
|
(void **)&new_fence)))
|
2021-06-24 12:09:35 +01:00
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
ID3D12Fence_Release(ddst->fence);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
ddst->fence = dsrc->fence;
|
|
|
|
|
dsrc->fence = new_fence;
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult
|
|
|
|
|
dzn_sync_wait(struct vk_device *device,
|
|
|
|
|
uint32_t wait_count,
|
|
|
|
|
const struct vk_sync_wait *waits,
|
|
|
|
|
enum vk_sync_wait_flags wait_flags,
|
|
|
|
|
uint64_t abs_timeout_ns)
|
|
|
|
|
{
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#ifdef _WIN32
|
2021-06-24 12:09:35 +01:00
|
|
|
|
HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
|
|
|
if (event == NULL)
|
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#else
|
|
|
|
|
int event_fd = eventfd(0, EFD_CLOEXEC);
|
|
|
|
|
if (event_fd == -1)
|
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
/* The D3D12 event-based APIs in WSL expect an eventfd file descriptor cast to HANDLE */
|
|
|
|
|
HANDLE event = (HANDLE)(intptr_t)event_fd;
|
|
|
|
|
#endif
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
|
|
|
|
STACK_ARRAY(ID3D12Fence *, fences, wait_count);
|
|
|
|
|
STACK_ARRAY(uint64_t, values, wait_count);
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < wait_count; i++) {
|
2022-04-05 16:41:20 +01:00
|
|
|
|
struct dzn_sync *sync = container_of(waits[i].sync, struct dzn_sync, vk);
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
|
|
|
|
fences[i] = sync->fence;
|
|
|
|
|
values[i] = (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? waits[i].wait_value : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags =
|
|
|
|
|
(wait_flags & VK_SYNC_WAIT_ANY) ?
|
|
|
|
|
D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY :
|
|
|
|
|
D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL;
|
|
|
|
|
|
2022-03-25 16:08:50 +00:00
|
|
|
|
if (FAILED(ID3D12Device1_SetEventOnMultipleFenceCompletion(ddev->dev,
|
|
|
|
|
fences,
|
|
|
|
|
values,
|
|
|
|
|
wait_count,
|
|
|
|
|
flags,
|
|
|
|
|
event))) {
|
2021-06-24 12:09:35 +01:00
|
|
|
|
STACK_ARRAY_FINISH(fences);
|
|
|
|
|
STACK_ARRAY_FINISH(values);
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#ifdef _WIN32
|
2021-06-24 12:09:35 +01:00
|
|
|
|
CloseHandle(event);
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#else
|
|
|
|
|
close(event_fd);
|
|
|
|
|
#endif
|
2021-06-24 12:09:35 +01:00
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#ifdef _WIN32
|
2021-06-24 12:09:35 +01:00
|
|
|
|
DWORD timeout_ms;
|
2022-07-01 17:05:25 +01:00
|
|
|
|
static const DWORD timeout_infinite = INFINITE;
|
|
|
|
|
#else
|
|
|
|
|
int timeout_ms;
|
|
|
|
|
static const int timeout_infinite = -1;
|
|
|
|
|
#endif
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
|
|
|
|
if (abs_timeout_ns == OS_TIMEOUT_INFINITE) {
|
2022-07-01 17:05:25 +01:00
|
|
|
|
timeout_ms = timeout_infinite;
|
2021-06-24 12:09:35 +01:00
|
|
|
|
} else {
|
|
|
|
|
uint64_t cur_time = os_time_get_nano();
|
|
|
|
|
uint64_t rel_timeout_ns =
|
|
|
|
|
abs_timeout_ns > cur_time ? abs_timeout_ns - cur_time : 0;
|
|
|
|
|
|
|
|
|
|
timeout_ms = (rel_timeout_ns / 1000000) + (rel_timeout_ns % 1000000 ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-01 17:05:25 +01:00
|
|
|
|
#ifdef _WIN32
|
2021-06-24 12:09:35 +01:00
|
|
|
|
DWORD res =
|
|
|
|
|
WaitForSingleObject(event, timeout_ms);
|
|
|
|
|
|
|
|
|
|
CloseHandle(event);
|
2022-07-01 17:05:25 +01:00
|
|
|
|
VkResult ret = VK_SUCCESS;
|
|
|
|
|
if (res == WAIT_TIMEOUT)
|
|
|
|
|
ret = VK_TIMEOUT;
|
|
|
|
|
else if (res != WAIT_OBJECT_0)
|
|
|
|
|
ret = vk_error(device, VK_ERROR_UNKNOWN);
|
|
|
|
|
#else
|
|
|
|
|
VkResult ret = sync_wait(event_fd, timeout_ms) != 0 ? VK_TIMEOUT : VK_SUCCESS;
|
|
|
|
|
close(event_fd);
|
|
|
|
|
#endif
|
2021-06-24 12:09:35 +01:00
|
|
|
|
|
|
|
|
|
STACK_ARRAY_FINISH(fences);
|
|
|
|
|
STACK_ARRAY_FINISH(values);
|
|
|
|
|
|
2022-07-01 17:05:25 +01:00
|
|
|
|
return ret;
|
2021-06-24 12:09:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct vk_sync_type dzn_sync_type = {
|
2022-04-05 16:41:20 +01:00
|
|
|
|
.size = sizeof(struct dzn_sync),
|
2021-06-24 12:09:35 +01:00
|
|
|
|
.features = (enum vk_sync_features)
|
dzn: Use the vk_sync_binary abstraction
D3D12 fences are capable of handling binary operations, but the
current dzn_sync implementation doesn't match vk_sync expectations
when sync objects are used to back semaphores. In that case, the wait
operation is supposed to set the sync object back to an unsignaled
state after the wait succeeded, but there's no way of knowing what
the sync object is used for, and this implicit-reset behavior is not
expected on fence objects, which also use the sync primitive.
That means we currently have a semaphore implementation that works
only once, and, as soon as the semaphore object has been signaled it
stays in a signaled state until it's destroyed.
We could extend the sync framework to pass an
implicit-reset-after-wait flag, but, given no one else seems to
need that, it's probably simpler to drop the binary sync
capability and rely on the binary-on-top-of-timeline emulation provided
by the core.
Fixes: a012b219640e ("microsoft: Initial vulkan-on-12 driver")
Reviewed-by: Jason Ekstrand <jason.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16629>
2022-05-20 09:31:24 +01:00
|
|
|
|
(VK_SYNC_FEATURE_TIMELINE |
|
2021-06-24 12:09:35 +01:00
|
|
|
|
VK_SYNC_FEATURE_GPU_WAIT |
|
|
|
|
|
VK_SYNC_FEATURE_CPU_WAIT |
|
|
|
|
|
VK_SYNC_FEATURE_CPU_SIGNAL |
|
|
|
|
|
VK_SYNC_FEATURE_WAIT_ANY |
|
|
|
|
|
VK_SYNC_FEATURE_WAIT_BEFORE_SIGNAL),
|
|
|
|
|
|
|
|
|
|
.init = dzn_sync_init,
|
|
|
|
|
.finish = dzn_sync_finish,
|
|
|
|
|
.signal = dzn_sync_signal,
|
|
|
|
|
.get_value = dzn_sync_get_value,
|
|
|
|
|
.reset = dzn_sync_reset,
|
|
|
|
|
.move = dzn_sync_move,
|
|
|
|
|
.wait_many = dzn_sync_wait,
|
|
|
|
|
};
|