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
92 static std::uint32_t driverId(QRhi& rhi) noexcept
93 {
94#if defined(VK_KHR_driver_properties) || defined(VK_VERSION_1_2)
95 if(rhi.backend() != QRhi::Vulkan)
96 return 0;
97 auto* nh = static_cast<const QRhiVulkanNativeHandles*>(rhi.nativeHandles());
98 if(!nh || !nh->physDev || !nh->inst)
99 return 0;
100 auto getProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
101 nh->inst->getInstanceProcAddr("vkGetPhysicalDeviceProperties2"));
102 if(!getProps2)
103 getProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
104 nh->inst->getInstanceProcAddr("vkGetPhysicalDeviceProperties2KHR"));
105 if(!getProps2)
106 return 0;
107
108 VkPhysicalDeviceDriverProperties drv{};
109 drv.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
110 VkPhysicalDeviceProperties2 props{};
111 props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
112 props.pNext = &drv;
113 getProps2(nh->physDev, &props);
114 return static_cast<std::uint32_t>(drv.driverID);
115#else
116 (void)rhi;
117 return 0;
118#endif
119 }
120
126 void waitIdle() noexcept
127 {
128 if(m_dfuncs && m_dev != VK_NULL_HANDLE)
129 m_dfuncs->vkDeviceWaitIdle(m_dev);
130 }
131
132 void cleanupPlane(PlaneImport& p)
133 {
134 if(p.image != VK_NULL_HANDLE)
135 m_dfuncs->vkDestroyImage(m_dev, p.image, nullptr);
136 if(p.memory != VK_NULL_HANDLE)
137 m_dfuncs->vkFreeMemory(m_dev, p.memory, nullptr);
138 p = {};
139 }
140
141 bool importPlane(
142 PlaneImport& out, int fd, uint64_t modifier, ptrdiff_t offset,
143 ptrdiff_t pitch, VkFormat format, int w, int h)
144 {
145 // --- VkImage creation with external memory + DRM format modifier ---
146
147 VkSubresourceLayout planeLayout{};
148 planeLayout.offset = static_cast<VkDeviceSize>(offset);
149 planeLayout.rowPitch = static_cast<VkDeviceSize>(pitch);
150
151 VkImageDrmFormatModifierExplicitCreateInfoEXT modInfo{};
152 modInfo.sType
153 = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
154 modInfo.drmFormatModifier = modifier;
155 modInfo.drmFormatModifierPlaneCount = 1;
156 modInfo.pPlaneLayouts = &planeLayout;
157
158 VkExternalMemoryImageCreateInfo extInfo{};
159 extInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
160 extInfo.pNext = &modInfo;
161 extInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
162
163 VkImageCreateInfo imgInfo{};
164 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
165 imgInfo.pNext = &extInfo;
166 imgInfo.imageType = VK_IMAGE_TYPE_2D;
167 imgInfo.format = format;
168 imgInfo.extent
169 = {static_cast<uint32_t>(w), static_cast<uint32_t>(h), 1};
170 imgInfo.mipLevels = 1;
171 imgInfo.arrayLayers = 1;
172 imgInfo.samples = VK_SAMPLE_COUNT_1_BIT;
173 imgInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
174 imgInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
175 imgInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
176 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
177
178 VkImage image{};
179 if(m_dfuncs->vkCreateImage(m_dev, &imgInfo, nullptr, &image)
180 != VK_SUCCESS)
181 return false;
182
183 // --- Memory import from DMA-BUF fd ---
184
185 VkMemoryRequirements memReqs{};
186 m_dfuncs->vkGetImageMemoryRequirements(m_dev, image, &memReqs);
187
188 int dupFd = dup(fd);
189 if(dupFd < 0)
190 {
191 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
192 return false;
193 }
194
195 VkMemoryFdPropertiesKHR fdProps{};
196 fdProps.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
197 if(m_getMemFdProps(
198 m_dev, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, dupFd,
199 &fdProps)
200 != VK_SUCCESS)
201 {
202 close(dupFd);
203 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
204 return false;
205 }
206
207 uint32_t memTypeIdx = UINT32_MAX;
208 uint32_t compatible = memReqs.memoryTypeBits & fdProps.memoryTypeBits;
209 for(uint32_t i = 0; i < 32; ++i)
210 {
211 if(compatible & (1u << i))
212 {
213 memTypeIdx = i;
214 break;
215 }
216 }
217 if(memTypeIdx == UINT32_MAX)
218 {
219 close(dupFd);
220 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
221 return false;
222 }
223
224 VkImportMemoryFdInfoKHR importInfo{};
225 importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
226 importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
227 importInfo.fd = dupFd;
228
229 VkMemoryDedicatedAllocateInfo dedicatedInfo{};
230 dedicatedInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
231 dedicatedInfo.pNext = &importInfo;
232 dedicatedInfo.image = image;
233
234 VkMemoryAllocateInfo allocInfo{};
235 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
236 allocInfo.pNext = &dedicatedInfo;
237 allocInfo.allocationSize = memReqs.size;
238 allocInfo.memoryTypeIndex = memTypeIdx;
239
240 VkDeviceMemory memory{};
241 if(m_dfuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &memory)
242 != VK_SUCCESS)
243 {
244 close(dupFd);
245 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
246 return false;
247 }
248
249 if(m_dfuncs->vkBindImageMemory(m_dev, image, memory, 0) != VK_SUCCESS)
250 {
251 m_dfuncs->vkFreeMemory(m_dev, memory, nullptr);
252 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
253 return false;
254 }
255
256 out.image = image;
257 out.memory = memory;
258 return true;
259 }
260};
261
262} // namespace score::gfx
263
264#endif // VK_EXT_image_drm_format_modifier && VK_KHR_external_memory_fd
265#endif // QT_HAS_VULKAN
266#endif // __linux__
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11