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 <Gfx/Graph/VulkanVideoDevice.hpp>
8
9#include <QtGui/private/qrhivulkan_p.h>
10#include <qvulkanfunctions.h>
11#include <vulkan/vulkan.h>
12
13#include <cstring>
14#include <vector>
15
16#include <unistd.h>
17
18#if defined(VK_EXT_image_drm_format_modifier) && defined(VK_KHR_external_memory_fd) \
19 && QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
20
21namespace score::gfx
22{
23
30struct DMABufPlaneImporter
31{
32 VkDevice m_dev{VK_NULL_HANDLE};
33 QVulkanDeviceFunctions* m_dfuncs{};
34 PFN_vkGetMemoryFdPropertiesKHR m_getMemFdProps{};
35
36 struct PlaneImport
37 {
38 VkImage image{VK_NULL_HANDLE};
39 VkDeviceMemory memory{VK_NULL_HANDLE};
40 };
41
42 void init(QRhi& rhi)
43 {
44 auto* nh
45 = static_cast<const QRhiVulkanNativeHandles*>(rhi.nativeHandles());
46 m_dev = nh->dev;
47 m_dfuncs = nh->inst->deviceFunctions(m_dev);
48 m_getMemFdProps = reinterpret_cast<PFN_vkGetMemoryFdPropertiesKHR>(
49 vulkanDeviceCommand(rhi, "vkGetMemoryFdPropertiesKHR"));
50 }
51
52 static bool isAvailable(QRhi& rhi)
53 {
54 if(rhi.backend() != QRhi::Vulkan)
55 return false;
56 auto* nh
57 = static_cast<const QRhiVulkanNativeHandles*>(rhi.nativeHandles());
58 if(!nh || !nh->dev || !nh->physDev || !nh->inst)
59 return false;
60 // Only the device knows what it enabled: external_memory_fd and image_drm_format_modifier.
61 if(!vulkanDeviceCommand(rhi, "vkGetMemoryFdPropertiesKHR")
62 || !vulkanDeviceCommand(rhi, "vkGetImageDrmFormatModifierPropertiesEXT"))
63 return false;
64
65 // VK_EXT_external_memory_dma_buf has no command to resolve, so check the physical device supports it (multi-GPU: VAAPI on one, Vulkan on another).
66 auto* funcs = nh->inst->functions();
67 uint32_t extCount = 0;
68 funcs->vkEnumerateDeviceExtensionProperties(
69 nh->physDev, nullptr, &extCount, nullptr);
70 std::vector<VkExtensionProperties> exts(extCount);
71 funcs->vkEnumerateDeviceExtensionProperties(
72 nh->physDev, nullptr, &extCount, exts.data());
73
74 bool hasDmaBuf = 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 }
82 return hasDmaBuf;
83 }
84
88 static std::uint32_t driverId(QRhi& rhi) noexcept
89 {
90#if defined(VK_KHR_driver_properties) || defined(VK_VERSION_1_2)
91 if(rhi.backend() != QRhi::Vulkan)
92 return 0;
93 auto* nh = static_cast<const QRhiVulkanNativeHandles*>(rhi.nativeHandles());
94 if(!nh || !nh->physDev || !nh->inst)
95 return 0;
96 auto getProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
97 nh->inst->getInstanceProcAddr("vkGetPhysicalDeviceProperties2"));
98 if(!getProps2)
99 getProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
100 nh->inst->getInstanceProcAddr("vkGetPhysicalDeviceProperties2KHR"));
101 if(!getProps2)
102 return 0;
103
104 VkPhysicalDeviceDriverProperties drv{};
105 drv.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
106 VkPhysicalDeviceProperties2 props{};
107 props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
108 props.pNext = &drv;
109 getProps2(nh->physDev, &props);
110 return static_cast<std::uint32_t>(drv.driverID);
111#else
112 (void)rhi;
113 return 0;
114#endif
115 }
116
122 void waitIdle() noexcept
123 {
124 if(m_dfuncs && m_dev != VK_NULL_HANDLE)
125 m_dfuncs->vkDeviceWaitIdle(m_dev);
126 }
127
128 void cleanupPlane(PlaneImport& p)
129 {
130 if(p.image != VK_NULL_HANDLE)
131 m_dfuncs->vkDestroyImage(m_dev, p.image, nullptr);
132 if(p.memory != VK_NULL_HANDLE)
133 m_dfuncs->vkFreeMemory(m_dev, p.memory, nullptr);
134 p = {};
135 }
136
137 bool importPlane(
138 PlaneImport& out, int fd, uint64_t modifier, ptrdiff_t offset,
139 ptrdiff_t pitch, VkFormat format, int w, int h)
140 {
141 // --- VkImage creation with external memory + DRM format modifier ---
142
143 VkSubresourceLayout planeLayout{};
144 planeLayout.offset = static_cast<VkDeviceSize>(offset);
145 planeLayout.rowPitch = static_cast<VkDeviceSize>(pitch);
146
147 VkImageDrmFormatModifierExplicitCreateInfoEXT modInfo{};
148 modInfo.sType
149 = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
150 modInfo.drmFormatModifier = modifier;
151 modInfo.drmFormatModifierPlaneCount = 1;
152 modInfo.pPlaneLayouts = &planeLayout;
153
154 VkExternalMemoryImageCreateInfo extInfo{};
155 extInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
156 extInfo.pNext = &modInfo;
157 extInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
158
159 VkImageCreateInfo imgInfo{};
160 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
161 imgInfo.pNext = &extInfo;
162 imgInfo.imageType = VK_IMAGE_TYPE_2D;
163 imgInfo.format = format;
164 imgInfo.extent
165 = {static_cast<uint32_t>(w), static_cast<uint32_t>(h), 1};
166 imgInfo.mipLevels = 1;
167 imgInfo.arrayLayers = 1;
168 imgInfo.samples = VK_SAMPLE_COUNT_1_BIT;
169 imgInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
170 imgInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
171 imgInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
172 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
173
174 VkImage image{};
175 if(m_dfuncs->vkCreateImage(m_dev, &imgInfo, nullptr, &image)
176 != VK_SUCCESS)
177 return false;
178
179 // --- Memory import from DMA-BUF fd ---
180
181 VkMemoryRequirements memReqs{};
182 m_dfuncs->vkGetImageMemoryRequirements(m_dev, image, &memReqs);
183
184 int dupFd = dup(fd);
185 if(dupFd < 0)
186 {
187 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
188 return false;
189 }
190
191 VkMemoryFdPropertiesKHR fdProps{};
192 fdProps.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
193 if(m_getMemFdProps(
194 m_dev, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, dupFd,
195 &fdProps)
196 != VK_SUCCESS)
197 {
198 close(dupFd);
199 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
200 return false;
201 }
202
203 uint32_t memTypeIdx = UINT32_MAX;
204 uint32_t compatible = memReqs.memoryTypeBits & fdProps.memoryTypeBits;
205 for(uint32_t i = 0; i < 32; ++i)
206 {
207 if(compatible & (1u << i))
208 {
209 memTypeIdx = i;
210 break;
211 }
212 }
213 if(memTypeIdx == UINT32_MAX)
214 {
215 close(dupFd);
216 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
217 return false;
218 }
219
220 VkImportMemoryFdInfoKHR importInfo{};
221 importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
222 importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
223 importInfo.fd = dupFd;
224
225 VkMemoryDedicatedAllocateInfo dedicatedInfo{};
226 dedicatedInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
227 dedicatedInfo.pNext = &importInfo;
228 dedicatedInfo.image = image;
229
230 VkMemoryAllocateInfo allocInfo{};
231 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
232 allocInfo.pNext = &dedicatedInfo;
233 allocInfo.allocationSize = memReqs.size;
234 allocInfo.memoryTypeIndex = memTypeIdx;
235
236 VkDeviceMemory memory{};
237 if(m_dfuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &memory)
238 != VK_SUCCESS)
239 {
240 close(dupFd);
241 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
242 return false;
243 }
244
245 if(m_dfuncs->vkBindImageMemory(m_dev, image, memory, 0) != VK_SUCCESS)
246 {
247 m_dfuncs->vkFreeMemory(m_dev, memory, nullptr);
248 m_dfuncs->vkDestroyImage(m_dev, image, nullptr);
249 return false;
250 }
251
252 out.image = image;
253 out.memory = memory;
254 return true;
255 }
256};
257
258} // namespace score::gfx
259
260#endif // VK_EXT_image_drm_format_modifier && VK_KHR_external_memory_fd
261#endif // QT_HAS_VULKAN
262#endif // __linux__
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11