| /* |
| * 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_semaphore( |
| device->magma_connection->connection, |
| (uint32_t)initial_value, &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_semaphore( |
| device->magma_connection->connection, handle, &semaphore, &id); |
| |
| if (status != MAGMA_STATUS_OK) { |
| return vk_errorf(device, VK_ERROR_UNKNOWN, |
| "magma_connection_import_semaphore 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_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 |
| } |
| |
| 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, |
| #ifdef __linux__ |
| .import_opaque_fd = vk_magma_syncobj_import_opaque_fd, |
| .export_opaque_fd = vk_magma_syncobj_export_opaque_fd, |
| #endif |
| #ifdef __Fuchsia__ |
| .import_magma_handle = vk_magma_syncobj_import_magma_handle, |
| .export_magma_handle = vk_magma_syncobj_export_magma_handle, |
| #endif |
| }; |
| |
| return type; |
| } |