2#include <score/gfx/Vulkan.hpp>
4#if QT_HAS_VULKAN && QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
6#include <QtGui/private/qrhivulkan_p.h>
7#include <qvulkanfunctions.h>
8#include <vulkan/vulkan.h>
10#if __has_include(<vulkan/vulkan_win32.h>)
11#include <vulkan/vulkan.h>
13#include <vulkan/vulkan_win32.h>
17#include <QCoreApplication>
29inline std::vector<const char*> qtQuickVulkanDeviceExtensions()
32 VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
33#if defined(_WIN32) && defined(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME)
34 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
36 VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
37 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
42inline PFN_vkVoidFunction vulkanDeviceCommand(QRhi& rhi,
const char* name)
44 if(rhi.backend() != QRhi::Vulkan)
46 auto* nh =
static_cast<const QRhiVulkanNativeHandles*
>(rhi.nativeHandles());
47 if(!nh || !nh->inst || !nh->dev)
49 return nh->inst->functions()->vkGetDeviceProcAddr(nh->dev, name);
53#ifdef VK_KHR_video_decode_queue
58inline double sharedVulkanDeviceTraceClockMs()
60 return std::chrono::duration<double, std::milli>(
61 std::chrono::steady_clock::now().time_since_epoch())
68inline bool sharedVulkanDeviceCacheDisabled()
71 = qEnvironmentVariableIsSet(
"SCORE_GFX_NO_VKDEVICE_CACHE");
76inline void destroySharedVulkanDevice(QVulkanInstance* inst, VkDevice dev)
78 if(!inst || dev == VK_NULL_HANDLE)
80 auto fn =
reinterpret_cast<PFN_vkDestroyDevice
>(
81 inst->getInstanceProcAddr(
"vkDestroyDevice"));
85 const double t0 = sharedVulkanDeviceTraceClockMs();
97struct SharedVulkanDevice
99 VkPhysicalDevice physDev{VK_NULL_HANDLE};
100 VkDevice dev{VK_NULL_HANDLE};
101 VkQueue gfxQueue{VK_NULL_HANDLE};
102 uint32_t gfxQueueFamilyIdx{0};
103 bool hasVideoDecodeQueue{
false};
108 bool timelineSemaphores{
false};
109 uint32_t videoDecodeQueueFamilyIdx{0};
112 std::vector<std::string> enabledExtensions;
115 struct QueueFamilyInfo
121 std::vector<QueueFamilyInfo> queueFamilies;
123 void destroy() { destroy(staticVulkanInstance(
false)); }
125 void destroy(QVulkanInstance* inst)
127 destroySharedVulkanDevice(inst, dev);
128 dev = VK_NULL_HANDLE;
131 explicit operator bool()
const {
return dev != VK_NULL_HANDLE; }
141inline std::vector<const char*> sharedVulkanDeviceExtensions()
143 auto exts = qtQuickVulkanDeviceExtensions();
144 exts.insert(exts.end(), {
146 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
147#ifdef VK_KHR_MAINTENANCE_1_EXTENSION_NAME
148 VK_KHR_MAINTENANCE_1_EXTENSION_NAME,
150#ifdef VK_KHR_MAINTENANCE_2_EXTENSION_NAME
151 VK_KHR_MAINTENANCE_2_EXTENSION_NAME,
153#ifdef VK_KHR_MAINTENANCE_3_EXTENSION_NAME
154 VK_KHR_MAINTENANCE_3_EXTENSION_NAME,
156#ifdef VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME
157 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
159#ifdef VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME
160 VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME,
162#ifdef VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME
163 VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME,
165#ifdef VK_KHR_MULTIVIEW_EXTENSION_NAME
166 VK_KHR_MULTIVIEW_EXTENSION_NAME,
168#ifdef VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME
169 VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
171#ifdef VK_KHR_SPIRV_1_4_EXTENSION_NAME
172 VK_KHR_SPIRV_1_4_EXTENSION_NAME,
174#ifdef VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME
175 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
178 VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
179#ifdef VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME
180 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
182#ifdef VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME
183 VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
185#ifdef VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME
186 VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
188#ifdef VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME
189 VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
191#ifdef VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
192 VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
194#ifdef VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME
195 VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
198 VK_KHR_VIDEO_QUEUE_EXTENSION_NAME,
199 VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
200#ifdef VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME
201 VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
203#ifdef VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME
204 VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
206#ifdef VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME
207 VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME,
210 VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
211 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
213#ifdef VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME
214 VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
216#ifdef VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME
217 VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
219#ifdef VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME
220 VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
222#ifdef VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME
223 VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME,
225#ifdef VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME
226 VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME,
228#ifdef VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME
229 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
231#ifdef VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME
232 VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME,
234#ifdef VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME
235 VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
237#ifdef VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME
238 VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
252inline VkPhysicalDevice resolveSharedVulkanPhysicalDevice(
253 QVulkanInstance* inst, VkPhysicalDevice preferredPhysDev = VK_NULL_HANDLE)
256 return VK_NULL_HANDLE;
257 if(preferredPhysDev != VK_NULL_HANDLE)
258 return preferredPhysDev;
260 auto* funcs = inst->functions();
262 return VK_NULL_HANDLE;
264 uint32_t devCount = 0;
265 funcs->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount,
nullptr);
267 return VK_NULL_HANDLE;
269 std::vector<VkPhysicalDevice> physDevs(devCount);
270 funcs->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, physDevs.data());
273 const int idx = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX", &ok);
274 if(ok && idx >= 0 && uint32_t(idx) < devCount)
275 return physDevs[uint32_t(idx)];
292inline SharedVulkanDevice createSharedVulkanDevice(
293 QVulkanInstance* inst, VkPhysicalDevice preferredPhysDev = VK_NULL_HANDLE)
295 SharedVulkanDevice result;
299 auto* funcs = inst->functions();
309 result.physDev = resolveSharedVulkanPhysicalDevice(inst, preferredPhysDev);
310 if(result.physDev == VK_NULL_HANDLE)
313 uint32_t qfCount = 0;
314 funcs->vkGetPhysicalDeviceQueueFamilyProperties(
315 result.physDev, &qfCount,
nullptr);
319 std::vector<VkQueueFamilyProperties> qfProps(qfCount);
320 funcs->vkGetPhysicalDeviceQueueFamilyProperties(
321 result.physDev, &qfCount, qfProps.data());
323 bool foundGfx =
false;
324 for(uint32_t i = 0; i < qfCount; i++)
326 if(!foundGfx && (qfProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
328 result.gfxQueueFamilyIdx = i;
331 if(qfProps[i].queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR)
333 result.hasVideoDecodeQueue =
true;
334 result.videoDecodeQueueFamilyIdx = i;
338 if(!foundGfx || !result.hasVideoDecodeQueue)
343 uint32_t extCount = 0;
344 funcs->vkEnumerateDeviceExtensionProperties(
345 result.physDev,
nullptr, &extCount,
nullptr);
346 std::vector<VkExtensionProperties> avail(extCount);
347 funcs->vkEnumerateDeviceExtensionProperties(
348 result.physDev,
nullptr, &extCount, avail.data());
350 auto hasExt = [&](
const char* name) {
352 if(
std::strcmp(e.extensionName, name) == 0)
361 auto wantedExtensions = sharedVulkanDeviceExtensions();
362 std::vector<const char*> extPtrs;
363 for(
auto* ext : wantedExtensions)
367 result.enabledExtensions.push_back(ext);
368 extPtrs.push_back(ext);
374 auto vkGetPhysicalDeviceFeatures2Fn
375 =
reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2
>(
376 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFeatures2"));
377 if(!vkGetPhysicalDeviceFeatures2Fn)
381 VkPhysicalDeviceVulkan13Features vk13{};
382 vk13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
384 VkPhysicalDeviceVulkan12Features vk12{};
385 vk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
388 VkPhysicalDeviceVulkan11Features vk11{};
389 vk11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
392 VkPhysicalDeviceFeatures2 features2{};
393 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
394 features2.pNext = &vk11;
397 vkGetPhysicalDeviceFeatures2Fn(result.physDev, &features2);
398 result.timelineSemaphores = vk12.timelineSemaphore == VK_TRUE;
403 features2.features.robustBufferAccess = VK_FALSE;
404 vk13.robustImageAccess = VK_FALSE;
408 std::vector<VkDeviceQueueCreateInfo> queueInfos;
409 float priority = 1.0f;
410 for(uint32_t i = 0; i < qfCount; i++)
412 VkDeviceQueueCreateInfo qi{};
413 qi.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
414 qi.queueFamilyIndex = i;
416 qi.pQueuePriorities = &priority;
417 queueInfos.push_back(qi);
419 result.queueFamilies.push_back(
420 {i, 1, qfProps[i].queueFlags});
425 VkDeviceCreateInfo devInfo{};
426 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
427 devInfo.pNext = &features2;
428 devInfo.queueCreateInfoCount =
static_cast<uint32_t
>(queueInfos.size());
429 devInfo.pQueueCreateInfos = queueInfos.data();
430 devInfo.enabledExtensionCount =
static_cast<uint32_t
>(extPtrs.size());
431 devInfo.ppEnabledExtensionNames = extPtrs.data();
433 auto vkCreateDeviceFn =
reinterpret_cast<PFN_vkCreateDevice
>(
434 inst->getInstanceProcAddr(
"vkCreateDevice"));
435 if(!vkCreateDeviceFn)
438 const double t0 = sharedVulkanDeviceTraceClockMs();
440 = vkCreateDeviceFn(result.physDev, &devInfo,
nullptr, &result.dev);
441 if(vkResult != VK_SUCCESS)
443 qDebug() <<
"createSharedVulkanDevice: vkCreateDevice failed:" << vkResult;
444 result.dev = VK_NULL_HANDLE;
450 auto vkGetDeviceQueueFn =
reinterpret_cast<PFN_vkGetDeviceQueue
>(
451 inst->getInstanceProcAddr(
"vkGetDeviceQueue"));
452 if(vkGetDeviceQueueFn)
454 result.dev, result.gfxQueueFamilyIdx, 0, &result.gfxQueue);
476class SharedVulkanDeviceCache;
477inline SharedVulkanDeviceCache& sharedVulkanDeviceCache();
479class SharedVulkanDeviceCache
487 acquire(QVulkanInstance* inst, VkPhysicalDevice preferredPhysDev = VK_NULL_HANDLE)
492 const VkPhysicalDevice physDev
493 = resolveSharedVulkanPhysicalDevice(inst, preferredPhysDev);
494 if(physDev == VK_NULL_HANDLE)
497 std::lock_guard lock{m_mutex};
498 for(
auto& e : m_entries)
500 if(e.inst == inst && e.device.physDev == physDev)
507 SharedVulkanDevice dev = createSharedVulkanDevice(inst, physDev);
514 m_entries.push_back(Entry{.inst = inst, .device = dev, .refcount = 1});
518 qAddPostRoutine([] { sharedVulkanDeviceCache().shutdown(); });
523 void release(VkDevice dev)
525 if(dev == VK_NULL_HANDLE)
527 std::lock_guard lock{m_mutex};
528 for(
auto& e : m_entries)
530 if(e.device.dev == dev)
544 std::lock_guard lock{m_mutex};
545 std::vector<Entry> stillUsed;
546 for(
auto& e : m_entries)
553 qWarning() <<
"SharedVulkanDeviceCache: device still referenced at "
554 "shutdown, refcount ="
556 stillUsed.push_back(e);
559 e.device.destroy(e.inst);
561 m_entries = std::move(stillUsed);
562 m_created = int(m_entries.size());
569 int createdDeviceCount()
const
571 std::lock_guard lock{m_mutex};
578 QVulkanInstance* inst{};
579 SharedVulkanDevice device;
583 mutable std::mutex m_mutex;
584 std::vector<Entry> m_entries;
588inline SharedVulkanDeviceCache& sharedVulkanDeviceCache()
590 static SharedVulkanDeviceCache cache;
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11