From de89436216e178b616aa3969e3d68b24b60602fd Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Thu, 31 Jan 2019 15:03:03 -0800 Subject: [PATCH] turnip: add functions to import/export prime fd Add tu_bo_init_dmabuf, tu_bo_export_dmabuf, tu_gem_import_dmabuf, and tu_gem_export_dmabuf. --- src/freedreno/vulkan/tu_device.c | 65 ++++++++++++++++++++++++------- src/freedreno/vulkan/tu_drm.c | 29 ++++++++++++++ src/freedreno/vulkan/tu_private.h | 13 +++++++ 3 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/freedreno/vulkan/tu_device.c b/src/freedreno/vulkan/tu_device.c index 072da76a602..c728f397d5d 100644 --- a/src/freedreno/vulkan/tu_device.c +++ b/src/freedreno/vulkan/tu_device.c @@ -73,19 +73,15 @@ tu_get_device_uuid(void *uuid) memset(uuid, 0, VK_UUID_SIZE); } -VkResult -tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size) +static VkResult +tu_bo_init(struct tu_device *dev, + struct tu_bo *bo, + uint32_t gem_handle, + uint64_t size) { - /* TODO: Choose better flags. As of 2018-11-12, freedreno/drm/msm_bo.c - * always sets `flags = MSM_BO_WC`, and we copy that behavior here. - */ - uint32_t gem_handle = tu_gem_new(dev, size, MSM_BO_WC); - if (!gem_handle) - goto fail_new; - uint64_t iova = tu_gem_info_iova(dev, gem_handle); if (!iova) - goto fail_info; + return VK_ERROR_OUT_OF_DEVICE_MEMORY; *bo = (struct tu_bo) { .gem_handle = gem_handle, @@ -94,11 +90,50 @@ tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size) }; return VK_SUCCESS; +} -fail_info: - tu_gem_close(dev, bo->gem_handle); -fail_new: - return vk_error(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY); +VkResult +tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size) +{ + /* TODO: Choose better flags. As of 2018-11-12, freedreno/drm/msm_bo.c + * always sets `flags = MSM_BO_WC`, and we copy that behavior here. + */ + uint32_t gem_handle = tu_gem_new(dev, size, MSM_BO_WC); + if (!gem_handle) + return vk_error(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY); + + VkResult result = tu_bo_init(dev, bo, gem_handle, size); + if (result != VK_SUCCESS) { + tu_gem_close(dev, gem_handle); + return vk_error(dev->instance, result); + } + + return VK_SUCCESS; +} + +VkResult +tu_bo_init_dmabuf(struct tu_device *dev, + struct tu_bo *bo, + uint64_t size, + int fd) +{ + uint32_t gem_handle = tu_gem_import_dmabuf(dev, fd, size); + if (!gem_handle) + return vk_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE); + + VkResult result = tu_bo_init(dev, bo, gem_handle, size); + if (result != VK_SUCCESS) { + tu_gem_close(dev, gem_handle); + return vk_error(dev->instance, result); + } + + return VK_SUCCESS; +} + +int +tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo) +{ + return tu_gem_export_dmabuf(dev, bo->gem_handle); } VkResult @@ -109,7 +144,7 @@ tu_bo_map(struct tu_device *dev, struct tu_bo *bo) uint64_t offset = tu_gem_info_offset(dev, bo->gem_handle); if (!offset) - return vk_error(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY); + return vk_error(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY); /* TODO: Should we use the wrapper os_mmap() like Freedreno does? */ void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, diff --git a/src/freedreno/vulkan/tu_drm.c b/src/freedreno/vulkan/tu_drm.c index c103561ef1a..6904b011e71 100644 --- a/src/freedreno/vulkan/tu_drm.c +++ b/src/freedreno/vulkan/tu_drm.c @@ -25,6 +25,7 @@ #include "tu_private.h" #include +#include #include #include #include @@ -123,6 +124,34 @@ tu_gem_new(const struct tu_device *dev, uint64_t size, uint32_t flags) return req.handle; } +uint32_t +tu_gem_import_dmabuf(const struct tu_device *dev, int prime_fd, uint64_t size) +{ + /* lseek() to get the real size */ + off_t real_size = lseek(prime_fd, 0, SEEK_END); + lseek(prime_fd, 0, SEEK_SET); + if (real_size < 0 || (uint64_t) real_size < size) + return 0; + + uint32_t gem_handle; + int ret = drmPrimeFDToHandle(dev->physical_device->local_fd, prime_fd, + &gem_handle); + if (ret) + return 0; + + return gem_handle; +} + +int +tu_gem_export_dmabuf(const struct tu_device *dev, uint32_t gem_handle) +{ + int prime_fd; + int ret = drmPrimeHandleToFD(dev->physical_device->local_fd, gem_handle, + DRM_CLOEXEC, &prime_fd); + + return ret == 0 ? prime_fd : -1; +} + void tu_gem_close(const struct tu_device *dev, uint32_t gem_handle) { diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 51b52848daf..62f7cf28004 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -442,6 +442,13 @@ struct tu_bo VkResult tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size); +VkResult +tu_bo_init_dmabuf(struct tu_device *dev, + struct tu_bo *bo, + uint64_t size, + int fd); +int +tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo); void tu_bo_finish(struct tu_device *dev, struct tu_bo *bo); VkResult @@ -1315,6 +1322,12 @@ tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id); uint32_t tu_gem_new(const struct tu_device *dev, uint64_t size, uint32_t flags); +uint32_t +tu_gem_import_dmabuf(const struct tu_device *dev, + int prime_fd, + uint64_t size); +int +tu_gem_export_dmabuf(const struct tu_device *dev, uint32_t gem_handle); void tu_gem_close(const struct tu_device *dev, uint32_t gem_handle); uint64_t