Loading...
Searching...
No Matches
DMABufImport.hpp
1#pragma once
2
3#if defined(__linux__)
4#include <score/gfx/Vulkan.hpp>
5
6#if QT_HAS_VULKAN
7#include <QtGui/private/qrhivulkan_p.h>
8#include <qvulkanfunctions.h>
9#include <vulkan/vulkan.h>
10
11#include <cstring>
12#include <vector>
13
14#include <unistd.h>
15
16#if defined(VK_EXT_image_drm_format_modifier) && defined(VK_KHR_external_memory_fd) \
17 && QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
18
19namespace score::gfx
20{
21
28struct DMABufPlaneImporter
29{
30 VkDevice m_dev{VK_NULL_HANDLE};
31 QVulkanDeviceFunctions* m_dfuncs{};
32 PFN_vkGetMemoryFdPropertiesKHR m_getMemFdProps{};
33
34 struct PlaneImport
35 {
36 VkImage image{VK_NULL_HANDLE};
37 VkDeviceMemory memory{VK_NULL_HANDLE};
38 };
39
40 void init(QRhi& rhi)
41 {
42 auto* nh
43 = static_cast<const QRhiVulkanNativeHandles*>(rhi.nativeHandles());
44 m_dev = nh->dev;
45 m_dfuncs = nh->inst->deviceFunctions(m_dev);
46 m_getMemFdProps = reinterpret_cast<PFN_vkGetMemoryFdPropertiesKHR>(
47 nh->inst->getInstanceProcAddr("vkGetMemoryFdPropertiesKHR"));
48 }
49
50 static bool isAvailable(QRhi& rhi)
51 {
52 if(rhi.backend() != QRhi::Vulkan)
53 return false;
54 auto* nh
55 = static_cast<const QRhiVulkanNativeHandles*>(rhi.nativeHandles());
56 if(!nh || !nh->dev || !nh->physDev || !nh->inst)
57 return false;
58 if(!nh->inst->getInstanceProcAddr("vkGetMemoryFdPropertiesKHR"))
59 return false;
60
61 // Verify VK_EXT_external_memory_dma_buf is available on the device.
62 // Without it, DMA-BUF import (VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)
63 // will fail. This also catches multi-GPU scenarios where VAAPI decodes on
64 // Intel but Vulkan renders on NVIDIA (which may not support DMA-BUF import).
65 auto* funcs = nh->inst->functions();
66 uint32_t extCount = 0;
67 funcs->vkEnumerateDeviceExtensionProperties(
68 nh->physDev, nullptr, &extCount, nullptr);
69 std::vector<VkExtensionProperties> exts(extCount);
70 funcs->vkEnumerateDeviceExtensionProperties(
71 nh->physDev, nullptr, &extCount, exts.data());
72
73 bool hasDmaBuf = false;
74 bool hasDrmModifier = false;
75 for(auto& e : exts)
76 {
77#ifdef VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME
78 if(std::strcmp(e.extensionName, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME) == 0)
79 hasDmaBuf = true;
80#endif
81#ifdef VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
82 if(std::strcmp(e.extensionName, VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) == 0)
83 hasDrmModifier = true;
84#endif
85 }
86 return hasDmaBuf && hasDrmModifier;
87 }
88
89 void cleanupPlane(PlaneImport& p)
90 {
91 if(p.image != VK_NULL_HANDLE)
92 m_dfuncs->vkDestroyImage(m_dev, p.image, nullptr);
93 if(p.memory != VK_NULL_HANDLE)
94 m_dfuncs->vkFreeMemory(m_dev, p.memory, nullptr);
95 p = {};
96 }
97
98 bool importPlane(
99 PlaneImport& out, int fd, uint64_t modifier, ptrdiff_t offset,
100 ptrdiff_t pitch, VkFormat format, int w, int h)
101 {
102 // --- VkImage creation with external memory + DRM format modifier ---
103
104 VkSubresourceLayout planeLayout{};
105 planeLayout.offset = static_cast<VkDeviceSize>(offset);
106 planeLayout.rowPitch = static_cast<VkDeviceSize>(pitch);
107
108 VkImageDrmFormatModifierExplicitCreateInfoEXT modInfo{};
109 modInfo.sType
110 = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
111 modInfo.drmFormatModifier = modifier;
112 modInfo.drmFormatModifierPlaneCount = 1;
113 modInfo.pPlaneLayouts = &planeLayout;
114
115 VkExternalMemoryImageCreateInfo extInfo{};
116 extInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
117 extInfo.pNext = &modInfo;
118 extInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
119
120 VkImageCreateInfo imgInfo{};
121 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
122 imgInfo.pNext = &extInfo;
123 imgInfo.imageType = VK_IMAGE_TYPE_2D;
124 imgInfo.format = format;
125 imgInfo.extent
126 = {static_cast<uint32_t>(w), static_cast<uint32_t>(h), 1};
127 imgInfo.mipLevels = 1;
128 imgInfo.arrayLayers = 1;
129 imgInfo.samples = VK_SAMPLE_COUNT_1_BIT;
130 imgInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
131 imgInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
132 imgInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
133 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
134
135 VkImage image{};
136 if(m_dfuncs->vkCreateImage(m_dev, &imgInfo, nullptr, &image)
137 != VK_SUCCESS)
138 return false;
139
140 // --- Memory import from DMA-BUF fd ---
141
142 VkMemoryRequirements memReqs{};
143 m_dfuncs->vkGetImageMemoryRequirements(m_dev, image, &memReqs);
144
145 int dupFd = dup(fd);
146 if(dupFd < 0)
147 {
148 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
149 return false;
150 }
151
152 VkMemoryFdPropertiesKHR fdProps{};
153 fdProps.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
154 if(m_getMemFdProps(
155 m_dev, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, dupFd,
156 &fdProps)
157 != VK_SUCCESS)
158 {
159 close(dupFd);
160 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
161 return false;
162 }
163
164 uint32_t memTypeIdx = UINT32_MAX;
165 uint32_t compatible = memReqs.memoryTypeBits & fdProps.memoryTypeBits;
166 for(uint32_t i = 0; i < 32; ++i)
167 {
168 if(compatible & (1u << i))
169 {
170 memTypeIdx = i;
171 break;
172 }
173 }
174 if(memTypeIdx == UINT32_MAX)
175 {
176 close(dupFd);
177 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
178 return false;
179 }
180
181 VkImportMemoryFdInfoKHR importInfo{};
182 importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
183 importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
184 importInfo.fd = dupFd;
185
186 VkMemoryDedicatedAllocateInfo dedicatedInfo{};
187 dedicatedInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
188 dedicatedInfo.pNext = &importInfo;
189 dedicatedInfo.image = image;
190
191 VkMemoryAllocateInfo allocInfo{};
192 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
193 allocInfo.pNext = &dedicatedInfo;
194 allocInfo.allocationSize = memReqs.size;
195 allocInfo.memoryTypeIndex = memTypeIdx;
196
197 VkDeviceMemory memory{};
198 if(m_dfuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &memory)
199 != VK_SUCCESS)
200 {
201 close(dupFd);
202 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
203 return false;
204 }
205
206 if(m_dfuncs->vkBindImageMemory(m_dev, image, memory, 0) != VK_SUCCESS)
207 {
208 m_dfuncs->vkFreeMemory(m_dev, memory, nullptr);
209 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
210 return false;
211 }
212
213 out.image = image;
214 out.memory = memory;
215 return true;
216 }
217};
218
219} // namespace score::gfx
220
221#endif // VK_EXT_image_drm_format_modifier && VK_KHR_external_memory_fd
222#endif // QT_HAS_VULKAN
223#endif // __linux__
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12