blob: ea720e02bc459617137a84234d43af0f1e8faaf1 [file] [log] [blame]
/*
* Copyright © 2022 The Fuchsia Authors
*
* 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 "vk_magma_syncobj.h"
#include "util/magma/magma_wait.h"
#include "drm-uapi/drm.h"
#include "vk_device.h"
#include "vk_log.h"
#include "vk_util.h"
static struct vk_magma_syncobj *
to_magma_syncobj(struct vk_sync *sync)
{
assert(vk_sync_type_is_magma_syncobj(sync->type));
return container_of(sync, struct vk_magma_syncobj, base);
}
static VkResult
vk_magma_syncobj_init(struct vk_device *device,
struct vk_sync *sync,
uint64_t initial_value)
{
struct vk_magma_syncobj *sobj = to_magma_syncobj(sync);
assert((sync->flags & VK_SYNC_IS_TIMELINE) == 0);
assert(device->magma_connection);
magma_status_t status;
if (initial_value && initial_value != 1) {
assert((initial_value >> 32) == 0);
status = magma_connection_import_semaphore2(
device->magma_connection->connection,
(uint32_t)initial_value, /*flags=*/0, &sobj->semaphore, &sobj->id);
} else {
status = magma_connection_create_semaphore(
device->magma_connection->connection, &sobj->semaphore, &sobj->id);
}
if (status == MAGMA_STATUS_CONNECTION_LOST) {
return vk_errorf(device, VK_ERROR_DEVICE_LOST,
"Failed to import or create semaphore: %m");
} else if (status != MAGMA_STATUS_OK) {
return vk_errorf(device, VK_ERROR_OUT_OF_HOST_MEMORY,
"Failed to import or create semaphore: %m");
}
if (initial_value == 1) {
magma_semaphore_signal(sobj->semaphore);
}
return VK_SUCCESS;
}
void
vk_magma_syncobj_finish(struct vk_device *device,
struct vk_sync *sync)
{
struct vk_magma_syncobj *sobj = to_magma_syncobj(sync);
assert(device->magma_connection);
magma_connection_release_semaphore(device->magma_connection->connection,
sobj->semaphore);
}
static VkResult
vk_magma_syncobj_signal(struct vk_device *device,
struct vk_sync *sync,
uint64_t value)
{
struct vk_magma_syncobj *sobj = to_magma_syncobj(sync);
magma_semaphore_signal(sobj->semaphore);
return VK_SUCCESS;
}
static VkResult
vk_magma_syncobj_reset(struct vk_device *device,
struct vk_sync *sync)
{
struct vk_magma_syncobj *sobj = to_magma_syncobj(sync);
magma_semaphore_reset(sobj->semaphore);
return VK_SUCCESS;
}
static VkResult
vk_magma_syncobj_wait_many(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)
{
assert((wait_flags & VK_SYNC_WAIT_PENDING) == 0);
/* Syncobj timeouts are signed */
abs_timeout_ns = MIN2(abs_timeout_ns, (uint64_t)INT64_MAX);
STACK_ARRAY(magma_semaphore_t, semaphores, wait_count);
for (uint32_t i = 0; i < wait_count; i++) {
semaphores[i] = to_magma_syncobj(waits[i].sync)->semaphore;
}
assert(device->magma_connection);
magma_status_t status = MAGMA_STATUS_OK;
if (wait_count) {
const bool kWaitAll = (wait_flags & VK_SYNC_WAIT_ANY) == 0;
status = magma_wait(device->magma_connection->notification_channel,
semaphores, wait_count, abs_timeout_ns,
kWaitAll, device->magma_connection->notification_callback,
device->magma_connection);
}
STACK_ARRAY_FINISH(semaphores);
switch (status) {
case MAGMA_STATUS_OK:
return VK_SUCCESS;
case MAGMA_STATUS_TIMED_OUT:
return VK_TIMEOUT;
case MAGMA_STATUS_CONNECTION_LOST:
return vk_errorf(device, VK_ERROR_DEVICE_LOST,
"magma_wait failed: %m");
default:
return vk_errorf(device, VK_ERROR_UNKNOWN,
"magma_wait failed: %m");
}
}
static VkResult
vk_magma_syncobj_import_magma_handle(struct vk_device *device,
struct vk_sync *sync,
uint32_t handle)
{
struct vk_magma_syncobj *sobj = to_magma_syncobj(sync);
assert(device->magma_connection);
magma_semaphore_t semaphore;
magma_semaphore_id_t id;
magma_status_t status = magma_connection_import_semaphore2(
device->magma_connection->connection, handle, /*flags=*/0, &semaphore, &id);
if (status != MAGMA_STATUS_OK) {
return vk_errorf(device, VK_ERROR_UNKNOWN,
"magma_connection_import_semaphore2 failed: %m");
}
magma_connection_release_semaphore(device->magma_connection->connection,
sobj->semaphore);
sobj->semaphore = semaphore;
sobj->id = id;
return VK_SUCCESS;
}
static VkResult
vk_magma_syncobj_export_magma_handle(struct vk_device *device,
struct vk_sync *sync,
uint32_t* handle_out)
{
struct vk_magma_syncobj *sobj = to_magma_syncobj(sync);
magma_handle_t handle;
magma_status_t status = magma_semaphore_export(sobj->semaphore, &handle);
if (status != MAGMA_STATUS_OK) {
return vk_errorf(device, VK_ERROR_UNKNOWN,
"magma_semaphore_export failed: %m");
}
*handle_out = handle;
return VK_SUCCESS;
}
static VkResult
vk_magma_syncobj_import_opaque_fd(struct vk_device *device,
struct vk_sync *sync,
int fd)
{
#if defined(DISABLE_EXTERNAL_SYNC_FD)
assert(false);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
#else
uint32_t handle = fd;
return vk_magma_syncobj_import_magma_handle(device, sync, handle);
#endif
}
static VkResult
vk_magma_syncobj_import_sync_file(struct vk_device *device,
struct vk_sync *sync,
int fd)
{
#if defined(DISABLE_EXTERNAL_SYNC_FD)
assert(false);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
#else
uint32_t handle = fd;
return vk_magma_syncobj_import_magma_handle(device, sync, handle);
#endif
}
static VkResult
vk_magma_syncobj_export_opaque_fd(struct vk_device *device,
struct vk_sync *sync,
int *fd)
{
#if defined(DISABLE_EXTERNAL_SYNC_FD)
assert(false);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
#else
magma_handle_t handle;
VkResult result = vk_magma_syncobj_export_magma_handle(device, sync, &handle);
if (result == VK_SUCCESS) {
*fd = handle;
}
return result;
#endif
}
static VkResult
vk_magma_syncobj_export_sync_file(struct vk_device *device,
struct vk_sync *sync,
int *fd)
{
#if defined(DISABLE_EXTERNAL_SYNC_FD)
assert(false);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
#else
// TODO(fxbug.dev/42146493) - currently we don't support export to sync files;
// failing here helps ANGLE avoid external fences for now.
return VK_ERROR_UNKNOWN;
#endif
}
struct vk_sync_type
vk_magma_syncobj_get_type(void)
{
struct vk_sync_type type = {
.size = sizeof(struct vk_magma_syncobj),
.features = VK_SYNC_FEATURE_BINARY |
VK_SYNC_FEATURE_GPU_WAIT |
VK_SYNC_FEATURE_CPU_RESET |
VK_SYNC_FEATURE_CPU_SIGNAL |
VK_SYNC_FEATURE_CPU_WAIT |
VK_SYNC_FEATURE_WAIT_ANY,
.init = vk_magma_syncobj_init,
.finish = vk_magma_syncobj_finish,
.signal = vk_magma_syncobj_signal,
.reset = vk_magma_syncobj_reset,
.wait_many = vk_magma_syncobj_wait_many,
#if defined(ANDROID)
.import_sync_file = vk_magma_syncobj_import_sync_file,
.export_sync_file = vk_magma_syncobj_export_sync_file,
#elif defined(__linux__)
.import_opaque_fd = vk_magma_syncobj_import_opaque_fd,
.export_opaque_fd = vk_magma_syncobj_export_opaque_fd,
#elif defined(__Fuchsia__)
.import_magma_handle = vk_magma_syncobj_import_magma_handle,
.export_magma_handle = vk_magma_syncobj_export_magma_handle,
#endif
};
return type;
}