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>
26#ifdef VK_KHR_video_decode_queue
33inline bool sharedVulkanDeviceTraceEnabled()
35 static const bool on = qEnvironmentVariableIsSet(
"SCORE_GFX_VKDEVICE_TRACE");
39inline double sharedVulkanDeviceTraceClockMs()
41 return std::chrono::duration<double, std::milli>(
42 std::chrono::steady_clock::now().time_since_epoch())
49inline bool sharedVulkanDeviceCacheDisabled()
52 = qEnvironmentVariableIsSet(
"SCORE_GFX_NO_VKDEVICE_CACHE");
57inline void destroySharedVulkanDevice(QVulkanInstance* inst, VkDevice dev)
59 if(!inst || dev == VK_NULL_HANDLE)
61 auto fn =
reinterpret_cast<PFN_vkDestroyDevice
>(
62 inst->getInstanceProcAddr(
"vkDestroyDevice"));
66 const double t0 = sharedVulkanDeviceTraceClockMs();
68 if(sharedVulkanDeviceTraceEnabled())
70 const double t1 = sharedVulkanDeviceTraceClockMs();
72 "%.3f VKDEV vkDestroyDevice %.2f ms dev=%p", t1, t1 - t0, (
void*)dev);
84struct SharedVulkanDevice
86 VkPhysicalDevice physDev{VK_NULL_HANDLE};
87 VkDevice dev{VK_NULL_HANDLE};
88 VkQueue gfxQueue{VK_NULL_HANDLE};
89 uint32_t gfxQueueFamilyIdx{0};
90 bool hasVideoDecodeQueue{
false};
95 bool timelineSemaphores{
false};
96 uint32_t videoDecodeQueueFamilyIdx{0};
99 std::vector<std::string> enabledExtensions;
102 struct QueueFamilyInfo
108 std::vector<QueueFamilyInfo> queueFamilies;
110 void destroy() { destroy(staticVulkanInstance(
false)); }
112 void destroy(QVulkanInstance* inst)
114 destroySharedVulkanDevice(inst, dev);
115 dev = VK_NULL_HANDLE;
118 explicit operator bool()
const {
return dev != VK_NULL_HANDLE; }
128inline std::vector<const char*> sharedVulkanDeviceExtensions()
132 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
133#ifdef VK_KHR_MAINTENANCE_1_EXTENSION_NAME
134 VK_KHR_MAINTENANCE_1_EXTENSION_NAME,
136#ifdef VK_KHR_MAINTENANCE_2_EXTENSION_NAME
137 VK_KHR_MAINTENANCE_2_EXTENSION_NAME,
139#ifdef VK_KHR_MAINTENANCE_3_EXTENSION_NAME
140 VK_KHR_MAINTENANCE_3_EXTENSION_NAME,
142#ifdef VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME
143 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
145#ifdef VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME
146 VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME,
148#ifdef VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME
149 VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME,
151#ifdef VK_KHR_MULTIVIEW_EXTENSION_NAME
152 VK_KHR_MULTIVIEW_EXTENSION_NAME,
154#ifdef VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME
155 VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
157#ifdef VK_KHR_SPIRV_1_4_EXTENSION_NAME
158 VK_KHR_SPIRV_1_4_EXTENSION_NAME,
160#ifdef VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME
161 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
164 VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
165 VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
166#ifdef VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME
167 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
169#ifdef VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME
170 VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
172#ifdef VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME
173 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
175#ifdef VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME
176 VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
178#ifdef VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME
179 VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
181#ifdef VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
182 VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
184#ifdef VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME
185 VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
187 VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
188 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
190 VK_KHR_VIDEO_QUEUE_EXTENSION_NAME,
191 VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME,
192#ifdef VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME
193 VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME,
195#ifdef VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME
196 VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME,
198#ifdef VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME
199 VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME,
202 VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
203 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
205#ifdef VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME
206 VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
208#ifdef VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME
209 VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
211#ifdef VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME
212 VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
214#ifdef VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME
215 VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME,
217#ifdef VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME
218 VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME,
220#ifdef VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME
221 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
223#ifdef VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME
224 VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME,
226#ifdef VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME
227 VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
229#ifdef VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME
230 VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
243inline VkPhysicalDevice resolveSharedVulkanPhysicalDevice(
244 QVulkanInstance* inst, VkPhysicalDevice preferredPhysDev = VK_NULL_HANDLE)
247 return VK_NULL_HANDLE;
248 if(preferredPhysDev != VK_NULL_HANDLE)
249 return preferredPhysDev;
251 auto* funcs = inst->functions();
253 return VK_NULL_HANDLE;
255 uint32_t devCount = 0;
256 funcs->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount,
nullptr);
258 return VK_NULL_HANDLE;
260 std::vector<VkPhysicalDevice> physDevs(devCount);
261 funcs->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, physDevs.data());
264 const int idx = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX", &ok);
265 if(ok && idx >= 0 && uint32_t(idx) < devCount)
266 return physDevs[uint32_t(idx)];
283inline SharedVulkanDevice createSharedVulkanDevice(
284 QVulkanInstance* inst, VkPhysicalDevice preferredPhysDev = VK_NULL_HANDLE)
286 SharedVulkanDevice result;
290 auto* funcs = inst->functions();
300 result.physDev = resolveSharedVulkanPhysicalDevice(inst, preferredPhysDev);
301 if(result.physDev == VK_NULL_HANDLE)
304 uint32_t qfCount = 0;
305 funcs->vkGetPhysicalDeviceQueueFamilyProperties(
306 result.physDev, &qfCount,
nullptr);
310 std::vector<VkQueueFamilyProperties> qfProps(qfCount);
311 funcs->vkGetPhysicalDeviceQueueFamilyProperties(
312 result.physDev, &qfCount, qfProps.data());
314 bool foundGfx =
false;
315 for(uint32_t i = 0; i < qfCount; i++)
317 if(!foundGfx && (qfProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
319 result.gfxQueueFamilyIdx = i;
322 if(qfProps[i].queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR)
324 result.hasVideoDecodeQueue =
true;
325 result.videoDecodeQueueFamilyIdx = i;
329 if(!foundGfx || !result.hasVideoDecodeQueue)
334 uint32_t extCount = 0;
335 funcs->vkEnumerateDeviceExtensionProperties(
336 result.physDev,
nullptr, &extCount,
nullptr);
337 std::vector<VkExtensionProperties> avail(extCount);
338 funcs->vkEnumerateDeviceExtensionProperties(
339 result.physDev,
nullptr, &extCount, avail.data());
341 auto hasExt = [&](
const char* name) {
343 if(
std::strcmp(e.extensionName, name) == 0)
352 auto wantedExtensions = sharedVulkanDeviceExtensions();
353 std::vector<const char*> extPtrs;
354 for(
auto* ext : wantedExtensions)
358 result.enabledExtensions.push_back(ext);
359 extPtrs.push_back(ext);
365 auto vkGetPhysicalDeviceFeatures2Fn
366 =
reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2
>(
367 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFeatures2"));
368 if(!vkGetPhysicalDeviceFeatures2Fn)
372 VkPhysicalDeviceVulkan13Features vk13{};
373 vk13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
375 VkPhysicalDeviceVulkan12Features vk12{};
376 vk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
379 VkPhysicalDeviceVulkan11Features vk11{};
380 vk11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
383 VkPhysicalDeviceFeatures2 features2{};
384 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
385 features2.pNext = &vk11;
388 vkGetPhysicalDeviceFeatures2Fn(result.physDev, &features2);
389 result.timelineSemaphores = vk12.timelineSemaphore == VK_TRUE;
394 features2.features.robustBufferAccess = VK_FALSE;
395 vk13.robustImageAccess = VK_FALSE;
399 std::vector<VkDeviceQueueCreateInfo> queueInfos;
400 float priority = 1.0f;
401 for(uint32_t i = 0; i < qfCount; i++)
403 VkDeviceQueueCreateInfo qi{};
404 qi.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
405 qi.queueFamilyIndex = i;
407 qi.pQueuePriorities = &priority;
408 queueInfos.push_back(qi);
410 result.queueFamilies.push_back(
411 {i, 1, qfProps[i].queueFlags});
416 VkDeviceCreateInfo devInfo{};
417 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
418 devInfo.pNext = &features2;
419 devInfo.queueCreateInfoCount =
static_cast<uint32_t
>(queueInfos.size());
420 devInfo.pQueueCreateInfos = queueInfos.data();
421 devInfo.enabledExtensionCount =
static_cast<uint32_t
>(extPtrs.size());
422 devInfo.ppEnabledExtensionNames = extPtrs.data();
424 auto vkCreateDeviceFn =
reinterpret_cast<PFN_vkCreateDevice
>(
425 inst->getInstanceProcAddr(
"vkCreateDevice"));
426 if(!vkCreateDeviceFn)
429 const double t0 = sharedVulkanDeviceTraceClockMs();
431 = vkCreateDeviceFn(result.physDev, &devInfo,
nullptr, &result.dev);
432 if(sharedVulkanDeviceTraceEnabled())
434 const double t1 = sharedVulkanDeviceTraceClockMs();
435 qDebug(
"%.3f VKDEV vkCreateDevice %.2f ms physDev=%p dev=%p result=%d", t1,
436 t1 - t0, (
void*)result.physDev, (
void*)result.dev,
int(vkResult));
438 if(vkResult != VK_SUCCESS)
440 qDebug() <<
"createSharedVulkanDevice: vkCreateDevice failed:" << vkResult;
441 result.dev = VK_NULL_HANDLE;
447 auto vkGetDeviceQueueFn =
reinterpret_cast<PFN_vkGetDeviceQueue
>(
448 inst->getInstanceProcAddr(
"vkGetDeviceQueue"));
449 if(vkGetDeviceQueueFn)
451 result.dev, result.gfxQueueFamilyIdx, 0, &result.gfxQueue);
473class SharedVulkanDeviceCache;
474inline SharedVulkanDeviceCache& sharedVulkanDeviceCache();
476class SharedVulkanDeviceCache
484 acquire(QVulkanInstance* inst, VkPhysicalDevice preferredPhysDev = VK_NULL_HANDLE)
489 const VkPhysicalDevice physDev
490 = resolveSharedVulkanPhysicalDevice(inst, preferredPhysDev);
491 if(physDev == VK_NULL_HANDLE)
494 std::lock_guard lock{m_mutex};
495 for(
auto& e : m_entries)
497 if(e.inst == inst && e.device.physDev == physDev)
500 if(sharedVulkanDeviceTraceEnabled())
502 "%.3f VKDEV cache HIT dev=%p refcount=%d",
503 sharedVulkanDeviceTraceClockMs(), (
void*)e.device.dev, e.refcount);
508 SharedVulkanDevice dev = createSharedVulkanDevice(inst, physDev);
511 if(sharedVulkanDeviceTraceEnabled())
513 "%.3f VKDEV cache MISS — creation unavailable, caller falls back",
514 sharedVulkanDeviceTraceClockMs());
519 m_entries.push_back(Entry{.inst = inst, .device = dev, .refcount = 1});
523 qAddPostRoutine([] { sharedVulkanDeviceCache().shutdown(); });
524 if(sharedVulkanDeviceTraceEnabled())
526 "%.3f VKDEV cache MISS dev=%p refcount=1", sharedVulkanDeviceTraceClockMs(),
532 void release(VkDevice dev)
534 if(dev == VK_NULL_HANDLE)
536 std::lock_guard lock{m_mutex};
537 for(
auto& e : m_entries)
539 if(e.device.dev == dev)
543 if(sharedVulkanDeviceTraceEnabled())
545 "%.3f VKDEV cache RELEASE dev=%p refcount=%d",
546 sharedVulkanDeviceTraceClockMs(), (
void*)dev, e.refcount);
557 std::lock_guard lock{m_mutex};
558 std::vector<Entry> stillUsed;
559 for(
auto& e : m_entries)
566 qWarning() <<
"SharedVulkanDeviceCache: device still referenced at "
567 "shutdown, refcount ="
569 stillUsed.push_back(e);
572 e.device.destroy(e.inst);
574 m_entries = std::move(stillUsed);
575 m_created = int(m_entries.size());
582 int createdDeviceCount()
const
584 std::lock_guard lock{m_mutex};
591 QVulkanInstance* inst{};
592 SharedVulkanDevice device;
596 mutable std::mutex m_mutex;
597 std::vector<Entry> m_entries;
601inline SharedVulkanDeviceCache& sharedVulkanDeviceCache()
603 static SharedVulkanDeviceCache cache;
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11