Path: blob/21.2-virgl/src/panfrost/vulkan/panvk_sync.c
4560 views
/*1* Copyright (C) 2021 Collabora Ltd.2*3* Derived from tu_drm.c which is:4* Copyright © 2018 Google, Inc.5* Copyright © 2015 Intel Corporation6*7* Permission is hereby granted, free of charge, to any person obtaining a8* copy of this software and associated documentation files (the "Software"),9* to deal in the Software without restriction, including without limitation10* the rights to use, copy, modify, merge, publish, distribute, sublicense,11* and/or sell copies of the Software, and to permit persons to whom the12* Software is furnished to do so, subject to the following conditions:13*14* The above copyright notice and this permission notice (including the next15* paragraph) shall be included in all copies or substantial portions of the16* Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL21* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER22* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING23* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER24* DEALINGS IN THE SOFTWARE.25*/2627#include <xf86drm.h>2829#include "panvk_private.h"3031static VkResult32sync_create(struct panvk_device *device,33struct panvk_syncobj *sync,34bool signaled)35{36const struct panfrost_device *pdev = &device->physical_device->pdev;3738struct drm_syncobj_create create = {39.flags = signaled ? DRM_SYNCOBJ_CREATE_SIGNALED : 0,40};4142int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);43if (ret)44return VK_ERROR_OUT_OF_HOST_MEMORY;4546sync->permanent = create.handle;4748return VK_SUCCESS;49}5051static void52sync_set_temporary(struct panvk_device *device, struct panvk_syncobj *sync,53uint32_t syncobj)54{55const struct panfrost_device *pdev = &device->physical_device->pdev;5657if (sync->temporary) {58struct drm_syncobj_destroy destroy = { .handle = sync->temporary };59drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &destroy);60}6162sync->temporary = syncobj;63}6465static void66sync_destroy(struct panvk_device *device, struct panvk_syncobj *sync)67{68const struct panfrost_device *pdev = &device->physical_device->pdev;6970if (!sync)71return;7273sync_set_temporary(device, sync, 0);74struct drm_syncobj_destroy destroy = { .handle = sync->permanent };75drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &destroy);76}7778static VkResult79sync_import(struct panvk_device *device, struct panvk_syncobj *sync,80bool temporary, bool sync_fd, int fd)81{82const struct panfrost_device *pdev = &device->physical_device->pdev;83int ret;8485if (!sync_fd) {86uint32_t *dst = temporary ? &sync->temporary : &sync->permanent;8788struct drm_syncobj_handle handle = { .fd = fd };89ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &handle);90if (ret)91return VK_ERROR_INVALID_EXTERNAL_HANDLE;9293if (*dst) {94struct drm_syncobj_destroy destroy = { .handle = *dst };95drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &destroy);96}97*dst = handle.handle;98close(fd);99} else {100assert(temporary);101102struct drm_syncobj_create create = {};103104if (fd == -1)105create.flags |= DRM_SYNCOBJ_CREATE_SIGNALED;106107ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);108if (ret)109return VK_ERROR_INVALID_EXTERNAL_HANDLE;110111if (fd != -1) {112struct drm_syncobj_handle handle = {113.fd = fd,114.handle = create.handle,115.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE,116};117118ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &handle);119if (ret) {120struct drm_syncobj_destroy destroy = { .handle = create.handle };121drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &destroy);122return VK_ERROR_INVALID_EXTERNAL_HANDLE;123}124close(fd);125}126127sync_set_temporary(device, sync, create.handle);128}129130return VK_SUCCESS;131}132133static VkResult134sync_export(struct panvk_device *device, struct panvk_syncobj *sync,135bool sync_fd, int *p_fd)136{137const struct panfrost_device *pdev = &device->physical_device->pdev;138139struct drm_syncobj_handle handle = {140.handle = sync->temporary ? : sync->permanent,141.flags = sync_fd ? DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE : 0,142.fd = -1,143};144int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);145if (ret)146return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);147148/* restore permanent payload on export */149sync_set_temporary(device, sync, 0);150151*p_fd = handle.fd;152return VK_SUCCESS;153}154155VkResult156panvk_CreateSemaphore(VkDevice _device,157const VkSemaphoreCreateInfo *pCreateInfo,158const VkAllocationCallbacks *pAllocator,159VkSemaphore *pSemaphore)160{161VK_FROM_HANDLE(panvk_device, device, _device);162struct panvk_semaphore *sem =163vk_object_zalloc(&device->vk, pAllocator, sizeof(*sem),164VK_OBJECT_TYPE_SEMAPHORE);165if (!sem)166return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);167168VkResult ret = sync_create(device, &sem->syncobj, false);169if (ret != VK_SUCCESS) {170vk_free2(&device->vk.alloc, pAllocator, sync);171return ret;172}173174*pSemaphore = panvk_semaphore_to_handle(sem);175return VK_SUCCESS;176}177178void179panvk_DestroySemaphore(VkDevice _device, VkSemaphore _sem, const VkAllocationCallbacks *pAllocator)180{181VK_FROM_HANDLE(panvk_device, device, _device);182VK_FROM_HANDLE(panvk_semaphore, sem, _sem);183184sync_destroy(device, &sem->syncobj);185vk_object_free(&device->vk, pAllocator, sem);186}187188VkResult189panvk_ImportSemaphoreFdKHR(VkDevice _device, const VkImportSemaphoreFdInfoKHR *info)190{191VK_FROM_HANDLE(panvk_device, device, _device);192VK_FROM_HANDLE(panvk_semaphore, sem, info->semaphore);193bool temp = info->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;194bool sync_fd = info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;195196return sync_import(device, &sem->syncobj, temp, sync_fd, info->fd);197}198199VkResult200panvk_GetSemaphoreFdKHR(VkDevice _device, const VkSemaphoreGetFdInfoKHR *info, int *pFd)201{202VK_FROM_HANDLE(panvk_device, device, _device);203VK_FROM_HANDLE(panvk_semaphore, sem, info->semaphore);204bool sync_fd = info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;205206return sync_export(device, &sem->syncobj, sync_fd, pFd);207}208209VkResult210panvk_CreateFence(VkDevice _device,211const VkFenceCreateInfo *info,212const VkAllocationCallbacks *pAllocator,213VkFence *pFence)214{215VK_FROM_HANDLE(panvk_device, device, _device);216struct panvk_fence *fence =217vk_object_zalloc(&device->vk, pAllocator, sizeof(*fence),218VK_OBJECT_TYPE_FENCE);219if (!fence)220return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);221222VkResult ret = sync_create(device, &fence->syncobj,223info->flags & VK_FENCE_CREATE_SIGNALED_BIT);224if (ret != VK_SUCCESS) {225vk_free2(&device->vk.alloc, pAllocator, fence);226return ret;227}228229*pFence = panvk_fence_to_handle(fence);230return VK_SUCCESS;231}232233void234panvk_DestroyFence(VkDevice _device, VkFence _fence,235const VkAllocationCallbacks *pAllocator)236{237VK_FROM_HANDLE(panvk_device, device, _device);238VK_FROM_HANDLE(panvk_fence, fence, _fence);239240sync_destroy(device, &fence->syncobj);241vk_object_free(&device->vk, pAllocator, fence);242}243244VkResult245panvk_ImportFenceFdKHR(VkDevice _device, const VkImportFenceFdInfoKHR *info)246{247VK_FROM_HANDLE(panvk_device, device, _device);248VK_FROM_HANDLE(panvk_fence, fence, info->fence);249bool sync_fd = info->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;250bool temp = info->flags & VK_FENCE_IMPORT_TEMPORARY_BIT;251252return sync_import(device, &fence->syncobj, temp, sync_fd, info->fd);253}254255VkResult256panvk_GetFenceFdKHR(VkDevice _device, const VkFenceGetFdInfoKHR *info, int *pFd)257{258VK_FROM_HANDLE(panvk_device, device, _device);259VK_FROM_HANDLE(panvk_fence, fence, info->fence);260bool sync_fd = info->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;261262return sync_export(device, &fence->syncobj, sync_fd, pFd);263}264265static VkResult266drm_syncobj_wait(struct panvk_device *device,267const uint32_t *handles, uint32_t count_handles,268int64_t timeout_nsec, bool wait_all)269{270const struct panfrost_device *pdev = &device->physical_device->pdev;271struct drm_syncobj_wait wait = {272.handles = (uint64_t) (uintptr_t) handles,273.count_handles = count_handles,274.timeout_nsec = timeout_nsec,275.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |276(wait_all ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL : 0)277};278279int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_WAIT, &wait);280if (ret) {281if (errno == ETIME)282return VK_TIMEOUT;283284assert(0);285return VK_ERROR_DEVICE_LOST; /* TODO */286}287return VK_SUCCESS;288}289290static uint64_t291gettime_ns(void)292{293struct timespec current;294clock_gettime(CLOCK_MONOTONIC, ¤t);295return (uint64_t)current.tv_sec * 1000000000 + current.tv_nsec;296}297298/* and the kernel converts it right back to relative timeout - very smart UAPI */299static uint64_t300absolute_timeout(uint64_t timeout)301{302if (timeout == 0)303return 0;304uint64_t current_time = gettime_ns();305uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;306307timeout = MIN2(max_timeout, timeout);308309return (current_time + timeout);310}311312VkResult313panvk_WaitForFences(VkDevice _device,314uint32_t fenceCount,315const VkFence *pFences,316VkBool32 waitAll,317uint64_t timeout)318{319VK_FROM_HANDLE(panvk_device, device, _device);320321if (panvk_device_is_lost(device))322return VK_ERROR_DEVICE_LOST;323324uint32_t handles[fenceCount];325for (unsigned i = 0; i < fenceCount; ++i) {326VK_FROM_HANDLE(panvk_fence, fence, pFences[i]);327328if (fence->syncobj.temporary) {329handles[i] = fence->syncobj.temporary;330} else {331handles[i] = fence->syncobj.permanent;332}333}334335return drm_syncobj_wait(device, handles, fenceCount, absolute_timeout(timeout), waitAll);336}337338VkResult339panvk_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences)340{341VK_FROM_HANDLE(panvk_device, device, _device);342const struct panfrost_device *pdev = &device->physical_device->pdev;343int ret;344345uint32_t handles[fenceCount];346for (unsigned i = 0; i < fenceCount; ++i) {347VK_FROM_HANDLE(panvk_fence, fence, pFences[i]);348349sync_set_temporary(device, &fence->syncobj, 0);350handles[i] = fence->syncobj.permanent;351}352353struct drm_syncobj_array objs = {354.handles = (uint64_t) (uintptr_t) handles,355.count_handles = fenceCount,356};357358ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_RESET, &objs);359if (ret) {360panvk_device_set_lost(device, "DRM_IOCTL_SYNCOBJ_RESET failure: %s",361strerror(errno));362}363364return VK_SUCCESS;365}366367VkResult368panvk_GetFenceStatus(VkDevice _device, VkFence _fence)369{370VK_FROM_HANDLE(panvk_device, device, _device);371VK_FROM_HANDLE(panvk_fence, fence, _fence);372uint32_t handle = fence->syncobj.temporary ? : fence->syncobj.permanent;373VkResult result;374375result = drm_syncobj_wait(device, &handle, 1, 0, false);376if (result == VK_TIMEOUT)377result = VK_NOT_READY;378return result;379}380381int382panvk_signal_syncobjs(struct panvk_device *device,383struct panvk_syncobj *syncobj1,384struct panvk_syncobj *syncobj2)385{386const struct panfrost_device *pdev = &device->physical_device->pdev;387uint32_t handles[2], count = 0;388389if (syncobj1)390handles[count++] = syncobj1->temporary ?: syncobj1->permanent;391392if (syncobj2)393handles[count++] = syncobj2->temporary ?: syncobj2->permanent;394395if (!count)396return 0;397398struct drm_syncobj_array objs = {399.handles = (uintptr_t) handles,400.count_handles = count401};402403return drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &objs);404}405406int407panvk_syncobj_to_fd(struct panvk_device *device, struct panvk_syncobj *sync)408{409const struct panfrost_device *pdev = &device->physical_device->pdev;410struct drm_syncobj_handle handle = { .handle = sync->permanent };411int ret;412413ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);414415return ret ? -1 : handle.fd;416}417418419