diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index 1c3e64d2e3f..d183c1276f0 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -101,6 +101,8 @@ pack_emit_reloc(void *cl, const void *reloc) {} memcpy((dest), (src), (count) * sizeof(*(src))); \ }) +#define NSEC_PER_SEC 1000000000ull + /* From vulkan spec "If the multiple viewports feature is not enabled, * scissorCount must be 1", ditto for viewportCount. For now we don't support * that feature. @@ -527,6 +529,14 @@ struct v3dv_semaphore { int32_t fd; }; +struct v3dv_fence { + /* A syncobject handle associated with this fence */ + uint32_t sync; + + /* The file handle of a fence that we imported into our syncobject */ + int32_t fd; +}; + struct v3dv_shader_module { unsigned char sha1[20]; uint32_t size; @@ -731,6 +741,7 @@ V3DV_DEFINE_HANDLE_CASTS(v3dv_queue, VkQueue) V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_cmd_pool, VkCommandPool) V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_buffer, VkBuffer) V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_device_memory, VkDeviceMemory) +V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_fence, VkFence) V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_framebuffer, VkFramebuffer) V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_image, VkImage) V3DV_DEFINE_NONDISP_HANDLE_CASTS(v3dv_image_view, VkImageView) diff --git a/src/broadcom/vulkan/v3dv_queue.c b/src/broadcom/vulkan/v3dv_queue.c index 8357b176630..53f3dd1258c 100644 --- a/src/broadcom/vulkan/v3dv_queue.c +++ b/src/broadcom/vulkan/v3dv_queue.c @@ -27,6 +27,7 @@ #include "broadcom/clif/clif_dump.h" #include +#include static void v3dv_clif_dump(struct v3dv_device *device, @@ -56,6 +57,25 @@ v3dv_clif_dump(struct v3dv_device *device, clif_dump_destroy(clif); } +static uint64_t +gettime_ns() +{ + struct timespec current; + clock_gettime(CLOCK_MONOTONIC, ¤t); + return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec; +} + +static uint64_t +get_absolute_timeout(uint64_t timeout) +{ + uint64_t current_time = gettime_ns(); + uint64_t max_timeout = (uint64_t) INT64_MAX - current_time; + + timeout = MIN2(max_timeout, timeout); + + return (current_time + timeout); +} + static VkResult process_semaphores_to_signal(struct v3dv_device *device, uint32_t count, const VkSemaphore *sems) @@ -85,6 +105,32 @@ process_semaphores_to_signal(struct v3dv_device *device, return VK_SUCCESS; } +static VkResult +process_fence_to_signal(struct v3dv_device *device, VkFence _fence) +{ + if (_fence == VK_NULL_HANDLE) + return VK_SUCCESS; + + struct v3dv_fence *fence = v3dv_fence_from_handle(_fence); + + if (fence->fd >= 0) + close(fence->fd); + fence->fd = -1; + + int fd; + drmSyncobjExportSyncFile(device->fd, device->last_job_sync, &fd); + if (fd == -1) + return VK_ERROR_DEVICE_LOST; + + int ret = drmSyncobjImportSyncFile(device->fd, fence->sync, fd); + if (ret) + return VK_ERROR_DEVICE_LOST; + + fence->fd = fd; + + return VK_SUCCESS; +} + static VkResult job_submit(struct v3dv_job *job, bool do_wait) { @@ -160,7 +206,6 @@ queue_submit(struct v3dv_queue *queue, VkFence fence) { /* FIXME */ - assert(fence == 0); assert(pSubmit->commandBufferCount == 1); V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, pSubmit->pCommandBuffers[0]); @@ -176,6 +221,10 @@ queue_submit(struct v3dv_queue *queue, pSubmit->pSignalSemaphores); if (result != VK_SUCCESS) return result; + + result = process_fence_to_signal(cmd_buffer->device, fence); + if (result != VK_SUCCESS) + return result; } return VK_SUCCESS; @@ -246,3 +295,133 @@ v3dv_DestroySemaphore(VkDevice _device, vk_free2(&device->alloc, pAllocator, sem); } + +VkResult +v3dv_CreateFence(VkDevice _device, + const VkFenceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkFence *pFence) +{ + V3DV_FROM_HANDLE(v3dv_device, device, _device); + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO); + + struct v3dv_fence *fence = + vk_alloc2(&device->alloc, pAllocator, sizeof(struct v3dv_fence), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (fence == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + unsigned flags = 0; + if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) + flags |= DRM_SYNCOBJ_CREATE_SIGNALED; + int ret = drmSyncobjCreate(device->fd, flags, &fence->sync); + if (ret) { + vk_free2(&device->alloc, pAllocator, fence); + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + } + + fence->fd = -1; + + *pFence = v3dv_fence_to_handle(fence); + + return VK_SUCCESS; +} + +void +v3dv_DestroyFence(VkDevice _device, + VkFence _fence, + const VkAllocationCallbacks *pAllocator) +{ + V3DV_FROM_HANDLE(v3dv_device, device, _device); + V3DV_FROM_HANDLE(v3dv_fence, fence, _fence); + + if (fence == NULL) + return; + + drmSyncobjDestroy(device->fd, fence->sync); + + if (fence->fd != -1) + close(fence->fd); + + vk_free2(&device->alloc, pAllocator, fence); +} + +VkResult +v3dv_GetFenceStatus(VkDevice _device, VkFence _fence) +{ + V3DV_FROM_HANDLE(v3dv_device, device, _device); + V3DV_FROM_HANDLE(v3dv_fence, fence, _fence); + + int ret = drmSyncobjWait(device->fd, &fence->sync, 1, + 0, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, NULL); + if (ret == -ETIME) + return VK_NOT_READY; + else if (ret) + return vk_error(device->instance, VK_ERROR_DEVICE_LOST); + return VK_SUCCESS; +} + +VkResult +v3dv_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences) +{ + V3DV_FROM_HANDLE(v3dv_device, device, _device); + + uint32_t *syncobjs = vk_alloc(&device->alloc, + sizeof(*syncobjs) * fenceCount, 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!syncobjs) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + for (uint32_t i = 0; i < fenceCount; i++) { + struct v3dv_fence *fence = v3dv_fence_from_handle(pFences[i]); + syncobjs[i] = fence->sync; + } + + int ret = drmSyncobjReset(device->fd, syncobjs, fenceCount); + + vk_free(&device->alloc, syncobjs); + + return ret ? VK_ERROR_OUT_OF_HOST_MEMORY : VK_SUCCESS; +} + +VkResult +v3dv_WaitForFences(VkDevice _device, + uint32_t fenceCount, + const VkFence *pFences, + VkBool32 waitAll, + uint64_t timeout) +{ + V3DV_FROM_HANDLE(v3dv_device, device, _device); + + const uint64_t abs_timeout = get_absolute_timeout(timeout); + + uint32_t *syncobjs = vk_alloc(&device->alloc, + sizeof(*syncobjs) * fenceCount, 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!syncobjs) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + for (uint32_t i = 0; i < fenceCount; i++) { + struct v3dv_fence *fence = v3dv_fence_from_handle(pFences[i]); + syncobjs[i] = fence->sync; + } + + unsigned flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT; + if (waitAll) + flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; + + int ret; + do { + ret = drmSyncobjWait(device->fd, syncobjs, fenceCount, + timeout, flags, NULL); + } while (ret == -ETIME && gettime_ns() < abs_timeout); + + vk_free(&device->alloc, syncobjs); + + if (ret == -ETIME) + return VK_TIMEOUT; + else if (ret) + return vk_error(device->instance, VK_ERROR_DEVICE_LOST); + return VK_SUCCESS; +}