6#include <qpa/qplatformvulkaninstance.h>
8#define VMA_IMPLEMENTATION
9#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
10#define VMA_STATIC_VULKAN_FUNCTIONS 0
11#define VMA_RECORDING_ENABLED 0
12#define VMA_DEDICATED_ALLOCATION 0
14Q_STATIC_LOGGING_CATEGORY(QRHI_LOG_VMA,
"qt.rhi.vma")
16#define VMA_ASSERT(expr) Q_ASSERT(expr)
18#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1
19#define VMA_DEBUG_LOG(str) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), (str))
20#define VMA_DEBUG_LOG_FORMAT(format, ...) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, __VA_ARGS__)
22template<
typename... Args>
23static void debugVmaLeak(
const char *format, Args&&... args)
27 static bool leakCheck =
true;
30 static bool leakCheck = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)(
"QT_RHI_LEAK_CHECK");
33 QT_PREPEND_NAMESPACE(qWarning)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, std::forward<Args>(args)...);
35#define VMA_LEAK_LOG_FORMAT(format, ...) debugVmaLeak(format, __VA_ARGS__)
37QT_WARNING_DISABLE_GCC(
"-Wsuggest-override")
38QT_WARNING_DISABLE_GCC(
"-Wundef")
39QT_WARNING_DISABLE_CLANG(
"-Wundef")
40#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1100
41QT_WARNING_DISABLE_CLANG(
"-Wdeprecated-copy")
43#include "vk_mem_alloc.h"
47#include <QVulkanFunctions>
48#include <QtGui/qwindow.h>
49#include <private/qvulkandefaultinstance_p.h>
51#include <QtCore/q20memory.h>
52#include <QtCore/qendian.h>
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
201
202
203
204
205
208
209
210
211
214
215
216
217
218
222
223
224
225
226
227
228
229
230
231
234
235
236
237
240
241
242
243
244
247
248
249
250
253
254
255
256
259
260
261
262
263
264
265
266
267
268
271
272
273
274
275
278
279
280
281
282
285
286
287
288
289
293
294
295
296
297
298
299
300
301
302
303
304
305
306
309
310
311
312
316
317
318
319
320
321
322
323
326
327
328
329
333
334
335
336
337
338
339
342
343
344
345
346
347
350
351
352
353
354
355
358
359
360
361
362
363
366
367
368
369
370
371
374
375
376
377
378
379
382
383
384
385
386
387
392struct QVkPhysicalDevicePortabilitySubsetFeatures
394 VkStructureType sType;
396 VkBool32 constantAlphaColorBlendFactors;
398 VkBool32 imageViewFormatReinterpretation;
399 VkBool32 imageViewFormatSwizzle;
400 VkBool32 imageView2DOn3DImage;
401 VkBool32 multisampleArrayImage;
402 VkBool32 mutableComparisonSamplers;
403 VkBool32 pointPolygons;
404 VkBool32 samplerMipLodBias;
405 VkBool32 separateStencilMaskRef;
406 VkBool32 shaderSampleRateInterpolationFunctions;
407 VkBool32 tessellationIsolines;
408 VkBool32 tessellationPointMode;
409 VkBool32 triangleFans;
410 VkBool32 vertexAttributeAccessBeyondStride;
413static const VkStructureType QVK_STRUCTURE_TYPE_PDPSF = VkStructureType(1000163000);
417inline Int aligned(Int v, Int byteAlign)
419 return (v + byteAlign - 1) & ~(byteAlign - 1);
424static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
426 return globalVulkanInstance->getInstanceProcAddr(pName);
429static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
431 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
436 return reinterpret_cast<VmaAllocation>(a);
441 return reinterpret_cast<VmaAllocator>(a);
445
446
447
448
449
450
451QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
454 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"),
456 QByteArrayLiteral(
"VK_EXT_swapchain_colorspace")
461
462
463
464
465QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
468 QByteArrayLiteral(
"VK_KHR_swapchain"),
469 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
470 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
471 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
472 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
485 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
486 inst = QVulkanDefaultInstance::instance();
490 requestedDeviceExtensions = params->deviceExtensions;
493 physDev = importParams->physDev;
494 dev = importParams->dev;
495 if (dev && physDev) {
497 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
498 gfxQueueIdx = importParams->gfxQueueIdx;
499 gfxQueueFlags = importParams->gfxQueueFlags;
501 if (importParams->vmemAllocator) {
510 QVulkanInstance::DebugMessageTypeFlags type,
511 const void *callbackData)
515#ifdef VK_EXT_debug_utils
516 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
520 if (strstr(d->pMessage,
"Mapping an image with layout")
521 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
532 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
535 Q_UNUSED(callbackData);
543 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
544 return QRhiDriverInfo::UnknownDevice;
545 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
546 return QRhiDriverInfo::IntegratedDevice;
547 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
548 return QRhiDriverInfo::DiscreteDevice;
549 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
550 return QRhiDriverInfo::VirtualDevice;
551 case VK_PHYSICAL_DEVICE_TYPE_CPU:
552 return QRhiDriverInfo::CpuDevice;
554 return QRhiDriverInfo::UnknownDevice;
558static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
560 info->deviceName = QByteArray(physDevProperties.deviceName);
561 info->deviceId = physDevProperties.deviceID;
562 info->vendorId = physDevProperties.vendorID;
563 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
569 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
571 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
577 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
582 if (!inst || !inst->isValid()) {
583 qWarning(
"Vulkan instance is not valid");
588 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
591 f = inst->functions();
592 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
593 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
594 const QByteArrayList extensions = inst->extensions();
595 for (
const char *ext : extensions)
596 qCDebug(QRHI_LOG_INFO,
" %s", ext);
600 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
602 QList<VkQueueFamilyProperties> queueFamilyProps;
603 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
604 uint32_t queueCount = 0;
605 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
606 queueFamilyProps.resize(
int(queueCount));
607 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
612 uint32_t physDevCount = 0;
613 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
615 qWarning(
"No physical devices");
618 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
619 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
620 if (err != VK_SUCCESS || !physDevCount) {
621 qWarning(
"Failed to enumerate physical devices: %d", err);
625 int physDevIndex = -1;
626 int requestedPhysDevIndex = -1;
627 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
628 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
630 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
631 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
632 for (
int i = 0; i <
int(physDevCount); ++i) {
633 if (physDevs[i] == requestedPhysDev) {
634 requestedPhysDevIndex = i;
640 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
641 for (
int i = 0; i <
int(physDevCount); ++i) {
642 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
643 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
644 requestedPhysDevIndex = i;
650 for (
int i = 0; i <
int(physDevCount); ++i) {
651 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
652 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
654 physDevProperties.deviceName,
655 VK_VERSION_MAJOR(physDevProperties.driverVersion),
656 VK_VERSION_MINOR(physDevProperties.driverVersion),
657 VK_VERSION_PATCH(physDevProperties.driverVersion),
658 VK_VERSION_MAJOR(physDevProperties.apiVersion),
659 VK_VERSION_MINOR(physDevProperties.apiVersion),
660 VK_VERSION_PATCH(physDevProperties.apiVersion),
661 physDevProperties.vendorID,
662 physDevProperties.deviceID,
663 physDevProperties.deviceType);
664 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
666 qCDebug(QRHI_LOG_INFO,
" using this physical device");
670 if (physDevIndex < 0) {
671 qWarning(
"No matching physical device");
674 physDev = physDevs[physDevIndex];
675 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
677 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
678 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
679 physDevProperties.deviceName,
680 VK_VERSION_MAJOR(physDevProperties.driverVersion),
681 VK_VERSION_MINOR(physDevProperties.driverVersion),
682 VK_VERSION_PATCH(physDevProperties.driverVersion),
683 VK_VERSION_MAJOR(physDevProperties.apiVersion),
684 VK_VERSION_MINOR(physDevProperties.apiVersion),
685 VK_VERSION_PATCH(physDevProperties.apiVersion),
686 physDevProperties.vendorID,
687 physDevProperties.deviceID,
688 physDevProperties.deviceType);
691 caps.apiVersion = inst->apiVersion();
697 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
698 VK_VERSION_MINOR(physDevProperties.apiVersion));
699 if (physDevApiVersion < caps.apiVersion) {
700 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
701 <<
"whereas the chosen physical device has" << physDevApiVersion
702 <<
"- restricting to the latter";
703 caps.apiVersion = physDevApiVersion;
708 QVulkanInfoVector<QVulkanExtension> devExts;
709 uint32_t devExtCount = 0;
710 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
712 QList<VkExtensionProperties> extProps(devExtCount);
713 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
714 for (
const VkExtensionProperties &p : std::as_const(extProps))
715 devExts.append({ p.extensionName, p.specVersion });
717 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
719 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
721 bool featuresQueried =
false;
723 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
724 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
727#ifdef VK_KHR_fragment_shading_rate
728 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
729 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
730 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
731 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
733#ifdef VK_EXT_device_fault
734 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
735 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
736 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
737 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
740 QVkPhysicalDevicePortabilitySubsetFeatures portabilitySubsetFeatures = {};
741 portabilitySubsetFeatures.sType = QVK_STRUCTURE_TYPE_PDPSF;
742 if (hasPhysDevProp2 && devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset")))
743 addToChain(&physDevFeaturesChainable, &portabilitySubsetFeatures);
748 if (!featuresQueried) {
750 if (caps.apiVersion >= QVersionNumber(1, 2)) {
751 physDevFeatures11IfApi12OrNewer = {};
752 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
753 physDevFeatures12 = {};
754 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
756 physDevFeatures13 = {};
757 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
759 physDevFeatures14 = {};
760 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
763 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
764 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
766 if (caps.apiVersion >= QVersionNumber(1, 3))
767 physDevFeatures12.pNext = &physDevFeatures13;
769 if (caps.apiVersion >= QVersionNumber(1, 4))
770 physDevFeatures13.pNext = &physDevFeatures14;
773 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
774 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
775 featuresQueried =
true;
782 if (!featuresQueried) {
790 if (caps.apiVersion == QVersionNumber(1, 1)) {
792 multiviewFeaturesIfApi11 = {};
793 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
794 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
797 shaderDrawParametersFeaturesIfApi11 = {};
798 shaderDrawParametersFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
799 addToChain(&physDevFeaturesChainable, &shaderDrawParametersFeaturesIfApi11);
801 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
802 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
803 featuresQueried =
true;
808 if (!featuresQueried) {
811 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
812 featuresQueried =
true;
820 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
821 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
822 queryQueueFamilyProps();
823 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
824 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
825 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
826 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
827 if (!gfxQueueFamilyIdxOpt.has_value()
828 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
829 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
831 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
832 gfxQueueFamilyIdxOpt = i;
833 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
834 computelessGfxQueueCandidateIdxOpt = i;
837 if (gfxQueueFamilyIdxOpt.has_value()) {
838 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
840 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
841 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
843 qWarning(
"No graphics (or no graphics+present) queue family found");
848 VkDeviceQueueCreateInfo queueInfo = {};
849 const float prio[] = { 0 };
850 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
851 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
852 queueInfo.queueCount = 1;
853 queueInfo.pQueuePriorities = prio;
855 QList<
const char *> requestedDevExts;
856 requestedDevExts.append(
"VK_KHR_swapchain");
858 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
859 if (hasPhysDevProp2) {
860 requestedDevExts.append(
"VK_KHR_portability_subset");
862 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
863 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
868#ifdef VK_EXT_vertex_attribute_divisor
869 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
870 if (hasPhysDevProp2) {
871 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
872 caps.vertexAttribDivisor =
true;
877#ifdef VK_KHR_create_renderpass2
878 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
882 bool canEnable =
true;
883 if (caps.apiVersion < QVersionNumber(1, 1)) {
884 canEnable = hasPhysDevProp2
885 && devExts.contains(QByteArrayLiteral(
"VK_KHR_multiview"))
886 && devExts.contains(QByteArrayLiteral(
"VK_KHR_maintenance2"));
888 requestedDevExts.append(
"VK_KHR_multiview");
889 requestedDevExts.append(
"VK_KHR_maintenance2");
893 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
894 caps.renderPass2KHR =
true;
899#ifdef VK_KHR_depth_stencil_resolve
901 const bool hasRenderPass2Dep = caps.renderPass2KHR || caps.apiVersion >= QVersionNumber(1, 2);
902 if (hasRenderPass2Dep && devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
903 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
904 caps.depthStencilResolveKHR =
true;
909#ifdef VK_KHR_fragment_shading_rate
911 const bool hasRenderPass2Dep = caps.renderPass2KHR || caps.apiVersion >= QVersionNumber(1, 2);
912 if (hasRenderPass2Dep && devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
913 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
917#ifdef VK_EXT_device_fault
918 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
919 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
920 caps.deviceFault =
true;
924 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
925 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
926 if (devExts.contains(ext)) {
927 requestedDevExts.append(ext.constData());
929 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
935 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
936 for (
const QByteArray &ext : envExtList) {
937 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
938 if (devExts.contains(ext)) {
939 requestedDevExts.append(ext.constData());
941 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
947 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
948 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
949 for (
const char *ext : std::as_const(requestedDevExts))
950 qCDebug(QRHI_LOG_INFO,
" %s", ext);
953 VkDeviceCreateInfo devInfo = {};
954 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
955 devInfo.queueCreateInfoCount = 1;
956 devInfo.pQueueCreateInfos = &queueInfo;
958 devInfo.enabledLayerCount = 0;
959 devInfo.ppEnabledLayerNames =
nullptr;
960 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
961 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
977 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
980 physDevFeatures13.robustImageAccess = VK_FALSE;
984 if (caps.apiVersion >= QVersionNumber(1, 1)) {
991 devInfo.pNext = &physDevFeaturesChainable;
995 physDevFeatures.robustBufferAccess = VK_FALSE;
996 devInfo.pEnabledFeatures = &physDevFeatures;
999 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
1000 if (err != VK_SUCCESS) {
1001 qWarning(
"Failed to create device: %d", err);
1005 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
1010 caps.deviceFault =
true;
1011 caps.vertexAttribDivisor =
true;
1012 caps.renderPass2KHR =
true;
1013 caps.depthStencilResolveKHR =
true;
1016 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
1017 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
1018 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
1019 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
1020 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
1021 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
1023 df = inst->deviceFunctions(dev);
1025 VkCommandPoolCreateInfo poolInfo = {};
1026 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1027 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
1029 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
1030 if (err != VK_SUCCESS) {
1031 qWarning(
"Failed to create command pool: %d", err);
1036 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
1037 gfxQueueFamilyIdx, gfxQueueIdx);
1040 if (gfxQueueFlags && caps.apiVersion >= QVersionNumber(1, 1)) {
1041 VkDeviceQueueInfo2 queueInfo = {};
1042 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
1043 queueInfo.flags = gfxQueueFlags;
1044 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
1045 queueInfo.queueIndex = gfxQueueIdx;
1046 df->vkGetDeviceQueue2(dev, &queueInfo, &gfxQueue);
1049 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
1051 if (queueFamilyProps.isEmpty())
1052 queryQueueFamilyProps();
1054 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
1055 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
1057 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
1060 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
1062 caps.depthClamp = physDevFeatures.depthClamp;
1064 caps.wideLines = physDevFeatures.wideLines;
1066 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
1068 caps.tessellation = physDevFeatures.tessellationShader;
1069 caps.geometryShader = physDevFeatures.geometryShader;
1071 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
1073 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
1075#ifdef VK_VERSION_1_2
1076 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1077 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1078 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
1081 caps.drawIndirectCount = physDevFeatures12.drawIndirectCount && caps.drawIndirectMulti;
1085#ifdef VK_VERSION_1_1
1086 if (caps.apiVersion == QVersionNumber(1, 1)) {
1087 caps.multiView = multiviewFeaturesIfApi11.multiview;
1088 caps.shaderDrawParameters = shaderDrawParametersFeaturesIfApi11.shaderDrawParameters;
1092#ifdef VK_KHR_fragment_shading_rate
1093 fragmentShadingRates.clear();
1094 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1095 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1096 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1097 if (caps.imageBasedShadingRate) {
1098 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1099 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1100 VkPhysicalDeviceProperties2 props2 = {};
1101 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1102 props2.pNext = &shadingRateProps;
1103 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1104 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1107 if (caps.perDrawShadingRate) {
1108 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1109 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1110 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1111 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1113 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1114 fragmentShadingRates.resize(count);
1115 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1117 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1119 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1121 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1122 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1131#ifdef VK_KHR_create_renderpass2
1132 if (caps.renderPass2KHR) {
1133 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1134 if (!vkCreateRenderPass2KHR)
1135 caps.renderPass2KHR =
false;
1139#ifdef VK_VERSION_1_2
1140 if (caps.drawIndirectCount) {
1141 vkCmdDrawIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndirectCount>(
1142 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndirectCount"));
1143 vkCmdDrawIndexedIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirectCount>(
1144 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndexedIndirectCount"));
1145 if (!vkCmdDrawIndirectCount || !vkCmdDrawIndexedIndirectCount) {
1146 qWarning(
"Failed to resolve vkCmdDrawIndirectCount/vkCmdDrawIndexedIndirectCount; disabling DrawIndirectCount feature.");
1147 caps.drawIndirectCount =
false;
1154 adapterLuidValid =
false;
1156#ifdef VK_VERSION_1_2
1157 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1158 VkPhysicalDeviceVulkan11Properties v11props = {};
1159 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1160 VkPhysicalDeviceProperties2 props2 = {};
1161 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1162 props2.pNext = &v11props;
1163 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1164 if (v11props.deviceLUIDValid) {
1165 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1166 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1167 adapterLuidValid =
true;
1168 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1169 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1170 adapterLuid.LowPart, adapterLuid.HighPart);
1177 VmaVulkanFunctions funcs = {};
1178 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1179 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1181 VmaAllocatorCreateInfo allocatorInfo = {};
1184 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1185 allocatorInfo.physicalDevice = physDev;
1186 allocatorInfo.device = dev;
1187 allocatorInfo.pVulkanFunctions = &funcs;
1188 allocatorInfo.instance = inst->vkInstance();
1196#ifdef VK_VERSION_1_4
1197 if (caps.apiVersion >= QVersionNumber(1, 4))
1198 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1201#ifdef VK_VERSION_1_3
1202 if (caps.apiVersion >= QVersionNumber(1, 3))
1203 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1206#ifdef VK_VERSION_1_2
1207 if (caps.apiVersion >= QVersionNumber(1, 2))
1208 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1211#ifdef VK_VERSION_1_1
1212 if (caps.apiVersion >= QVersionNumber(1, 1))
1213 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1216#ifdef VK_VERSION_1_0
1217 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1220 VmaAllocator vmaallocator;
1221 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1222 if (err != VK_SUCCESS) {
1223 qWarning(
"Failed to create allocator: %d", err);
1229 inst->installDebugOutputFilter(qvk_debug_filter);
1231 VkDescriptorPool pool;
1232 VkResult err = createDescriptorPool(&pool);
1233 if (err == VK_SUCCESS)
1234 descriptorPools.append(pool);
1236 qWarning(
"Failed to create initial descriptor pool: %d", err);
1238 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1239 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1240 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1242 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1243 if (err != VK_SUCCESS) {
1244 qWarning(
"Failed to create timestamp query pool: %d", err);
1247 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1248 timestampQueryPoolMap.fill(
false);
1250#ifdef VK_EXT_debug_utils
1251 if (caps.debugUtils) {
1252 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1253 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1254 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1255 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1259#ifdef VK_EXT_device_fault
1260 if (caps.deviceFault) {
1261 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1267 nativeHandlesStruct.physDev = physDev;
1268 nativeHandlesStruct.dev = dev;
1269 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1270 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1271 nativeHandlesStruct.gfxQueueFlags = gfxQueueFlags;
1272 nativeHandlesStruct.gfxQueue = gfxQueue;
1273 nativeHandlesStruct.vmemAllocator = allocator;
1274 nativeHandlesStruct.inst = inst;
1285 df->vkQueueWaitIdle(gfxQueue);
1292 dxgiHdrInfo =
nullptr;
1296 if (ofr.cmdFence[i]) {
1297 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1298 ofr.cmdFence[i] = VK_NULL_HANDLE;
1300 ofr.cmdFenceWaitable[i] =
false;
1303 if (pipelineCache) {
1304 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1305 pipelineCache = VK_NULL_HANDLE;
1308 for (
const DescriptorPoolData &pool : descriptorPools)
1309 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1311 descriptorPools.clear();
1313 if (timestampQueryPool) {
1314 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1315 timestampQueryPool = VK_NULL_HANDLE;
1319 vmaDestroyAllocator(toVmaAllocator(allocator));
1325 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1326 cmdPool[i] = VK_NULL_HANDLE;
1328 freeSecondaryCbs[i].clear();
1329 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1332 if (!importedDevice && dev) {
1333 df->vkDestroyDevice(dev,
nullptr);
1334 inst->resetDeviceFunctions(dev);
1335 dev = VK_NULL_HANDLE;
1345QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1347 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1348 if (nativeHandles) {
1349 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1350 requestedPhysDev = h->physDev;
1353 QRhi::AdapterList list;
1354 QVulkanFunctions *f = inst->functions();
1355 uint32_t physDevCount = 0;
1356 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1360 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1361 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1362 if (err != VK_SUCCESS || !physDevCount)
1365 VkPhysicalDeviceProperties physDevProperties = {};
1366 for (uint32_t i = 0; i < physDevCount; ++i) {
1367 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1370 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1371 QVulkanAdapter *a =
new QVulkanAdapter;
1372 a->physDev = physDevs[i];
1373 fillDriverInfo(&a->adapterInfo, physDevProperties);
1387 VkDescriptorPoolSize descPoolSizes[] = {
1388 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1389 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1390 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1391 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1392 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1393 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1394 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1396 VkDescriptorPoolCreateInfo descPoolInfo = {};
1397 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1401 descPoolInfo.flags = 0;
1403 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1404 descPoolInfo.pPoolSizes = descPoolSizes;
1405 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1410 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1411 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1412 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1413 if (r == VK_SUCCESS)
1414 descriptorPools[poolIndex].refCount += 1;
1418 int lastPoolIdx = descriptorPools.size() - 1;
1419 for (
int i = lastPoolIdx; i >= 0; --i) {
1420 if (descriptorPools[i].refCount == 0) {
1421 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1422 descriptorPools[i].allocedDescSets = 0;
1424 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1425 VkResult err = tryAllocate(i);
1426 if (err == VK_SUCCESS) {
1427 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1428 *resultPoolIndex = i;
1434 VkDescriptorPool newPool;
1435 VkResult poolErr = createDescriptorPool(&newPool);
1436 if (poolErr == VK_SUCCESS) {
1437 descriptorPools.append(newPool);
1438 lastPoolIdx = descriptorPools.size() - 1;
1439 VkResult err = tryAllocate(lastPoolIdx);
1440 if (err != VK_SUCCESS) {
1441 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1444 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1445 *resultPoolIndex = lastPoolIdx;
1448 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1455 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1457 case QRhiTexture::RGBA8:
1458 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1459 case QRhiTexture::BGRA8:
1460 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1461 case QRhiTexture::R8:
1462 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1463 case QRhiTexture::RG8:
1464 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1465 case QRhiTexture::R16:
1466 return VK_FORMAT_R16_UNORM;
1467 case QRhiTexture::RG16:
1468 return VK_FORMAT_R16G16_UNORM;
1469 case QRhiTexture::RED_OR_ALPHA8:
1470 return VK_FORMAT_R8_UNORM;
1472 case QRhiTexture::RGBA16F:
1473 return VK_FORMAT_R16G16B16A16_SFLOAT;
1474 case QRhiTexture::RGBA32F:
1475 return VK_FORMAT_R32G32B32A32_SFLOAT;
1476 case QRhiTexture::R16F:
1477 return VK_FORMAT_R16_SFLOAT;
1478 case QRhiTexture::R32F:
1479 return VK_FORMAT_R32_SFLOAT;
1481 case QRhiTexture::RGB10A2:
1483 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1485 case QRhiTexture::R8SI:
1486 return VK_FORMAT_R8_SINT;
1487 case QRhiTexture::R32SI:
1488 return VK_FORMAT_R32_SINT;
1489 case QRhiTexture::RG32SI:
1490 return VK_FORMAT_R32G32_SINT;
1491 case QRhiTexture::RGBA32SI:
1492 return VK_FORMAT_R32G32B32A32_SINT;
1494 case QRhiTexture::R8UI:
1495 return VK_FORMAT_R8_UINT;
1496 case QRhiTexture::R32UI:
1497 return VK_FORMAT_R32_UINT;
1498 case QRhiTexture::RG32UI:
1499 return VK_FORMAT_R32G32_UINT;
1500 case QRhiTexture::RGBA32UI:
1501 return VK_FORMAT_R32G32B32A32_UINT;
1503 case QRhiTexture::D16:
1504 return VK_FORMAT_D16_UNORM;
1505 case QRhiTexture::D24:
1506 return VK_FORMAT_X8_D24_UNORM_PACK32;
1507 case QRhiTexture::D24S8:
1508 return VK_FORMAT_D24_UNORM_S8_UINT;
1509 case QRhiTexture::D32F:
1510 return VK_FORMAT_D32_SFLOAT;
1511 case QRhiTexture::D32FS8:
1512 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1514 case QRhiTexture::BC1:
1515 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1516 case QRhiTexture::BC2:
1517 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1518 case QRhiTexture::BC3:
1519 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1520 case QRhiTexture::BC4:
1521 return VK_FORMAT_BC4_UNORM_BLOCK;
1522 case QRhiTexture::BC5:
1523 return VK_FORMAT_BC5_UNORM_BLOCK;
1524 case QRhiTexture::BC6H:
1525 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1526 case QRhiTexture::BC7:
1527 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1529 case QRhiTexture::ETC2_RGB8:
1530 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1531 case QRhiTexture::ETC2_RGB8A1:
1532 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1533 case QRhiTexture::ETC2_RGBA8:
1534 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1536 case QRhiTexture::ASTC_4x4:
1537 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1538 case QRhiTexture::ASTC_5x4:
1539 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1540 case QRhiTexture::ASTC_5x5:
1541 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1542 case QRhiTexture::ASTC_6x5:
1543 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1544 case QRhiTexture::ASTC_6x6:
1545 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1546 case QRhiTexture::ASTC_8x5:
1547 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1548 case QRhiTexture::ASTC_8x6:
1549 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1550 case QRhiTexture::ASTC_8x8:
1551 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1552 case QRhiTexture::ASTC_10x5:
1553 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1554 case QRhiTexture::ASTC_10x6:
1555 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1556 case QRhiTexture::ASTC_10x8:
1557 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1558 case QRhiTexture::ASTC_10x10:
1559 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1560 case QRhiTexture::ASTC_12x10:
1561 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1562 case QRhiTexture::ASTC_12x12:
1563 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1566 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1573 case VK_FORMAT_R8G8B8A8_UNORM:
1574 return QRhiTexture::RGBA8;
1575 case VK_FORMAT_R8G8B8A8_SRGB:
1577 (*flags) |= QRhiTexture::sRGB;
1578 return QRhiTexture::RGBA8;
1579 case VK_FORMAT_B8G8R8A8_UNORM:
1580 return QRhiTexture::BGRA8;
1581 case VK_FORMAT_B8G8R8A8_SRGB:
1583 (*flags) |= QRhiTexture::sRGB;
1584 return QRhiTexture::BGRA8;
1585 case VK_FORMAT_R16G16B16A16_SFLOAT:
1586 return QRhiTexture::RGBA16F;
1587 case VK_FORMAT_R32G32B32A32_SFLOAT:
1588 return QRhiTexture::RGBA32F;
1589 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1590 return QRhiTexture::RGB10A2;
1592 qWarning(
"VkFormat %d cannot be read back", format);
1595 return QRhiTexture::UnknownFormat;
1601 case QRhiTexture::Format::D16:
1602 case QRhiTexture::Format::D24:
1603 case QRhiTexture::Format::D24S8:
1604 case QRhiTexture::Format::D32F:
1605 case QRhiTexture::Format::D32FS8:
1616 case QRhiTexture::Format::D24S8:
1617 case QRhiTexture::Format::D32FS8:
1627 if (isDepthTextureFormat(format)) {
1628 if (isStencilTextureFormat(format))
1629 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1631 return VK_IMAGE_ASPECT_DEPTH_BIT;
1633 return VK_IMAGE_ASPECT_COLOR_BIT;
1644 VkPhysicalDeviceMemoryProperties physDevMemProps;
1645 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1647 VkMemoryRequirements memReq;
1648 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1649 uint32_t memTypeIndex = uint32_t(-1);
1651 if (memReq.memoryTypeBits) {
1653 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1654 bool foundDevLocal =
false;
1655 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1656 if (memReq.memoryTypeBits & (1 << i)) {
1657 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1658 if (!foundDevLocal) {
1659 foundDevLocal =
true;
1662 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1671 return memTypeIndex;
1675 const QSize &pixelSize,
1676 VkImageUsageFlags usage,
1677 VkImageAspectFlags aspectMask,
1678 VkSampleCountFlagBits samples,
1679 VkDeviceMemory *mem,
1684 VkMemoryRequirements memReq;
1687 *mem = VK_NULL_HANDLE;
1688 for (
int i = 0; i < count; ++i) {
1689 images[i] = VK_NULL_HANDLE;
1690 views[i] = VK_NULL_HANDLE;
1693 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1694 for (
int i = 0; i < count; ++i) {
1696 df->vkDestroyImageView(dev, views[i],
nullptr);
1697 views[i] = VK_NULL_HANDLE;
1700 df->vkDestroyImage(dev, images[i],
nullptr);
1701 images[i] = VK_NULL_HANDLE;
1705 df->vkFreeMemory(dev, *mem,
nullptr);
1706 *mem = VK_NULL_HANDLE;
1710 for (
int i = 0; i < count; ++i) {
1711 VkImageCreateInfo imgInfo = {};
1712 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1713 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1714 imgInfo.format = format;
1715 imgInfo.extent.width = uint32_t(pixelSize.width());
1716 imgInfo.extent.height = uint32_t(pixelSize.height());
1717 imgInfo.extent.depth = 1;
1718 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1719 imgInfo.samples = samples;
1720 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1721 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1722 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1724 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1725 if (err != VK_SUCCESS) {
1726 qWarning(
"Failed to create image: %d", err);
1733 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1736 VkMemoryAllocateInfo memInfo = {};
1737 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1738 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1740 uint32_t startIndex = 0;
1742 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1743 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1744 qWarning(
"No suitable memory type found");
1747 startIndex = memInfo.memoryTypeIndex + 1;
1748 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1749 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1750 qWarning(
"Failed to allocate image memory: %d", err);
1753 }
while (err != VK_SUCCESS);
1755 VkDeviceSize ofs = 0;
1756 for (
int i = 0; i < count; ++i) {
1757 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1758 if (err != VK_SUCCESS) {
1759 qWarning(
"Failed to bind image memory: %d", err);
1762 ofs += aligned(memReq.size, memReq.alignment);
1764 VkImageViewCreateInfo imgViewInfo = {};
1765 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1766 imgViewInfo.image = images[i];
1767 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1768 imgViewInfo.format = format;
1769 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1770 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1771 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1772 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1773 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1774 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1776 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1777 if (err != VK_SUCCESS) {
1778 qWarning(
"Failed to create image view: %d", err);
1789 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1790 return optimalDsFormat;
1792 const VkFormat dsFormatCandidates[] = {
1793 VK_FORMAT_D24_UNORM_S8_UINT,
1794 VK_FORMAT_D32_SFLOAT_S8_UINT,
1795 VK_FORMAT_D16_UNORM_S8_UINT
1797 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1798 int dsFormatIdx = 0;
1799 while (dsFormatIdx < dsFormatCandidateCount) {
1800 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1801 VkFormatProperties fmtProp;
1802 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1803 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1807 if (dsFormatIdx == dsFormatCandidateCount)
1808 qWarning(
"Failed to find an optimal depth-stencil format");
1810 return optimalDsFormat;
1815 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1817 if (multiViewCount < 2)
1819 if (!multiViewCap) {
1820 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1823#ifdef VK_VERSION_1_1
1824 uint32_t allViewsMask = 0;
1825 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1826 allViewsMask |= (1 << i);
1827 multiViewMask = allViewsMask;
1828 multiViewCorrelationMask = allViewsMask;
1829 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1830 multiViewInfo.subpassCount = 1;
1831 multiViewInfo.pViewMasks = &multiViewMask;
1832 multiViewInfo.correlationMaskCount = 1;
1833 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1834 rpInfo->pNext = &multiViewInfo;
1839#ifdef VK_VERSION_1_1
1846#ifdef VK_KHR_create_renderpass2
1850struct RenderPass2SetupHelper
1852 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1854 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1858 if (multiViewCount >= 2) {
1859 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1860 viewMask |= (1 << i);
1863 attDescs2.resize(rpInfo->attachmentCount);
1864 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1865 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1866 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1868 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1869 att2.flags = att.flags;
1870 att2.format = att.format;
1871 att2.samples = att.samples;
1872 att2.loadOp = att.loadOp;
1873 att2.storeOp = att.storeOp;
1874 att2.stencilLoadOp = att.stencilLoadOp;
1875 att2.stencilStoreOp = att.stencilStoreOp;
1876 att2.initialLayout = att.initialLayout;
1877 att2.finalLayout = att.finalLayout;
1882 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1883 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1884 subpass2.flags = subpassDesc.flags;
1885 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1886 if (multiViewCount >= 2)
1887 subpass2.viewMask = viewMask;
1890 qsizetype startIndex = attRefs2.count();
1891 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1892 attRefs2.append({});
1893 VkAttachmentReference2KHR &attref2(attRefs2.last());
1894 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1895 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1896 attref2.attachment = attref.attachment;
1897 attref2.layout = attref.layout;
1898 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1900 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1901 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1904 if (subpassDesc.pResolveAttachments) {
1905 startIndex = attRefs2.count();
1906 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1907 attRefs2.append({});
1908 VkAttachmentReference2KHR &attref2(attRefs2.last());
1909 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1910 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1911 attref2.attachment = attref.attachment;
1912 attref2.layout = attref.layout;
1913 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1915 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1919 if (subpassDesc.pDepthStencilAttachment) {
1920 startIndex = attRefs2.count();
1921 attRefs2.append({});
1922 VkAttachmentReference2KHR &attref2(attRefs2.last());
1923 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1924 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1925 attref2.attachment = attref.attachment;
1926 attref2.layout = attref.layout;
1927 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1928 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1932#ifdef VK_KHR_depth_stencil_resolve
1934 if (rpD->hasDepthStencilResolve) {
1935 startIndex = attRefs2.count();
1936 attRefs2.append({});
1937 VkAttachmentReference2KHR &attref2(attRefs2.last());
1938 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1939 attref2.attachment = rpD->dsResolveRef.attachment;
1940 attref2.layout = rpD->dsResolveRef.layout;
1941 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1942 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1943 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1944 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1945 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1946 addToChain(&subpass2, &dsResolveDesc);
1950#ifdef VK_KHR_fragment_shading_rate
1951 shadingRateAttInfo = {};
1952 if (rpD->hasShadingRateMap) {
1953 startIndex = attRefs2.count();
1954 attRefs2.append({});
1955 VkAttachmentReference2KHR &attref2(attRefs2.last());
1956 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1957 attref2.attachment = rpD->shadingRateRef.attachment;
1958 attref2.layout = rpD->shadingRateRef.layout;
1959 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1960 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1961 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1962 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1963 addToChain(&subpass2, &shadingRateAttInfo);
1969 subpassDeps2.clear();
1970 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1971 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1972 subpassDeps2.append({});
1973 VkSubpassDependency2 &dep2(subpassDeps2.last());
1974 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1975 dep2.srcSubpass = dep.srcSubpass;
1976 dep2.dstSubpass = dep.dstSubpass;
1977 dep2.srcStageMask = dep.srcStageMask;
1978 dep2.dstStageMask = dep.dstStageMask;
1979 dep2.srcAccessMask = dep.srcAccessMask;
1980 dep2.dstAccessMask = dep.dstAccessMask;
1981 dep2.dependencyFlags = dep.dependencyFlags;
1984 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1985 rpInfo2->pNext =
nullptr;
1986 rpInfo2->flags = rpInfo->flags;
1987 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1988 rpInfo2->pAttachments = attDescs2.constData();
1989 rpInfo2->subpassCount = 1;
1990 rpInfo2->pSubpasses = &subpass2;
1991 rpInfo2->dependencyCount = subpassDeps2.count();
1992 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1993 if (multiViewCount >= 2) {
1994 rpInfo2->correlatedViewMaskCount = 1;
1995 rpInfo2->pCorrelatedViewMasks = &viewMask;
2001 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
2002 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
2003 VkSubpassDescription2KHR subpass2;
2004 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
2005#ifdef VK_KHR_depth_stencil_resolve
2006 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
2008#ifdef VK_KHR_fragment_shading_rate
2009 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
2016 VkSubpassDescription *subpassDesc,
2019 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
2020 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
2021 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
2022 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
2023 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
2024 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
2026 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
2027 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
2028 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
2029 rpInfo->pAttachments = rpD->attDescs.constData();
2030 rpInfo->subpassCount = 1;
2031 rpInfo->pSubpasses = subpassDesc;
2032 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
2033 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
2039 VkSubpassDependency selfDependency = {};
2040 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2041 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2042 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2043 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2044 selfDependency.srcSubpass = 0;
2045 selfDependency.dstSubpass = 0;
2046 selfDependency.srcStageMask = stageMask;
2047 selfDependency.dstStageMask = stageMask;
2048 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2049 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2050 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2051#ifdef VK_VERSION_1_1
2052 if (rpD->multiViewCount >= 2)
2053 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2055 selfDependency.dependencyFlags = depFlags;
2056 rpD->subpassDeps.append(selfDependency);
2060 bool hasDepthStencil,
2061 VkSampleCountFlagBits samples,
2062 VkFormat colorFormat,
2063 QRhiShadingRateMap *shadingRateMap)
2067 VkAttachmentDescription attDesc = {};
2068 attDesc.format = colorFormat;
2069 attDesc.samples = samples;
2070 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2071 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2072 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2073 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2074 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2075 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2076 rpD->attDescs.append(attDesc);
2078 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2083 rpD->multiViewCount = 0;
2085 if (hasDepthStencil) {
2089 attDesc.format = optimalDepthStencilFormat();
2090 attDesc.samples = samples;
2091 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2092 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2093 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2094 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2095 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2096 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2097 rpD->attDescs.append(attDesc);
2099 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2104 if (samples > VK_SAMPLE_COUNT_1_BIT) {
2106 attDesc.format = colorFormat;
2107 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2108 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2109 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2110 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2111 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2112 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2113 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2114 rpD->attDescs.append(attDesc);
2116 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2119 rpD->dsResolveRef = {};
2121 rpD->shadingRateRef = {};
2122#ifdef VK_KHR_fragment_shading_rate
2123 if (shadingRateMap) {
2125 attDesc.format = VK_FORMAT_R8_UINT;
2126 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2127 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2128 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2129 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2130 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2131 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2132 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2133 rpD->attDescs.append(attDesc);
2135 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2140 VkSubpassDependency subpassDep = {};
2141 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2142 subpassDep.dstSubpass = 0;
2143 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2144 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2145 subpassDep.srcAccessMask = 0;
2146 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2147 rpD->subpassDeps.append(subpassDep);
2148 if (hasDepthStencil) {
2149 memset(&subpassDep, 0,
sizeof(subpassDep));
2150 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2151 subpassDep.dstSubpass = 0;
2152 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2153 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2154 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2155 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2156 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2157 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2158 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2159 rpD->subpassDeps.append(subpassDep);
2164 VkRenderPassCreateInfo rpInfo;
2165 VkSubpassDescription subpassDesc;
2166 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2168#ifdef VK_KHR_create_renderpass2
2169 if (caps.renderPass2KHR) {
2171 VkRenderPassCreateInfo2KHR rpInfo2;
2172 RenderPass2SetupHelper rp2Helper(
this);
2173 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2175 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2176 if (err != VK_SUCCESS) {
2177 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2184 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2185 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2186 if (err != VK_SUCCESS) {
2187 qWarning(
"Failed to create renderpass: %d", err);
2196 const QRhiColorAttachment *colorAttachmentsBegin,
2197 const QRhiColorAttachment *colorAttachmentsEnd,
2201 QRhiRenderBuffer *depthStencilBuffer,
2202 QRhiTexture *depthTexture,
2203 QRhiTexture *depthResolveTexture,
2205 QRhiShadingRateMap *shadingRateMap)
2209 int multiViewCount = 0;
2210 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2213 Q_ASSERT(texD || rbD);
2214 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2215 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2217 VkAttachmentDescription attDesc = {};
2218 attDesc.format = vkformat;
2219 attDesc.samples = samples;
2220 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2221 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2222 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2223 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2225 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2226 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2227 rpD->attDescs.append(attDesc);
2229 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2230 rpD->colorRefs.append(ref);
2232 if (it->multiViewCount() >= 2) {
2233 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2234 qWarning(
"Inconsistent multiViewCount in color attachment set");
2236 multiViewCount = it->multiViewCount();
2237 }
else if (multiViewCount > 0) {
2238 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2241 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2242 rpD->multiViewCount = uint32_t(multiViewCount);
2246 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2247 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2248 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2249 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2250 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2251 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2252 VkAttachmentDescription attDesc = {};
2253 attDesc.format = dsFormat;
2254 attDesc.samples = samples;
2255 attDesc.loadOp = loadOp;
2256 attDesc.storeOp = storeOp;
2257 attDesc.stencilLoadOp = loadOp;
2258 attDesc.stencilStoreOp = storeOp;
2259 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2260 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2261 rpD->attDescs.append(attDesc);
2262 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2263 multiViewCount = depthTexture->arraySize();
2264 rpD->multiViewCount = multiViewCount;
2266 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2271 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2272 if (it->resolveTexture()) {
2274 const VkFormat dstFormat = rtexD->vkformat;
2275 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2276 qWarning(
"Resolving into a multisample texture is not supported");
2280 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2281 if (srcFormat != dstFormat) {
2285 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2286 int(srcFormat),
int(dstFormat));
2289 VkAttachmentDescription attDesc = {};
2290 attDesc.format = rtexD->viewFormat;
2291 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2292 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2293 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2294 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2295 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2296 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2297 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2298 rpD->attDescs.append(attDesc);
2300 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2301 rpD->resolveRefs.append(ref);
2303 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2304 rpD->resolveRefs.append(ref);
2307 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2312 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2313 qWarning(
"Resolving into a multisample depth texture is not supported");
2314 const VkFormat dstFormat = rtexD->vkformat;
2318 Q_ASSERT(texD || rbD);
2319 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2320 if (srcFormat != dstFormat) {
2321 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2322 int(srcFormat),
int(dstFormat));
2325 VkAttachmentDescription attDesc = {};
2326 attDesc.format = rtexD->viewFormat;
2327 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2328 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2329 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2330 attDesc.stencilLoadOp = attDesc.loadOp;
2331 attDesc.stencilStoreOp = attDesc.storeOp;
2332 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2333 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2334 rpD->attDescs.append(attDesc);
2335 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2337 rpD->dsResolveRef = {};
2341 rpD->shadingRateRef = {};
2342#ifdef VK_KHR_fragment_shading_rate
2343 if (shadingRateMap) {
2344 VkAttachmentDescription attDesc = {};
2345 attDesc.format = VK_FORMAT_R8_UINT;
2346 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2347 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2348 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2349 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2350 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2351 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2352 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2353 rpD->attDescs.append(attDesc);
2354 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2365 VkRenderPassCreateInfo rpInfo;
2366 VkSubpassDescription subpassDesc;
2367 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2370 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2373#ifdef VK_KHR_create_renderpass2
2374 if (caps.renderPass2KHR) {
2376 VkRenderPassCreateInfo2KHR rpInfo2;
2377 RenderPass2SetupHelper rp2Helper(
this);
2378 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2381 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2382 if (err != VK_SUCCESS) {
2383 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2390 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2391 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2394 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2395 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2396 if (err != VK_SUCCESS) {
2397 qWarning(
"Failed to create renderpass: %d", err);
2408 if (swapChainD->pixelSize.isEmpty()) {
2409 qWarning(
"Surface size is 0, cannot create swapchain");
2414 df->vkQueueWaitIdle(gfxQueue);
2416 if (!vkCreateSwapchainKHR) {
2417 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2418 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2419 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2420 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2421 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2422 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2423 qWarning(
"Swapchain functions not available");
2428 VkSurfaceCapabilitiesKHR surfaceCaps;
2429 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2430 quint32 reqBufferCount;
2431 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2432 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2434 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2436 VkSurfaceTransformFlagBitsKHR preTransform =
2437 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2438 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2439 : surfaceCaps.currentTransform;
2465 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2466 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2467 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2468 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2470 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2471 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2472 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2473 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2474 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2475 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2476 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2477 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2478 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2479 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2482 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2483 swapChainD
->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2484 if (swapChainD
->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2485 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2487 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2488 && surfaceCaps.maxImageArrayLayers > 1;
2491 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2492 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2496 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2497 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2498 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2499 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2507 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2509 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2510 reuseExisting ?
"recycled" :
"new",
2511 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2513 VkSwapchainCreateInfoKHR swapChainInfo = {};
2514 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2515 swapChainInfo.surface = swapChainD->surface;
2516 swapChainInfo.minImageCount = reqBufferCount;
2517 swapChainInfo.imageFormat = swapChainD->colorFormat;
2518 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2519 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2520 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2521 swapChainInfo.imageUsage = usage;
2522 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2523 swapChainInfo.preTransform = preTransform;
2524 swapChainInfo.compositeAlpha = compositeAlpha;
2525 swapChainInfo.presentMode = presentMode;
2526 swapChainInfo.clipped =
true;
2527 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2529 VkSwapchainKHR newSwapChain;
2530 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2531 if (err != VK_SUCCESS) {
2532 qWarning(
"Failed to create swapchain: %d", err);
2535 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2540 swapChainD->sc = newSwapChain;
2541 swapChainD->lastConnectedSurface = swapChainD->surface;
2543 quint32 actualSwapChainBufferCount = 0;
2544 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2545 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2546 qWarning(
"Failed to get swapchain images: %d", err);
2550 if (actualSwapChainBufferCount != reqBufferCount)
2551 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2554 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2555 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2556 if (err != VK_SUCCESS) {
2557 qWarning(
"Failed to get swapchain images: %d", err);
2561 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2562 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2563 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2564 if (!createTransientImage(swapChainD->colorFormat,
2565 swapChainD->pixelSize,
2566 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2567 VK_IMAGE_ASPECT_COLOR_BIT,
2568 swapChainD->samples,
2569 &swapChainD->msaaImageMem,
2572 swapChainD->bufferCount))
2574 qWarning(
"Failed to create transient image for MSAA color buffer");
2579 VkFenceCreateInfo fenceInfo = {};
2580 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2581 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2584 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2588 image.image = swapChainImages[i];
2589 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2590 image.msaaImage = msaaImages[i];
2591 image.msaaImageView = msaaViews[i];
2594 VkImageViewCreateInfo imgViewInfo = {};
2595 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2596 imgViewInfo.image = swapChainImages[i];
2597 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2598 imgViewInfo.format = swapChainD->colorFormat;
2599 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2600 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2601 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2602 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2603 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2604 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2605 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2606 if (err != VK_SUCCESS) {
2607 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2613 VkSemaphoreCreateInfo semInfo = {};
2614 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2615 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2620 image.image = swapChainImages[i];
2621 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2622 image.msaaImage = msaaImages[i];
2623 image.msaaImageView = msaaViews[i];
2626 VkImageViewCreateInfo imgViewInfo = {};
2627 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2628 imgViewInfo.image = swapChainImages[i];
2629 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2630 imgViewInfo.format = swapChainD->colorFormat;
2631 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2632 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2633 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2634 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2635 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2636 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2637 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2638 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2639 if (err != VK_SUCCESS) {
2640 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2644 VkSemaphoreCreateInfo semInfo = {};
2645 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2646 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2652 swapChainD->currentImageIndex = 0;
2654 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2656 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2657 VkImageViewCreateInfo viewInfo = {};
2658 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2659 viewInfo.image = texD->image;
2660 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2661 viewInfo.format = texD->viewFormat;
2662 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2663 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2664 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2665 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2666 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2667 viewInfo.subresourceRange.baseMipLevel = 0;
2668 viewInfo.subresourceRange.levelCount = 1;
2669 viewInfo.subresourceRange.baseArrayLayer = 0;
2670 viewInfo.subresourceRange.layerCount = 1;
2671 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2672 if (err != VK_SUCCESS) {
2673 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2678 VkSemaphoreCreateInfo semInfo = {};
2679 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2687 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2689 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2690 if (err != VK_SUCCESS) {
2691 qWarning(
"Failed to create command buffer fence: %d", err);
2704 if (swapChainD->sc == VK_NULL_HANDLE)
2708 df->vkQueueWaitIdle(gfxQueue);
2712 if (frame.cmdFence) {
2714 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2715 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2716 frame.cmdFence = VK_NULL_HANDLE;
2719 if (frame.imageSem) {
2720 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2721 frame.imageSem = VK_NULL_HANDLE;
2728 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2729 image.fb = VK_NULL_HANDLE;
2731 if (image.imageView) {
2732 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2733 image.imageView = VK_NULL_HANDLE;
2735 if (image.msaaImageView) {
2736 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2737 image.msaaImageView = VK_NULL_HANDLE;
2739 if (image.msaaImage) {
2740 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2741 image.msaaImage = VK_NULL_HANDLE;
2743 if (image.drawSem) {
2744 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2745 image.drawSem = VK_NULL_HANDLE;
2749 if (swapChainD->msaaImageMem) {
2750 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2751 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2754 if (swapChainD->shadingRateMapView) {
2755 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2756 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2759 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2760 swapChainD->sc = VK_NULL_HANDLE;
2767 VkCommandPoolResetFlags flags = 0;
2773 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2776 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2782 for (quint64 i = 0; i < timestampValidBits; i += 8)
2783 mask |= 0xFFULL << i;
2784 const quint64 ts0 = timestamp[0] & mask;
2785 const quint64 ts1 = timestamp[1] & mask;
2786 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2787 if (!qFuzzyIsNull(nsecsPerTick)) {
2788 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2789 const double elapsedSec = elapsedMs / 1000.0;
2800 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2803 inst->handle()->beginFrame(swapChainD->window);
2804 auto instEndFrameOnErrorGuard = qScopeGuard([
this, swapChainD] {
2805 inst->handle()->endFrame(swapChainD->window);
2816 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2817 if (waitResult != QRhi::FrameOpSuccess)
2822 uint32_t imageIndex = 0;
2823 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2824 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2826 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2827 swapChainD->currentImageIndex = imageIndex;
2830 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2831 return QRhi::FrameOpSwapChainOutOfDate;
2833 if (err == VK_ERROR_DEVICE_LOST) {
2834 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2835 printExtraErrorInfo(err);
2837 return QRhi::FrameOpDeviceLost;
2839 qWarning(
"Failed to acquire next swapchain image: %d", err);
2840 return QRhi::FrameOpError;
2852 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2853 if (cbres != QRhi::FrameOpSuccess)
2856 swapChainD->cbWrapper.cb = frame.cmdBuf;
2859 swapChainD->rtWrapper.d.fb = image.fb;
2863 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2864 swapChainD->rtWrapperRight.d.fb = image.fb;
2871 quint64 timestamp[2] = { 0, 0 };
2872 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2873 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2874 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2875 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2877 if (err == VK_SUCCESS) {
2879 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2881 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2883 qWarning(
"Failed to query timestamp: %d", err);
2888 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2889 int timestampQueryIdx = -1;
2890 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2891 if (!timestampQueryPoolMap.testBit(i)) {
2892 timestampQueryPoolMap.setBit(i);
2893 timestampQueryIdx = i * 2;
2897 if (timestampQueryIdx >= 0) {
2898 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2900 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2901 timestampQueryPool, uint32_t(timestampQueryIdx));
2906 instEndFrameOnErrorGuard.dismiss();
2907 return QRhi::FrameOpSuccess;
2915 auto cleanup = qScopeGuard([
this, swapChainD] {
2916 inst->handle()->endFrame(swapChainD->window);
2921 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2926 VkImageMemoryBarrier presTrans = {};
2927 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2928 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2929 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2930 presTrans.image = image.image;
2931 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2932 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2936 presTrans.srcAccessMask = 0;
2937 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2938 df->vkCmdPipelineBarrier(frame.cmdBuf,
2939 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2940 0, 0,
nullptr, 0,
nullptr,
2944 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2945 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2946 df->vkCmdPipelineBarrier(frame.cmdBuf,
2947 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2948 0, 0,
nullptr, 0,
nullptr,
2956 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2962 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2963 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2965 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2966 needsPresent ? &image.drawSem :
nullptr);
2967 if (submitres != QRhi::FrameOpSuccess)
2975 VkPresentInfoKHR presInfo = {};
2976 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2977 presInfo.swapchainCount = 1;
2978 presInfo.pSwapchains = &swapChainD->sc;
2979 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2980 waitSemaphoresForPresent.append(image.drawSem);
2981 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2982 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2986 inst->presentAboutToBeQueued(swapChainD->window);
2988 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2989 waitSemaphoresForPresent.clear();
2990 if (err != VK_SUCCESS) {
2991 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2992 return QRhi::FrameOpSwapChainOutOfDate;
2993 }
else if (err != VK_SUBOPTIMAL_KHR) {
2994 if (err == VK_ERROR_DEVICE_LOST) {
2995 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2996 printExtraErrorInfo(err);
2998 return QRhi::FrameOpDeviceLost;
3000 qWarning(
"Failed to present: %d", err);
3001 return QRhi::FrameOpError;
3007 inst->presentQueued(swapChainD->window);
3012 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3017 return QRhi::FrameOpSuccess;
3031 QRHI_RES(QVkCommandBuffer, cb)->resetState();
3041 VkCommandBufferAllocateInfo cmdBufInfo = {};
3042 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3043 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3044 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
3045 cmdBufInfo.commandBufferCount = 1;
3047 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
3048 if (err != VK_SUCCESS) {
3049 if (err == VK_ERROR_DEVICE_LOST) {
3050 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
3051 printExtraErrorInfo(err);
3053 return QRhi::FrameOpDeviceLost;
3055 qWarning(
"Failed to allocate frame command buffer: %d", err);
3056 return QRhi::FrameOpError;
3060 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3061 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3063 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
3064 if (err != VK_SUCCESS) {
3065 if (err == VK_ERROR_DEVICE_LOST) {
3066 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
3067 printExtraErrorInfo(err);
3069 return QRhi::FrameOpDeviceLost;
3071 qWarning(
"Failed to begin frame command buffer: %d", err);
3072 return QRhi::FrameOpError;
3075 return QRhi::FrameOpSuccess;
3079 VkSemaphore *waitSem, VkSemaphore *signalSem)
3081 VkResult err =
df->vkEndCommandBuffer(cb);
3082 if (err != VK_SUCCESS) {
3083 if (err == VK_ERROR_DEVICE_LOST) {
3084 qWarning(
"Device loss detected in vkEndCommandBuffer()");
3085 printExtraErrorInfo(err);
3087 return QRhi::FrameOpDeviceLost;
3089 qWarning(
"Failed to end frame command buffer: %d", err);
3090 return QRhi::FrameOpError;
3093 VkSubmitInfo submitInfo = {};
3094 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
3095 submitInfo.commandBufferCount = 1;
3096 submitInfo.pCommandBuffers = &cb;
3099 waitSemaphoresForQueueSubmit.append(*waitSem);
3101 signalSemaphoresForQueueSubmit.append(*signalSem);
3103 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
3104 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
3105 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
3106 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3107 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
3109 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3110 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3111 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3114 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3116 waitSemaphoresForQueueSubmit.clear();
3117 signalSemaphoresForQueueSubmit.clear();
3119 if (err != VK_SUCCESS) {
3120 if (err == VK_ERROR_DEVICE_LOST) {
3121 qWarning(
"Device loss detected in vkQueueSubmit()");
3122 printExtraErrorInfo(err);
3124 return QRhi::FrameOpDeviceLost;
3126 qWarning(
"Failed to submit to graphics queue: %d", err);
3127 return QRhi::FrameOpError;
3130 return QRhi::FrameOpSuccess;
3135 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3136 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3137 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3138 if (frame.cmdFenceWaitable) {
3139 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3141 if (err != VK_SUCCESS) {
3142 if (err == VK_ERROR_DEVICE_LOST) {
3143 qWarning(
"Device loss detected in vkWaitForFences()");
3144 printExtraErrorInfo(err);
3146 return QRhi::FrameOpDeviceLost;
3148 qWarning(
"Failed to wait for fence: %d", err);
3149 return QRhi::FrameOpError;
3152 df->vkResetFences(dev, 1, &frame.cmdFence);
3153 frame.cmdFenceWaitable =
false;
3157 if (ofr.cmdFenceWaitable[frameSlot]) {
3158 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3159 if (err != VK_SUCCESS) {
3160 if (err == VK_ERROR_DEVICE_LOST) {
3161 qWarning(
"Device loss detected in vkWaitForFences()");
3162 printExtraErrorInfo(err);
3164 return QRhi::FrameOpDeviceLost;
3166 qWarning(
"Failed to wait for offscreen fence: %d", err);
3167 return QRhi::FrameOpError;
3169 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3170 ofr.cmdFenceWaitable[frameSlot] =
false;
3173 return QRhi::FrameOpSuccess;
3178 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3179 if (waitResult != QRhi::FrameOpSuccess)
3185 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3186 if (cbres != QRhi::FrameOpSuccess)
3192 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3193 quint64 timestamp[2] = { 0, 0 };
3194 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3195 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3196 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3197 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3198 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3199 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3200 if (err == VK_SUCCESS) {
3202 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3206 qWarning(
"Failed to query timestamp: %d", err);
3210 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3211 int timestampQueryIdx = -1;
3212 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3213 if (!timestampQueryPoolMap.testBit(i)) {
3214 timestampQueryPoolMap.setBit(i);
3215 timestampQueryIdx = i * 2;
3219 if (timestampQueryIdx >= 0) {
3220 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3222 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3223 timestampQueryPool, uint32_t(timestampQueryIdx));
3224 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3229 return QRhi::FrameOpSuccess;
3235 Q_ASSERT(ofr.active);
3241 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3245 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3246 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3247 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3250 if (!ofr.cmdFence[currentFrameSlot]) {
3251 VkFenceCreateInfo fenceInfo = {};
3252 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3253 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3254 if (err != VK_SUCCESS) {
3255 qWarning(
"Failed to create command buffer fence: %d", err);
3256 return QRhi::FrameOpError;
3260 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3261 if (submitres != QRhi::FrameOpSuccess)
3264 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3267 if (readbacksPending) {
3268 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3269 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3270 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3277 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3279 return QRhi::FrameOpSuccess;
3301 swapChainFrameRes = &swapChainD->frameRes[swapChainD->bufferCount > 1 ? currentFrameSlot : 0];
3303 swapChainD->cbWrapper.resetCommands();
3304 cb = swapChainD->cbWrapper.cb;
3307 ? &swapChainFrameRes->imageSem
3309 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE, waitSem,
nullptr);
3310 if (submitres != QRhi::FrameOpSuccess)
3316 df->vkQueueWaitIdle(gfxQueue);
3323 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3325 startPrimaryCommandBuffer(&swapChainFrameRes->cmdBuf);
3326 swapChainD->cbWrapper.cb = swapChainFrameRes->cmdBuf;
3333 return QRhi::FrameOpSuccess;
3340 u
.access =
int(bufUsage.access);
3341 u
.stage =
int(bufUsage.stage);
3349 u
.access =
int(texUsage.access);
3350 u
.stage =
int(texUsage.stage);
3356 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3360 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3362 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3384 if (rtD->m_desc.depthStencilBuffer()) {
3386 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3395 if (rtD->m_desc.depthTexture()) {
3402 if (rtD->m_desc.depthResolveTexture()) {
3409 if (rtD->m_desc.shadingRateMap()) {
3428 VkCommandBuffer secondaryCb;
3430 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3431 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3432 freeSecondaryCbs[currentFrameSlot].removeLast();
3434 VkCommandBufferAllocateInfo cmdBufInfo = {};
3435 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3436 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3437 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3438 cmdBufInfo.commandBufferCount = 1;
3440 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3441 if (err != VK_SUCCESS) {
3442 qWarning(
"Failed to create secondary command buffer: %d", err);
3443 return VK_NULL_HANDLE;
3447 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3448 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3449 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3450 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3451 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3452 cmdBufInheritInfo.subpass = 0;
3454 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3455 cmdBufInheritInfo.framebuffer = rtD->fb;
3457 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3459 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3460 if (err != VK_SUCCESS) {
3461 qWarning(
"Failed to begin secondary command buffer: %d", err);
3462 return VK_NULL_HANDLE;
3470 VkResult err =
df->vkEndCommandBuffer(cb);
3471 if (err != VK_SUCCESS)
3472 qWarning(
"Failed to end secondary command buffer: %d", err);
3476 cmd.args.executeSecondary.cb = cb;
3481 e.secondaryCommandBuffer.cb = cb;
3482 releaseQueue.append(e);
3486 QRhiRenderTarget *rt,
3487 const QColor &colorClearValue,
3488 const QRhiDepthStencilClearValue &depthStencilClearValue,
3489 QRhiResourceUpdateBatch *resourceUpdates,
3490 QRhiCommandBuffer::BeginPassFlags flags)
3495 if (resourceUpdates)
3505 switch (rt->resourceType()) {
3506 case QRhiResource::SwapChainRenderTarget:
3521 case QRhiResource::TextureRenderTarget:
3535 cbD->currentTarget = rt;
3540 VkRenderPassBeginInfo rpBeginInfo = {};
3541 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3542 rpBeginInfo.renderPass = rtD
->rp->rp;
3543 rpBeginInfo.framebuffer = rtD->fb;
3544 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3545 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3547 const bool rpHasAnyClearOp =
std::any_of(rtD
->rp->attDescs.cbegin(), rtD
->rp->attDescs.cend(),
3548 [](
const VkAttachmentDescription &attDesc) {
3549 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3550 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3553 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3554 if (rpHasAnyClearOp) {
3556 VkClearValue cv = {};
3557 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3558 colorClearValue.alphaF() } };
3562 VkClearValue cv = {};
3563 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3567 VkClearValue cv = {};
3568 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3569 colorClearValue.alphaF() } };
3573 VkClearValue cv = {};
3574 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3578 VkClearValue cv = {};
3579 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3583 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3584 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3588 cmd.args.beginRenderPass.desc = rpBeginInfo;
3589 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3591 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3594 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3599 rateCmd.args.setShadingRate.w = 1;
3600 rateCmd.args.setShadingRate.h = 1;
3612 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3613 cbD->activeSecondaryCbStack.removeLast();
3614 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3621 cbD->currentTarget =
nullptr;
3623 if (resourceUpdates)
3628 QRhiResourceUpdateBatch *resourceUpdates,
3629 QRhiCommandBuffer::BeginPassFlags flags)
3634 if (resourceUpdates)
3642 cbD->computePassState.reset();
3645 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3656 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3657 cbD->activeSecondaryCbStack.removeLast();
3658 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3663 if (resourceUpdates)
3670 Q_ASSERT(psD->pipeline);
3676 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3680 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3681 cmd.args.bindPipeline.pipeline = psD->pipeline;
3684 cbD->currentGraphicsPipeline =
nullptr;
3685 cbD->currentComputePipeline = ps;
3694 QRhiShaderResourceBinding::Type bindingType,
3695 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3697 VkAccessFlags access = 0;
3698 if (bindingType == loadTypeVal) {
3699 access = VK_ACCESS_SHADER_READ_BIT;
3701 access = VK_ACCESS_SHADER_WRITE_BIT;
3702 if (bindingType == loadStoreTypeVal)
3703 access |= VK_ACCESS_SHADER_READ_BIT;
3705 auto it = writtenResources->find(resource);
3706 if (it != writtenResources->end())
3707 it->second.accessFlags |= access;
3708 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3709 writtenResources->insert(resource, { access,
true });
3714 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3715 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3716 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3717 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3718 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3719 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3725 QVarLengthArray<VkImageMemoryBarrier, 8> *imageBarriers,
3726 QVarLengthArray<VkBufferMemoryBarrier, 8> *bufferBarriers)
3728 if (!cbD->currentComputeSrb)
3734 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3735 accessAndIsNewFlag = { 0,
false };
3738 for (
auto &binding : srbD->m_bindings) {
3739 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3740 switch (b->type()) {
3741 case QRhiShaderResourceBinding::ImageLoad:
3742 case QRhiShaderResourceBinding::ImageStore:
3743 case QRhiShaderResourceBinding::ImageLoadStore:
3744 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3747 QRhiShaderResourceBinding::ImageLoad,
3748 QRhiShaderResourceBinding::ImageStore,
3749 QRhiShaderResourceBinding::ImageLoadStore);
3751 case QRhiShaderResourceBinding::BufferLoad:
3752 case QRhiShaderResourceBinding::BufferStore:
3753 case QRhiShaderResourceBinding::BufferLoadStore:
3754 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3757 QRhiShaderResourceBinding::BufferLoad,
3758 QRhiShaderResourceBinding::BufferStore,
3759 QRhiShaderResourceBinding::BufferLoadStore);
3766 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3767 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3768 const bool isNewInThisDispatch = it->second.isNew;
3769 if (accessInThisDispatch && !isNewInThisDispatch) {
3770 if (it.key()->resourceType() == QRhiResource::Texture) {
3772 VkImageMemoryBarrier barrier = {};
3773 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3774 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3776 barrier.subresourceRange.baseMipLevel = 0;
3777 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3778 barrier.subresourceRange.baseArrayLayer = 0;
3779 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3780 barrier.oldLayout = texD->usageState.layout;
3781 barrier.newLayout = texD->usageState.layout;
3782 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3783 barrier.dstAccessMask = accessInThisDispatch;
3784 barrier.image = texD->image;
3785 imageBarriers->append(barrier);
3788 VkBufferMemoryBarrier barrier = {};
3789 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3790 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3791 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3792 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3793 barrier.dstAccessMask = accessInThisDispatch;
3794 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3795 barrier.size = VK_WHOLE_SIZE;
3796 bufferBarriers->append(barrier);
3802 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3803 it = cbD->computePassState.writtenResources.erase(it);
3814 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3815 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3816 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
3819 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3820 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3821 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3823 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3824 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3826 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3828 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3831 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3832 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3833 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3834 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3835 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3836 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3837 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3838 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3842 cmd.args.dispatch.x = x;
3843 cmd.args.dispatch.y = y;
3844 cmd.args.dispatch.z = z;
3849 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3850 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3851 quint32 maxDrawCount, quint32 stride)
3853 if (!caps.drawIndirectCount) {
3854 qWarning(
"drawIndirectCount called but the DrawIndirectCount feature is not supported");
3864 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3866 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3870 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3874 if (countBufD->m_type == QRhiBuffer::Dynamic)
3876 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3880 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3883#ifdef VK_VERSION_1_2
3884 vkCmdDrawIndirectCount(cbD->activeSecondaryCbStack.last(),
3885 indirectBufVk, indirectBufferOffset,
3886 countBufVk, countBufferOffset,
3887 maxDrawCount, stride);
3892 cmd.args.drawIndirectCount.indirectBuffer = indirectBufVk;
3893 cmd.args.drawIndirectCount.indirectBufferOffset = indirectBufferOffset;
3894 cmd.args.drawIndirectCount.countBuffer = countBufVk;
3895 cmd.args.drawIndirectCount.countBufferOffset = countBufferOffset;
3896 cmd.args.drawIndirectCount.maxDrawCount = maxDrawCount;
3897 cmd.args.drawIndirectCount.stride = stride;
3902 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3903 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3904 quint32 maxDrawCount, quint32 stride)
3906 if (!caps.drawIndirectCount) {
3907 qWarning(
"drawIndexedIndirectCount called but the DrawIndirectCount feature is not supported");
3917 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3919 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3923 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3927 if (countBufD->m_type == QRhiBuffer::Dynamic)
3929 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3933 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3936#ifdef VK_VERSION_1_2
3937 vkCmdDrawIndexedIndirectCount(cbD->activeSecondaryCbStack.last(),
3938 indirectBufVk, indirectBufferOffset,
3939 countBufVk, countBufferOffset,
3940 maxDrawCount, stride);
3945 cmd.args.drawIndexedIndirectCount.indirectBuffer = indirectBufVk;
3946 cmd.args.drawIndexedIndirectCount.indirectBufferOffset = indirectBufferOffset;
3947 cmd.args.drawIndexedIndirectCount.countBuffer = countBufVk;
3948 cmd.args.drawIndexedIndirectCount.countBufferOffset = countBufferOffset;
3949 cmd.args.drawIndexedIndirectCount.maxDrawCount = maxDrawCount;
3950 cmd.args.drawIndexedIndirectCount.stride = stride;
3955 quint32 indirectBufferOffset)
3963 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3965 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3966 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3971 VkAccessFlags indirectSrcAccess = 0;
3972 VkPipelineStageFlags indirectSrcStage = 0;
3977 if (cbD->computePassState.writtenResources.contains(indirectBufD)) {
3978 indirectSrcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
3979 indirectSrcStage |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3987 const auto trackedIt = passResTracker
.buffers().find(indirectBufD);
3988 if (trackedIt != passResTracker
.buffers().cend()
3991 indirectSrcAccess |= VkAccessFlags(trackedIt->second.stateAtPassBegin.access);
3992 indirectSrcStage |= VkPipelineStageFlags(trackedIt->second.stateAtPassBegin.stage);
3995 u.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
3996 u.stage |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
4003 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
4004 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
4005 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
4007 VkBufferMemoryBarrier indirectBarrier = {};
4008 const bool needsIndirectBarrier = indirectSrcStage != 0 && accessIsWrite(indirectSrcAccess);
4009 if (needsIndirectBarrier) {
4010 indirectBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4011 indirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4012 indirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4013 indirectBarrier.srcAccessMask = indirectSrcAccess;
4014 indirectBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
4015 indirectBarrier.buffer = indirectBufVk;
4016 indirectBarrier.size = VK_WHOLE_SIZE;
4020 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
4021 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
4022 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
4024 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
4025 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
4027 if (needsIndirectBarrier) {
4028 df->vkCmdPipelineBarrier(secondaryCb, indirectSrcStage, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
4030 1, &indirectBarrier,
4033 df->vkCmdDispatchIndirect(secondaryCb, indirectBufVk, VkDeviceSize(indirectBufferOffset));
4035 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
4038 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4039 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4040 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
4041 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
4042 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
4043 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
4044 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
4045 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
4047 if (needsIndirectBarrier) {
4050 cmd.args.bufferBarrier.srcStageMask = indirectSrcStage;
4051 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
4052 cmd.args.bufferBarrier.count = 1;
4053 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4054 cbD->pools.bufferBarrier.append(indirectBarrier);
4058 cmd.args.dispatchIndirect.indirectBuffer = indirectBufVk;
4059 cmd.args.dispatchIndirect.indirectBufferOffset = VkDeviceSize(indirectBufferOffset);
4065 VkShaderModuleCreateInfo shaderInfo = {};
4066 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
4067 shaderInfo.codeSize = size_t(spirv.size());
4068 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
4069 VkShaderModule shaderModule;
4070 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
4071 if (err != VK_SUCCESS) {
4072 qWarning(
"Failed to create shader module: %d", err);
4073 return VK_NULL_HANDLE;
4075 return shaderModule;
4083 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
4084 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
4085 pipelineCacheInfo.initialDataSize = initialDataSize;
4086 pipelineCacheInfo.pInitialData = initialData;
4087 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
4088 if (err != VK_SUCCESS) {
4089 qWarning(
"Failed to create pipeline cache: %d", err);
4099 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
4100 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
4101 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
4102 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
4103 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
4105 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
4106 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
4109 VkWriteDescriptorSet writeInfo = {};
4110 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
4111 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
4112 writeInfo.dstBinding = uint32_t(b->binding);
4113 writeInfo.descriptorCount = 1;
4115 int bufferInfoIndex = -1;
4116 int imageInfoIndex = -1;
4118 switch (b->type()) {
4119 case QRhiShaderResourceBinding::UniformBuffer:
4121 writeInfo.descriptorType = b->ubuf().hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
4122 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
4123 QRhiBuffer *buf = b->ubuf().buf;
4125 bd.ubuf.id = bufD->m_id;
4127 VkDescriptorBufferInfo bufInfo = {};
4128 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4129 bufInfo.offset = b->ubuf().offset;
4130 bufInfo.range = b->ubuf().maybeSize ? b->ubuf().maybeSize : VK_WHOLE_SIZE;
4132 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
4133 bufferInfoIndex = bufferInfos.size();
4134 bufferInfos.append(bufInfo);
4137 case QRhiShaderResourceBinding::SampledTexture:
4139 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex();
4140 writeInfo.descriptorCount = data->count();
4141 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
4142 ArrayOfImageDesc imageInfo(data->count());
4143 bd.stex.d.resize(data->count());
4144 for (
int elem = 0; elem < data->count(); ++elem) {
4147 bd.stex.d[elem].texId = texD->m_id;
4149 bd.stex.d[elem].samplerId = samplerD->m_id;
4150 bd.stex.d[elem].samplerGeneration = samplerD
->generation;
4151 imageInfo[elem].sampler = samplerD->sampler;
4152 imageInfo[elem].imageView = texD->imageView;
4153 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4155 imageInfoIndex = imageInfos.size();
4156 imageInfos.append(imageInfo);
4159 case QRhiShaderResourceBinding::Texture:
4161 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex();
4162 writeInfo.descriptorCount = data->count();
4163 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
4164 ArrayOfImageDesc imageInfo(data->count());
4165 bd.stex.d.resize(data->count());
4166 for (
int elem = 0; elem < data->count(); ++elem) {
4168 bd.stex.d[elem].texId = texD->m_id;
4170 bd.stex.d[elem].samplerId = 0;
4171 bd.stex.d[elem].samplerGeneration = 0;
4172 imageInfo[elem].sampler = VK_NULL_HANDLE;
4173 imageInfo[elem].imageView = texD->imageView;
4174 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4176 imageInfoIndex = imageInfos.size();
4177 imageInfos.append(imageInfo);
4180 case QRhiShaderResourceBinding::Sampler:
4183 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
4184 bd.stex.d.resize(1);
4185 bd.stex.d[0].texId = 0;
4186 bd.stex.d[0].texGeneration = 0;
4187 bd.stex.d[0].samplerId = samplerD->m_id;
4189 ArrayOfImageDesc imageInfo(1);
4190 imageInfo[0].sampler = samplerD->sampler;
4191 imageInfo[0].imageView = VK_NULL_HANDLE;
4192 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4193 imageInfoIndex = imageInfos.size();
4194 imageInfos.append(imageInfo);
4197 case QRhiShaderResourceBinding::ImageLoad:
4198 case QRhiShaderResourceBinding::ImageStore:
4199 case QRhiShaderResourceBinding::ImageLoadStore:
4202 VkImageView view = texD->perLevelImageViewForLoadStore(b->simage().level);
4204 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
4205 bd.simage.id = texD->m_id;
4207 ArrayOfImageDesc imageInfo(1);
4208 imageInfo[0].sampler = VK_NULL_HANDLE;
4209 imageInfo[0].imageView = view;
4210 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4211 imageInfoIndex = imageInfos.size();
4212 imageInfos.append(imageInfo);
4216 case QRhiShaderResourceBinding::BufferLoad:
4217 case QRhiShaderResourceBinding::BufferStore:
4218 case QRhiShaderResourceBinding::BufferLoadStore:
4221 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
4222 bd.sbuf.id = bufD->m_id;
4224 VkDescriptorBufferInfo bufInfo = {};
4225 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4226 bufInfo.offset = b->sbuf().offset;
4227 bufInfo.range = b->sbuf().maybeSize ? b->sbuf().maybeSize : VK_WHOLE_SIZE;
4228 bufferInfoIndex = bufferInfos.size();
4229 bufferInfos.append(bufInfo);
4236 writeInfos.append(writeInfo);
4237 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
4240 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
4241 const int bufferInfoIndex = infoIndices[i].first;
4242 const int imageInfoIndex = infoIndices[i].second;
4243 if (bufferInfoIndex >= 0)
4244 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
4245 else if (imageInfoIndex >= 0)
4246 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
4249 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
4253 VkAccessFlags access, VkPipelineStageFlags stage)
4256 Q_ASSERT(access && stage);
4264 if (s.access == access && s.stage == stage) {
4267 if (!accessIsWrite(access))
4271 VkBufferMemoryBarrier bufMemBarrier = {};
4272 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4273 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4274 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4275 bufMemBarrier.srcAccessMask = s.access;
4276 bufMemBarrier.dstAccessMask = access;
4277 bufMemBarrier.buffer = bufD->buffers[slot];
4278 bufMemBarrier.size = VK_WHOLE_SIZE;
4282 cmd.args.bufferBarrier.srcStageMask = s.stage;
4283 cmd.args.bufferBarrier.dstStageMask = stage;
4284 cmd.args.bufferBarrier.count = 1;
4285 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4286 cbD->pools.bufferBarrier.append(bufMemBarrier);
4293 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
4296 Q_ASSERT(layout && access && stage);
4298 if (s.access == access && s.stage == stage && s.layout == layout) {
4299 if (!accessIsWrite(access))
4303 VkImageMemoryBarrier barrier = {};
4304 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4305 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
4306 barrier.subresourceRange.baseMipLevel = 0;
4307 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4308 barrier.subresourceRange.baseArrayLayer = 0;
4309 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4310 barrier.oldLayout = s.layout;
4311 barrier.newLayout = layout;
4312 barrier.srcAccessMask = s.access;
4313 barrier.dstAccessMask = access;
4314 barrier.image = texD->image;
4316 VkPipelineStageFlags srcStage = s.stage;
4319 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4323 cmd.args.imageBarrier.srcStageMask = srcStage;
4324 cmd.args.imageBarrier.dstStageMask = stage;
4325 cmd.args.imageBarrier.count = 1;
4326 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4327 cbD->pools.imageBarrier.append(barrier);
4338 VkImageMemoryBarrier barrier = {};
4339 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4340 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4341 barrier.subresourceRange.baseMipLevel = 0;
4342 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4343 barrier.subresourceRange.baseArrayLayer = 0;
4344 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4345 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4346 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4347 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4348 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4349 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4350 barrier.image = rbD->image;
4352 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4353 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4357 cmd.args.imageBarrier.srcStageMask = stages;
4358 cmd.args.imageBarrier.dstStageMask = stages;
4359 cmd.args.imageBarrier.count = 1;
4360 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4361 cbD->pools.imageBarrier.append(barrier);
4365 VkImageLayout oldLayout, VkImageLayout newLayout,
4366 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4367 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4368 int startLayer,
int layerCount,
4369 int startLevel,
int levelCount)
4372 VkImageMemoryBarrier barrier = {};
4373 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4374 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4375 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4376 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4377 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4378 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4379 barrier.oldLayout = oldLayout;
4380 barrier.newLayout = newLayout;
4381 barrier.srcAccessMask = srcAccess;
4382 barrier.dstAccessMask = dstAccess;
4383 barrier.image = image;
4387 cmd.args.imageBarrier.srcStageMask = srcStage;
4388 cmd.args.imageBarrier.dstStageMask = dstStage;
4389 cmd.args.imageBarrier.count = 1;
4390 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4391 cbD->pools.imageBarrier.append(barrier);
4396 VkDeviceSize size = 0;
4397 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4398 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4399 if (imageSizeBytes > 0)
4400 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4405 const QRhiTextureSubresourceUploadDescription &subresDesc,
4406 size_t *curOfs,
void *mp,
4407 BufferImageCopyList *copyInfos)
4409 qsizetype copySizeBytes = 0;
4410 qsizetype imageSizeBytes = 0;
4411 const void *src =
nullptr;
4412 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4413 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4415 VkBufferImageCopy copyInfo = {};
4416 copyInfo.bufferOffset = *curOfs;
4417 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4418 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4419 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4420 copyInfo.imageSubresource.layerCount = 1;
4421 copyInfo.imageExtent.depth = 1;
4423 copyInfo.imageOffset.z = uint32_t(layer);
4425 copyInfo.imageOffset.y = uint32_t(layer);
4427 const QByteArray rawData = subresDesc.data();
4428 const QPoint dp = subresDesc.destinationTopLeft();
4429 QImage image = subresDesc.image();
4430 if (!image.isNull()) {
4431 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4432 QSize size = image.size();
4433 src = image.constBits();
4436 int bpc = qMax(1, image.depth() / 8);
4438 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4439 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4440 const int sx = subresDesc.sourceTopLeft().x();
4441 const int sy = subresDesc.sourceTopLeft().y();
4442 if (!subresDesc.sourceSize().isEmpty())
4443 size = subresDesc.sourceSize();
4444 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4445 if (size.width() == image.width()) {
4448 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4449 copySizeBytes = size.height() * image.bytesPerLine();
4451 image = image.copy(sx, sy, size.width(), size.height());
4452 src = image.constBits();
4455 copySizeBytes = image.sizeInBytes();
4456 bpc = qMax(1, image.depth() / 8);
4457 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4460 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4462 copyInfo.imageOffset.x = dp.x();
4463 copyInfo.imageOffset.y = dp.y();
4464 copyInfo.imageExtent.width = uint32_t(size.width());
4465 copyInfo.imageExtent.height = uint32_t(size.height());
4466 copyInfos->append(copyInfo);
4467 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4468 copySizeBytes = imageSizeBytes = rawData.size();
4469 src = rawData.constData();
4470 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4471 const int subresw = size.width();
4472 const int subresh = size.height();
4473 if (!subresDesc.sourceSize().isEmpty())
4474 size = subresDesc.sourceSize();
4475 const int w = size.width();
4476 const int h = size.height();
4478 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4480 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4481 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4484 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4485 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4486 copyInfos->append(copyInfo);
4487 }
else if (!rawData.isEmpty()) {
4488 copySizeBytes = imageSizeBytes = rawData.size();
4489 src = rawData.constData();
4490 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4491 if (!subresDesc.sourceSize().isEmpty())
4492 size = subresDesc.sourceSize();
4493 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4495 quint32 bytesPerPixel = 0;
4496 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4497 if (subresDesc.dataStride() && bytesPerPixel)
4498 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4500 size = clampedSubResourceUploadSizeForSourceData(size, subresDesc.dataStride(),
4501 bytesPerPixel, rawData.size());
4503 if (!size.isEmpty()) {
4504 copyInfo.imageOffset.x = dp.x();
4505 copyInfo.imageOffset.y = dp.y();
4506 copyInfo.imageExtent.width = uint32_t(size.width());
4507 copyInfo.imageExtent.height = uint32_t(size.height());
4508 copyInfos->append(copyInfo);
4511 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4515 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4516 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4522 if (err == VK_ERROR_DEVICE_LOST)
4523 printDeviceLossErrorInfo();
4524 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4525 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4530#ifdef VK_EXT_device_fault
4531 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4534 VkDeviceFaultCountsEXT faultCounts{};
4535 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4536 faultCounts.pNext =
nullptr;
4538 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4539 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4540 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4543 faultCounts.vendorBinarySize = 0;
4545 const auto numAddressInfos = faultCounts.addressInfoCount;
4546 const auto addressInfos
4547 = q20::make_unique_for_overwrite<VkDeviceFaultAddressInfoEXT[]>(numAddressInfos);
4549 const auto numVendorInfos = faultCounts.vendorInfoCount;
4550 const auto vendorInfos
4551 = q20::make_unique_for_overwrite<VkDeviceFaultVendorInfoEXT[]>(numVendorInfos);
4553 VkDeviceFaultInfoEXT info{};
4554 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4555 info.pNext =
nullptr;
4556 info.pAddressInfos = numAddressInfos ? addressInfos.get() :
nullptr;
4557 info.pVendorInfos = numVendorInfos ? vendorInfos.get() :
nullptr;
4558 info.pVendorBinaryData =
nullptr;
4560 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4561 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4562 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4566 const char *desc = info.description[0] ? info.description :
"n/a";
4567 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4568 faultCounts.addressInfoCount,
4569 faultCounts.vendorInfoCount,
4570 (
unsigned long long)faultCounts.vendorBinarySize,
4573 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4574 const auto &a = addressInfos[i];
4575 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4577 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4578 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4579 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4580 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4581 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4582 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4583 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4584 default:
return "UNKNOWN";
4587 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4589 addressTypeString(a.addressType),
4590 (
unsigned long long)a.reportedAddress,
4591 (
unsigned long long)a.addressPrecision);
4594 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4595 const auto &v = vendorInfos[i];
4596 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4598 (
unsigned long long)v.vendorFaultCode,
4599 (
unsigned long long)v.vendorFaultData,
4613 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4615 if (u.offset == 0 && u.data.size() == bufD->m_size)
4616 bufD->pendingDynamicUpdates[i].clear();
4617 bufD->pendingDynamicUpdates[i].append({ u.offset, u.data });
4621 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4622 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
4624 if (!bufD->stagingBuffers[currentFrameSlot]) {
4625 VkBufferCreateInfo bufferInfo = {};
4626 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4629 bufferInfo.size = bufD->m_size;
4630 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4632 VmaAllocationCreateInfo allocInfo = {};
4633 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4635 VmaAllocation allocation;
4636 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4637 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4638 if (err == VK_SUCCESS) {
4639 bufD->stagingAllocations[currentFrameSlot] = allocation;
4640 setAllocationName(allocation, bufD->name());
4642 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4643 printExtraErrorInfo(err);
4648 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u.data.constData(),
4649 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4650 u.offset, u.data.size());
4651 if (err != VK_SUCCESS) {
4652 qWarning(
"Failed to copy memory to buffer: %d", err);
4656 trackedBufferBarrier(cbD, bufD, 0,
4657 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4659 VkBufferCopy copyInfo = {};
4660 copyInfo.srcOffset = u.offset;
4661 copyInfo.dstOffset = u.offset;
4662 copyInfo.size = u.data.size();
4666 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4667 cmd.args.copyBuffer.dst = bufD->buffers[0];
4668 cmd.args.copyBuffer.desc = copyInfo;
4679 if (bufD->m_type == QRhiBuffer::Immutable) {
4683 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4684 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4685 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4686 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4687 releaseQueue.append(e);
4691 if (bufD->m_type == QRhiBuffer::Dynamic) {
4693 u.result->data.resizeForOverwrite(u.readSize);
4694 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4695 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4696 u.offset, u.result->data.data(), u.readSize);
4697 if (err != VK_SUCCESS) {
4698 qWarning(
"Failed to copy memory from buffer: %d", err);
4699 u.result->data.clear();
4701 if (u.result->completed)
4702 u.result->completed();
4712 readback.result = u.result;
4713 readback.byteSize = u.readSize;
4715 VkBufferCreateInfo bufferInfo = {};
4716 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4717 bufferInfo.size = readback.byteSize;
4718 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4720 VmaAllocationCreateInfo allocInfo = {};
4721 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4723 VmaAllocation allocation;
4724 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4725 if (err == VK_SUCCESS) {
4727 setAllocationName(allocation, bufD->name());
4729 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4730 printExtraErrorInfo(err);
4734 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4736 VkBufferCopy copyInfo = {};
4737 copyInfo.srcOffset = u.offset;
4738 copyInfo.size = u.readSize;
4742 cmd.args.copyBuffer.src = bufD->buffers[0];
4743 cmd.args.copyBuffer.dst = readback.stagingBuf;
4744 cmd.args.copyBuffer.desc = copyInfo;
4748 activeBufferReadbacks.append(readback);
4753 Q_ASSERT(dstD->m_type != QRhiBuffer::Dynamic && srcD->m_type != QRhiBuffer::Dynamic);
4755 trackedBufferBarrier(cbD, srcD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4756 trackedBufferBarrier(cbD, dstD, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4758 VkBufferCopy copyInfo = {};
4759 copyInfo.srcOffset = u.srcOffset;
4760 copyInfo.dstOffset = u.offset;
4761 copyInfo.size = u.readSize;
4765 cmd.args.copyBuffer.src = srcD->buffers[0];
4766 cmd.args.copyBuffer.dst = dstD->buffers[0];
4767 cmd.args.copyBuffer.desc = copyInfo;
4772 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4774 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4778 cmd.args.fillBuffer.dst = bufD->buffers[0];
4779 cmd.args.fillBuffer.offset = u.offset;
4780 cmd.args.fillBuffer.size = u.readSize;
4781 cmd.args.fillBuffer.data = u.fillValue32();
4792 VkDeviceSize stagingSize = 0;
4793 for (
const auto &subres : u.subresDesc)
4794 stagingSize += subresUploadByteSize(subres.desc);
4796 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4797 VkBufferCreateInfo bufferInfo = {};
4798 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4799 bufferInfo.size = stagingSize;
4800 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4802 VmaAllocationCreateInfo allocInfo = {};
4803 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4805 VmaAllocation allocation;
4806 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4807 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4808 if (err != VK_SUCCESS) {
4809 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4810 printExtraErrorInfo(err);
4813 utexD->stagingAllocations[currentFrameSlot] = allocation;
4814 setAllocationName(allocation, utexD->name());
4816 BufferImageCopyList copyInfos;
4819 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4820 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4821 if (err != VK_SUCCESS) {
4822 qWarning(
"Failed to map image data: %d", err);
4823 vmaDestroyBuffer(toVmaAllocator(allocator), utexD->stagingBuffers[currentFrameSlot], a);
4824 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4825 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4829 for (
const auto &subres : u.subresDesc)
4830 prepareUploadSubres(utexD, subres.layer, subres.level, subres.desc, &curOfs, mp, ©Infos);
4831 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4832 vmaUnmapMemory(toVmaAllocator(allocator), a);
4834 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4835 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4837 if (!copyInfos.isEmpty()) {
4840 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4841 cmd.args.copyBufferToImage.dst = utexD->image;
4842 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4843 cmd.args.copyBufferToImage.count = copyInfos.size();
4844 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4845 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4852 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4853 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4854 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4855 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4856 releaseQueue.append(e);
4865 qWarning(
"Texture copy with matching source and destination is not supported");
4870 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4871 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4873 VkImageCopy region = {};
4874 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4875 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4876 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4877 region.srcSubresource.layerCount = 1;
4879 region.srcOffset.x = u.desc.sourceTopLeft().x();
4880 region.srcOffset.y = u.desc.sourceTopLeft().y();
4882 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4884 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4885 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4886 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4887 region.dstSubresource.layerCount = 1;
4889 region.dstOffset.x = u.desc.destinationTopLeft().x();
4890 region.dstOffset.y = u.desc.destinationTopLeft().y();
4892 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4894 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4895 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4896 region.extent.width = uint32_t(copySize.width());
4897 region.extent.height = uint32_t(copySize.height());
4898 region.extent.depth = 1;
4900 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4901 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4902 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4903 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4907 cmd.args.copyImage.src = srcD->image;
4908 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4909 cmd.args.copyImage.dst = dstD->image;
4910 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4911 cmd.args.copyImage.desc = region;
4917 readback.desc = u.rb;
4918 readback.result = u.result;
4924 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4925 qWarning(
"Multisample texture cannot be read back");
4928 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4929 if (u.rb.rect().isValid())
4930 readback.rect = u.rb.rect();
4932 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4933 readback.format = texD->m_format;
4939 qWarning(
"Swapchain does not support readback");
4942 if (u.rb.rect().isValid())
4943 readback.rect = u.rb.rect();
4945 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4946 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4947 if (readback.format == QRhiTexture::UnknownFormat)
4953 if (!textureFormatInfo(readback.format, readback.rect.size(),
nullptr,
4954 &readback.byteSize,
nullptr))
4962 const bool combinedDepthStencil = texD && isStencilTextureFormat(readback.format);
4967 const quint64 pixelCount =
4968 quint64(readback.rect.width()) * quint64(readback.rect.height());
4969 const quint64 depthPlaneByteSize = pixelCount * 4;
4970 const quint64 stagingByteSize = combinedDepthStencil
4971 ? depthPlaneByteSize + pixelCount
4972 : readback.byteSize;
4973 if (stagingByteSize > std::numeric_limits<quint32>::max()) {
4974 qWarning(
"Readback of texture of size %dx%d would need %llu bytes "
4975 "which is too large to be handled",
4976 readback.rect.width(), readback.rect.height(), stagingByteSize);
4981 VkBufferCreateInfo bufferInfo = {};
4982 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4983 bufferInfo.size = stagingByteSize;
4984 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4986 VmaAllocationCreateInfo allocInfo = {};
4987 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4989 VmaAllocation allocation;
4990 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4991 if (err == VK_SUCCESS) {
4993 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4995 qWarning(
"Failed to create readback buffer of size %llu: %d", stagingByteSize, err);
4996 printExtraErrorInfo(err);
5001 VkBufferImageCopy copyDesc = {};
5002 copyDesc.bufferOffset = 0;
5003 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
5004 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
5005 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
5006 copyDesc.imageSubresource.layerCount = 1;
5007 copyDesc.imageOffset.x = readback.rect.x();
5008 copyDesc.imageOffset.y = readback.rect.y();
5010 copyDesc.imageOffset.z = u.rb.layer();
5011 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
5012 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
5013 copyDesc.imageExtent.depth = 1;
5015 const int bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
5016 if (combinedDepthStencil) {
5017 copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
5018 cbD->pools.bufferImageCopy.append(copyDesc);
5019 copyDesc.bufferOffset = depthPlaneByteSize;
5020 copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
5022 cbD->pools.bufferImageCopy.append(copyDesc);
5023 const int copyCount = cbD->pools.bufferImageCopy.size() - bufferImageCopyIndex;
5026 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5027 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
5030 cmd.args.copyImageToBuffer.src = texD->image;
5031 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
5032 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
5033 cmd.args.copyImageToBuffer.count = copyCount;
5034 cmd.args.copyImageToBuffer.bufferImageCopyIndex = bufferImageCopyIndex;
5038 VkImage image = imageRes.image;
5041 qWarning(
"Attempted to read back undefined swapchain image content, "
5042 "results are undefined. (do a render pass first)");
5044 subresourceBarrier(cbD, image,
5045 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5046 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
5047 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5055 cmd.args.copyImageToBuffer.src = image;
5056 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5057 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
5058 cmd.args.copyImageToBuffer.count = copyCount;
5059 cmd.args.copyImageToBuffer.bufferImageCopyIndex = bufferImageCopyIndex;
5062 activeTextureReadbacks.append(readback);
5065 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
5066 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
5067 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
5068 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
5070 VkImageLayout origLayout = utexD->usageState.layout;
5071 VkAccessFlags origAccess = utexD->usageState.access;
5072 VkPipelineStageFlags origStage = utexD->usageState.stage;
5074 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5076 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
5077 int w = utexD->m_pixelSize.width();
5078 int h = utexD->m_pixelSize.height();
5079 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
5082 subresourceBarrier(cbD, utexD->image,
5083 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5084 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
5085 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
5089 subresourceBarrier(cbD, utexD->image,
5090 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5091 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
5092 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5097 subresourceBarrier(cbD, utexD->image,
5098 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5099 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
5100 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
5104 VkImageBlit region = {};
5105 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5106 region.srcSubresource.mipLevel = uint32_t(level) - 1;
5107 region.srcSubresource.baseArrayLayer = uint32_t(layer);
5108 region.srcSubresource.layerCount = 1;
5110 region.srcOffsets[1].x = qMax(1, w);
5111 region.srcOffsets[1].y = qMax(1, h);
5112 region.srcOffsets[1].z = qMax(1, depth);
5114 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5115 region.dstSubresource.mipLevel = uint32_t(level);
5116 region.dstSubresource.baseArrayLayer = uint32_t(layer);
5117 region.dstSubresource.layerCount = 1;
5119 region.dstOffsets[1].x = qMax(1, w >> 1);
5120 region.dstOffsets[1].y = qMax(1, h >> 1);
5121 region.dstOffsets[1].z = qMax(1, depth >> 1);
5125 cmd.args.blitImage.src = utexD->image;
5126 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5127 cmd.args.blitImage.dst = utexD->image;
5128 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5129 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
5130 cmd.args.blitImage.desc = region;
5138 subresourceBarrier(cbD, utexD->image,
5139 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
5140 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
5141 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5143 0,
int(utexD->mipLevelCount) - 1);
5144 subresourceBarrier(cbD, utexD->image,
5145 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
5146 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
5147 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5149 int(utexD->mipLevelCount) - 1, 1);
5161 if (bufD->pendingDynamicUpdates[slot].isEmpty())
5164 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
5166 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
5170 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
5171 if (err != VK_SUCCESS) {
5172 qWarning(
"Failed to map buffer: %d", err);
5175 quint32 changeBegin = UINT32_MAX;
5176 quint32 changeEnd = 0;
5177 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
5178 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
5179 if (u.offset < changeBegin)
5180 changeBegin = u.offset;
5181 if (u.offset + u.data.size() > changeEnd)
5182 changeEnd = u.offset + u.data.size();
5184 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
5185 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
5186 vmaUnmapMemory(toVmaAllocator(allocator), a);
5188 bufD->pendingDynamicUpdates[slot].clear();
5194 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
5195 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
5201 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
5202 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
5203 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
5208 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
5209 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
5211 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
5212 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
5213 if (e.texture.extraImageViews[i])
5214 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
5220 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
5225 qsizetype keepBegin = releaseQueue.size();
5226 for (qsizetype i = keepBegin - 1; i >= 0; --i) {
5228 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
5231 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
5232 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
5235 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
5236 if (e.shaderResourceBindings.poolIndex >= 0) {
5237 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
5238 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
5245 qrhivk_releaseRenderBuffer(e, dev,
df);
5251 qrhivk_releaseSampler(e, dev,
df);
5254 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
5256 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
5257 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
5259 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
5260 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
5261 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
5264 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
5267 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
5269 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
5270 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
5276 }
else if (--keepBegin != i) {
5277 releaseQueue[keepBegin] = std::move(releaseQueue[i]);
5281 releaseQueue.remove(0, keepBegin);
5286 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5288 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
5290 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5291 readback.result->format = readback.format;
5292 readback.result->pixelSize = readback.rect.size();
5293 readback.result->data.resizeForOverwrite(readback.byteSize);
5295 if (isStencilTextureFormat(readback.format)) {
5303 const quint64 pixelCount =
5304 quint64(readback.rect.width()) * quint64(readback.rect.height());
5305 const quint64 depthPlaneByteSize = pixelCount * 4;
5307 planar.resizeForOverwrite(qsizetype(depthPlaneByteSize + pixelCount));
5308 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5309 toVmaAllocation(readback.stagingAlloc),
5310 0, planar.data(), size_t(planar.size()));
5311 if (err == VK_SUCCESS) {
5312 const quint32 *depthPlane =
reinterpret_cast<
const quint32 *>(planar.constData());
5313 const quint8 *stencilPlane =
reinterpret_cast<
const quint8 *>(planar.constData() + depthPlaneByteSize);
5314 char *dst = readback.result->data.data();
5315 if (readback.format == QRhiTexture::D32FS8) {
5318 for (quint32 px = 0; px < pixelCount; ++px) {
5319 const quint32 stencilWord = stencilPlane[px];
5320 memcpy(dst + px * 8, &depthPlane[px],
sizeof(quint32));
5321 memcpy(dst + px * 8 + 4, &stencilWord,
sizeof(quint32));
5326 for (quint32 px = 0; px < pixelCount; ++px) {
5329 const quint32 combined = ((depthPlane[px] & 0x00FFFFFFu) << 8) | stencilPlane[px];
5330 memcpy(dst + px * 4, &combined,
sizeof(quint32));
5334 qWarning(
"Failed to copy texture readback buffer of size %lld: %d",
5335 qint64(planar.size()), err);
5336 readback.result->data.clear();
5339 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5340 toVmaAllocation(readback.stagingAlloc),
5341 0, readback.result->data.data(), readback.byteSize);
5342 if (err != VK_SUCCESS) {
5343 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
5344 readback.result->data.clear();
5345 }
else if (readback.format == QRhiTexture::D24) {
5350 char *p = readback.result->data.data();
5351 for (quint32 px = 0, count = readback.byteSize / 4; px < count; ++px)
5352 qToUnaligned((qFromUnaligned<quint32>(p + px * 4) & 0x00FFFFFFu) << 8, p + px * 4);
5356 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5358 if (readback.result->completed)
5359 completedCallbacks.append(readback.result->completed);
5361 activeTextureReadbacks.remove(i);
5365 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
5367 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5368 readback.result->data.resizeForOverwrite(readback.byteSize);
5369 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5370 toVmaAllocation(readback.stagingAlloc),
5371 0, readback.result->data.data(), readback.byteSize);
5372 if (err != VK_SUCCESS) {
5373 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
5374 readback.result->data.clear();
5377 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5379 if (readback.result->completed)
5380 completedCallbacks.append(readback.result->completed);
5382 activeBufferReadbacks.remove(i);
5386 for (
const auto &f : completedCallbacks)
5391 VkSampleCountFlagBits mask;
5393} qvk_sampleCounts[] = {
5395 { VK_SAMPLE_COUNT_1_BIT, 1 },
5396 { VK_SAMPLE_COUNT_2_BIT, 2 },
5397 { VK_SAMPLE_COUNT_4_BIT, 4 },
5398 { VK_SAMPLE_COUNT_8_BIT, 8 },
5399 { VK_SAMPLE_COUNT_16_BIT, 16 },
5400 { VK_SAMPLE_COUNT_32_BIT, 32 },
5401 { VK_SAMPLE_COUNT_64_BIT, 64 }
5406 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
5407 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
5408 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
5409 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
5412 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5413 if ((color & qvk_sampleCount.mask)
5414 && (depth & qvk_sampleCount.mask)
5415 && (stencil & qvk_sampleCount.mask))
5417 result.append(qvk_sampleCount.count);
5426 const int s = effectiveSampleCount(sampleCount);
5428 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5429 if (qvk_sampleCount.count == s)
5430 return qvk_sampleCount.mask;
5433 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
5438 QList<QSize> result;
5439#ifdef VK_KHR_fragment_shading_rate
5440 sampleCount = qMax(1, sampleCount);
5441 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
5442 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5443 if (qvk_sampleCount.count == sampleCount) {
5444 mask = qvk_sampleCount.mask;
5448 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
5449 if (s.sampleCounts & mask)
5450 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
5453 Q_UNUSED(sampleCount);
5454 result.append(QSize(1, 1));
5461 cbD->passResTrackers.emplace_back();
5466 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5473 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5477 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5478 1, &cmd.args.copyBuffer.desc);
5481 df->vkCmdFillBuffer(cbD->cb, cmd.args.fillBuffer.dst, cmd.args.fillBuffer.offset,
5482 cmd.args.fillBuffer.size, cmd.args.fillBuffer.data);
5485 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5486 cmd.args.copyBufferToImage.dstLayout,
5487 uint32_t(cmd.args.copyBufferToImage.count),
5488 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5491 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5492 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5493 1, &cmd.args.copyImage.desc);
5496 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5497 cmd.args.copyImageToBuffer.dst,
5498 uint32_t(cmd.args.copyImageToBuffer.count),
5499 cbD->pools.bufferImageCopy.constData() + cmd.args.copyImageToBuffer.bufferImageCopyIndex);
5502 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5503 0, 0,
nullptr, 0,
nullptr,
5504 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5507 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5509 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5513 const auto &barrier = cmd.args.imageAndBufferBarrier;
5514 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5515 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5516 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5517 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5518 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5520 barrier.bufferCount, bufferBarrierData,
5521 barrier.imageCount, imageBarrierData);
5524 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5525 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5526 1, &cmd.args.blitImage.desc,
5527 cmd.args.blitImage.filter);
5530 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5531 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5532 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5533 : VK_SUBPASS_CONTENTS_INLINE);
5536 VkMemoryBarrier barrier = {};
5537 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5538 barrier.pNext =
nullptr;
5539 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5540 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5541 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5547 df->vkCmdEndRenderPass(cbD->cb);
5550 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5554 const uint32_t *offsets =
nullptr;
5555 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5556 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5557 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5558 cmd.args.bindDescriptorSet.pipelineLayout,
5559 0, 1, &cmd.args.bindDescriptorSet.descSet,
5560 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5565 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5566 uint32_t(cmd.args.bindVertexBuffer.count),
5567 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5568 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5571 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5572 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5575 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5578 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5581 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5584 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5587 df->vkCmdPushConstants(cbD->cb,
5588 cmd.args.setPushConstants.layout,
5589 cmd.args.setPushConstants.stages,
5590 cmd.args.setPushConstants.offset,
5591 cmd.args.setPushConstants.size,
5592 cbD->pools.pushConstantData.constData() + cmd.args.setPushConstants.dataIndex);
5595 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5596 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5599 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5600 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5601 cmd.args.drawIndexed.firstInstance);
5604 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5605 cmd.args.drawIndirect.indirectBufferOffset,
5606 cmd.args.drawIndirect.drawCount,
5607 cmd.args.drawIndirect.stride);
5610 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5611 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5612 cmd.args.drawIndexedIndirect.drawCount,
5613 cmd.args.drawIndexedIndirect.stride);
5615#ifdef VK_VERSION_1_2
5616 case QVkCommandBuffer::Command::DrawIndirectCount:
5617 vkCmdDrawIndirectCount(cbD->cb,
5618 cmd.args.drawIndirectCount.indirectBuffer,
5619 cmd.args.drawIndirectCount.indirectBufferOffset,
5620 cmd.args.drawIndirectCount.countBuffer,
5621 cmd.args.drawIndirectCount.countBufferOffset,
5622 cmd.args.drawIndirectCount.maxDrawCount,
5623 cmd.args.drawIndirectCount.stride);
5625 case QVkCommandBuffer::Command::DrawIndexedIndirectCount:
5626 vkCmdDrawIndexedIndirectCount(cbD->cb,
5627 cmd.args.drawIndexedIndirectCount.indirectBuffer,
5628 cmd.args.drawIndexedIndirectCount.indirectBufferOffset,
5629 cmd.args.drawIndexedIndirectCount.countBuffer,
5630 cmd.args.drawIndexedIndirectCount.countBufferOffset,
5631 cmd.args.drawIndexedIndirectCount.maxDrawCount,
5632 cmd.args.drawIndexedIndirectCount.stride);
5636#ifdef VK_EXT_debug_utils
5637 cmd.args.debugMarkerBegin.label.pLabelName =
5638 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5639 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5643#ifdef VK_EXT_debug_utils
5644 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5648#ifdef VK_EXT_debug_utils
5649 cmd.args.debugMarkerInsert.label.pLabelName =
5650 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5651 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5658 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5661 df->vkCmdDispatchIndirect(cbD->cb,
5662 cmd.args.dispatchIndirect.indirectBuffer,
5663 cmd.args.dispatchIndirect.indirectBufferOffset);
5666 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5670#ifdef VK_KHR_fragment_shading_rate
5671 VkFragmentShadingRateCombinerOpKHR op[2] = {
5672 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5673 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5675 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5676 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5689 case QRhiPassResourceTracker::BufIndirectDraw:
5690 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5691 case QRhiPassResourceTracker::BufVertexInput:
5692 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5693 case QRhiPassResourceTracker::BufIndexRead:
5694 return VK_ACCESS_INDEX_READ_BIT;
5695 case QRhiPassResourceTracker::BufUniformRead:
5696 return VK_ACCESS_UNIFORM_READ_BIT;
5697 case QRhiPassResourceTracker::BufStorageLoad:
5698 return VK_ACCESS_SHADER_READ_BIT;
5699 case QRhiPassResourceTracker::BufStorageStore:
5700 return VK_ACCESS_SHADER_WRITE_BIT;
5701 case QRhiPassResourceTracker::BufStorageLoadStore:
5702 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5713 case QRhiPassResourceTracker::BufIndirectDrawStage:
5714 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5715 case QRhiPassResourceTracker::BufVertexInputStage:
5716 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5717 case QRhiPassResourceTracker::BufVertexStage:
5718 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5719 case QRhiPassResourceTracker::BufTCStage:
5720 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5721 case QRhiPassResourceTracker::BufTEStage:
5722 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5723 case QRhiPassResourceTracker::BufFragmentStage:
5724 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5725 case QRhiPassResourceTracker::BufComputeStage:
5726 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5727 case QRhiPassResourceTracker::BufGeometryStage:
5728 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5739 u.access = VkAccessFlags(usage
.access);
5740 u.stage = VkPipelineStageFlags(usage
.stage);
5747 case QRhiPassResourceTracker::TexSample:
5748 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5749 case QRhiPassResourceTracker::TexColorOutput:
5750 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5751 case QRhiPassResourceTracker::TexDepthOutput:
5752 case QRhiPassResourceTracker::TexDepthResolveOutput:
5753 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5754 case QRhiPassResourceTracker::TexStorageLoad:
5755 case QRhiPassResourceTracker::TexStorageStore:
5756 case QRhiPassResourceTracker::TexStorageLoadStore:
5757 return VK_IMAGE_LAYOUT_GENERAL;
5758 case QRhiPassResourceTracker::TexShadingRate:
5759#ifdef VK_KHR_fragment_shading_rate
5760 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5762 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5768 return VK_IMAGE_LAYOUT_GENERAL;
5774 case QRhiPassResourceTracker::TexSample:
5775 return VK_ACCESS_SHADER_READ_BIT;
5776 case QRhiPassResourceTracker::TexColorOutput:
5777 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5778 case QRhiPassResourceTracker::TexDepthOutput:
5779 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5780 case QRhiPassResourceTracker::TexDepthResolveOutput:
5783 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5784 case QRhiPassResourceTracker::TexStorageLoad:
5785 return VK_ACCESS_SHADER_READ_BIT;
5786 case QRhiPassResourceTracker::TexStorageStore:
5787 return VK_ACCESS_SHADER_WRITE_BIT;
5788 case QRhiPassResourceTracker::TexStorageLoadStore:
5789 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5802 case QRhiPassResourceTracker::TexVertexStage:
5803 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5804 case QRhiPassResourceTracker::TexTCStage:
5805 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5806 case QRhiPassResourceTracker::TexTEStage:
5807 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5808 case QRhiPassResourceTracker::TexFragmentStage:
5809 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5810 case QRhiPassResourceTracker::TexColorOutputStage:
5811 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5812 case QRhiPassResourceTracker::TexDepthOutputStage:
5813 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5814 case QRhiPassResourceTracker::TexComputeStage:
5815 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5816 case QRhiPassResourceTracker::TexGeometryStage:
5817 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5828 u.layout = VkImageLayout(usage
.layout);
5829 u.access = VkAccessFlags(usage
.access);
5830 u.stage = VkPipelineStageFlags(usage
.stage);
5841 const VkAccessFlags newAccess = toVkAccess(access);
5842 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5843 if (u.access == newAccess && u.stage == newStage) {
5844 if (!accessIsWrite(newAccess))
5848 u.access = newAccess;
5858 const VkAccessFlags newAccess = toVkAccess(access);
5859 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5860 const VkImageLayout newLayout = toVkLayout(access);
5861 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5862 if (!accessIsWrite(newAccess))
5866 u.layout = newLayout;
5867 u.access = newAccess;
5876 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5877 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5878 VkAccessFlags access = toVkAccess(trackedB.access);
5879 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5880 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5883 if (s.access == access && s.stage == stage) {
5884 if (!accessIsWrite(access))
5887 VkBufferMemoryBarrier bufMemBarrier = {};
5888 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5889 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5890 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5891 bufMemBarrier.srcAccessMask = s.access;
5892 bufMemBarrier.dstAccessMask = access;
5893 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5894 bufMemBarrier.size = VK_WHOLE_SIZE;
5895 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5901 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5902 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5903 VkImageLayout layout = toVkLayout(trackedT.access);
5904 VkAccessFlags access = toVkAccess(trackedT.access);
5905 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5906 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5907 if (s.access == access && s.stage == stage && s.layout == layout) {
5908 if (!accessIsWrite(access))
5911 VkImageMemoryBarrier barrier = {};
5912 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5913 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5914 barrier.subresourceRange.baseMipLevel = 0;
5915 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5916 barrier.subresourceRange.baseArrayLayer = 0;
5917 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5918 barrier.oldLayout = s.layout;
5919 barrier.newLayout = layout;
5920 barrier.srcAccessMask = s.access;
5921 barrier.dstAccessMask = access;
5922 barrier.image = texD->image;
5923 VkPipelineStageFlags srcStage = s.stage;
5926 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5927 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5936 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5937 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5938 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5940 qWarning(
"Physical device surface queries not available");
5944 return new QVkSwapChain(
this);
5947QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5949 return new QVkBuffer(
this, type, usage, size);
5954 return int(ubufAlign);
5977 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
5978 0.0f, -1.0f, 0.0f, 0.0f,
5979 0.0f, 0.0f, 0.5f, 0.5f,
5980 0.0f, 0.0f, 0.0f, 1.0f);
5989 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5990 if (!physDevFeatures.textureCompressionBC)
5994 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5995 if (!physDevFeatures.textureCompressionETC2)
5999 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
6000 if (!physDevFeatures.textureCompressionASTC_LDR)
6004 VkFormat vkformat = toVkTextureFormat(format, flags);
6005 VkFormatProperties props;
6006 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
6007 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
6013 case QRhi::MultisampleTexture:
6015 case QRhi::MultisampleRenderBuffer:
6017 case QRhi::DebugMarkers:
6018 return caps.debugUtils;
6019 case QRhi::Timestamps:
6020 return timestampValidBits != 0;
6021 case QRhi::Instancing:
6023 case QRhi::CustomInstanceStepRate:
6024 return caps.vertexAttribDivisor;
6025 case QRhi::PrimitiveRestart:
6027 case QRhi::NonDynamicUniformBuffers:
6029 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
6031 case QRhi::NPOTTextureRepeat:
6033 case QRhi::RedOrAlpha8IsRed:
6035 case QRhi::ElementIndexUint:
6038 return caps.compute;
6039 case QRhi::FragmentStoresAndAtomics:
6040 return physDevFeatures.fragmentStoresAndAtomics;
6041 case QRhi::WideLines:
6042 return caps.wideLines;
6043 case QRhi::VertexShaderPointSize:
6045 case QRhi::BaseVertex:
6047 case QRhi::BaseInstance:
6049 case QRhi::TriangleFanTopology:
6051 case QRhi::ReadBackNonUniformBuffer:
6053 case QRhi::ReadBackNonBaseMipLevel:
6055 case QRhi::TexelFetch:
6057 case QRhi::RenderToNonBaseMipLevel:
6059 case QRhi::IntAttributes:
6061 case QRhi::ScreenSpaceDerivatives:
6063 case QRhi::ReadBackAnyTextureFormat:
6065 case QRhi::PipelineCacheDataLoadSave:
6067 case QRhi::ImageDataStride:
6069 case QRhi::RenderBufferImport:
6071 case QRhi::ThreeDimensionalTextures:
6073 case QRhi::RenderTo3DTextureSlice:
6074 return caps.texture3DSliceAs2D;
6075 case QRhi::TextureArrays:
6077 case QRhi::Tessellation:
6078 return caps.tessellation;
6079 case QRhi::GeometryShader:
6080 return caps.geometryShader;
6081 case QRhi::TextureArrayRange:
6083 case QRhi::NonFillPolygonMode:
6084 return caps.nonFillPolygonMode;
6085 case QRhi::OneDimensionalTextures:
6087 case QRhi::OneDimensionalTextureMipmaps:
6089 case QRhi::HalfAttributes:
6091 case QRhi::RenderToOneDimensionalTexture:
6093 case QRhi::ThreeDimensionalTextureMipmaps:
6095 case QRhi::MultiView:
6096 return caps.multiView;
6097 case QRhi::TextureViewFormat:
6099 case QRhi::ResolveDepthStencil:
6100 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
6101 case QRhi::VariableRateShading:
6102 return caps.renderPass2KHR && caps.perDrawShadingRate;
6103 case QRhi::VariableRateShadingMap:
6104 case QRhi::VariableRateShadingMapWithTexture:
6105 return caps.renderPass2KHR && caps.imageBasedShadingRate;
6106 case QRhi::PerRenderTargetBlending:
6107 case QRhi::SampleVariables:
6109 case QRhi::InstanceIndexIncludesBaseInstance:
6111 case QRhi::DepthClamp:
6112 return caps.depthClamp;
6113 case QRhi::DrawIndirect:
6115 case QRhi::DrawIndirectMulti:
6116 return caps.drawIndirectMulti;
6117 case QRhi::ShaderDrawParameters:
6118 return caps.shaderDrawParameters;
6119 case QRhi::DispatchIndirect:
6121 case QRhi::PushConstants:
6123 case QRhi::DrawIndirectCount:
6124 return caps.drawIndirectCount;
6125 case QRhi::BufferToBufferCopy:
6127 case QRhi::StaticBuffersOnGpuTimeline:
6130 Q_UNREACHABLE_RETURN(
false);
6137 case QRhi::TextureSizeMin:
6139 case QRhi::TextureSizeMax:
6140 return int(physDevProperties.limits.maxImageDimension2D);
6141 case QRhi::MaxColorAttachments:
6142 return int(physDevProperties.limits.maxColorAttachments);
6143 case QRhi::FramesInFlight:
6145 case QRhi::MaxAsyncReadbackFrames:
6147 case QRhi::MaxThreadGroupsPerDimension:
6148 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
6149 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
6150 physDevProperties.limits.maxComputeWorkGroupCount[2])));
6151 case QRhi::MaxThreadsPerThreadGroup:
6152 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
6153 case QRhi::MaxThreadGroupX:
6154 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
6155 case QRhi::MaxThreadGroupY:
6156 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
6157 case QRhi::MaxThreadGroupZ:
6158 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
6159 case QRhi::TextureArraySizeMax:
6160 return int(physDevProperties.limits.maxImageArrayLayers);
6161 case QRhi::MaxUniformBufferRange:
6162 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
6163 case QRhi::MaxVertexInputs:
6164 return physDevProperties.limits.maxVertexInputAttributes;
6165 case QRhi::MaxVertexOutputs:
6166 return physDevProperties.limits.maxVertexOutputComponents / 4;
6167 case QRhi::MaxPushConstantsSize:
6168 return int(physDevProperties.limits.maxPushConstantsSize);
6169 case QRhi::MaxVertexStorageBuffers:
6170 case QRhi::MaxFragmentStorageBuffers:
6171 return int(physDevProperties.limits.maxPerStageDescriptorStorageBuffers);
6172 case QRhi::ShadingRateImageTileSize:
6173 return caps.imageBasedShadingRateTileSize;
6175 Q_UNREACHABLE_RETURN(0);
6181 return &nativeHandlesStruct;
6186 return driverInfoStruct;
6192 result.totalPipelineCreationTime = totalPipelineCreationTime();
6194 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
6195 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
6197 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
6198 for (uint32_t i = 0; i < count; ++i) {
6199 const VmaStatistics &stats(budgets[i].statistics);
6200 result.blockCount += stats.blockCount;
6201 result.allocCount += stats.allocationCount;
6202 result.usedBytes += stats.allocationBytes;
6203 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
6217 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
6221 waitSemaphoresForQueueSubmit.clear();
6222 if (sp->waitSemaphoreCount)
6223 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
6225 signalSemaphoresForQueueSubmit.clear();
6226 if (sp->signalSemaphoreCount)
6227 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
6229 waitSemaphoresForPresent.clear();
6230 if (sp->presentWaitSemaphoreCount)
6231 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
6261 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
6264 size_t dataSize = 0;
6265 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
6266 if (err != VK_SUCCESS) {
6267 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
6268 return QByteArray();
6271 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6272 data.resize(dataOffset + dataSize);
6273 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
6274 if (err != VK_SUCCESS) {
6275 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
6276 return QByteArray();
6280 header.rhiId = pipelineCacheRhiId();
6281 header.arch = quint32(
sizeof(
void*));
6282 header.driverVersion = physDevProperties.driverVersion;
6283 header.vendorId = physDevProperties.vendorID;
6284 header.deviceId = physDevProperties.deviceID;
6285 header.dataSize = quint32(dataSize);
6286 header.uuidSize = VK_UUID_SIZE;
6287 header.reserved = 0;
6288 memcpy(data.data(), &header, headerSize);
6289 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
6300 if (data.size() < qsizetype(headerSize)) {
6301 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
6305 memcpy(&header, data.constData(), headerSize);
6307 const quint32 rhiId = pipelineCacheRhiId();
6308 if (header.rhiId != rhiId) {
6309 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
6310 rhiId, header.rhiId);
6313 const quint32 arch = quint32(
sizeof(
void*));
6314 if (header.arch != arch) {
6315 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
6319 if (header.driverVersion != physDevProperties.driverVersion) {
6320 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
6321 physDevProperties.driverVersion, header.driverVersion);
6324 if (header.vendorId != physDevProperties.vendorID) {
6325 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
6326 physDevProperties.vendorID, header.vendorId);
6329 if (header.deviceId != physDevProperties.deviceID) {
6330 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
6331 physDevProperties.deviceID, header.deviceId);
6334 if (header.uuidSize != VK_UUID_SIZE) {
6335 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
6336 quint32(VK_UUID_SIZE), header.uuidSize);
6340 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
6341 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
6344 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
6345 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
6349 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6350 if (quint64(data.size()) < quint64(dataOffset) + header.dataSize) {
6351 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
6355 if (pipelineCache) {
6356 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
6357 pipelineCache = VK_NULL_HANDLE;
6360 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
6361 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
6362 int(header.dataSize));
6364 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
6368QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
6369 int sampleCount, QRhiRenderBuffer::Flags flags,
6370 QRhiTexture::Format backingFormatHint)
6372 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
6376 const QSize &pixelSize,
int depth,
int arraySize,
6377 int sampleCount, QRhiTexture::Flags flags)
6379 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
6383 QRhiSampler::Filter mipmapMode,
6384 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
6386 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
6391 return new QVkShadingRateMap(
this);
6395 QRhiTextureRenderTarget::Flags flags)
6402 return new QVkGraphicsPipeline(
this);
6407 return new QVkComputePipeline(
this);
6412 return new QVkShaderResourceBindings(
this);
6418 Q_ASSERT(psD->pipeline);
6424 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
6428 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
6429 cmd.args.bindPipeline.pipeline = psD->pipeline;
6432 cbD->currentGraphicsPipeline = ps;
6433 cbD->currentComputePipeline =
nullptr;
6443 if (psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef)) {
6444 if (!cbD->stencilRefValid)
6445 recordStencilRef(cbD, cbD->currentStencilRef);
6455 int dynamicOffsetCount,
6456 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
6466 srb = gfxPsD->m_shaderResourceBindings;
6468 srb = compPsD->m_shaderResourceBindings;
6472 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
6473 bool rewriteDescSet =
false;
6474 bool addWriteBarrier =
false;
6475 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
6476 VkPipelineStageFlags writeBarrierDstStageMask = 0;
6480 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
6481 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
6483 switch (b->type()) {
6484 case QRhiShaderResourceBinding::UniformBuffer:
6487 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
6488 sanityCheckResourceOwnership(bufD);
6490 if (bufD->m_type == QRhiBuffer::Dynamic)
6494 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6496 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
6502 if (bufD
->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
6503 rewriteDescSet =
true;
6504 bd.ubuf.id = bufD->m_id;
6509 case QRhiShaderResourceBinding::SampledTexture:
6510 case QRhiShaderResourceBinding::Texture:
6511 case QRhiShaderResourceBinding::Sampler:
6513 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex();
6514 if (bd.stex.d.size() != data->count()) {
6515 bd.stex.d.resize(data->count());
6516 rewriteDescSet =
true;
6518 for (
int elem = 0; elem < data->count(); ++elem) {
6524 Q_ASSERT(texD || samplerD);
6525 sanityCheckResourceOwnership(texD);
6526 sanityCheckResourceOwnership(samplerD);
6535 const quint64 texId = texD ? texD->m_id : 0;
6537 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6538 const uint samplerGen = samplerD ? samplerD
->generation : 0;
6539 if (texGen != bd.stex.d[elem].texGeneration
6540 || texId != bd.stex.d[elem].texId
6541 || samplerGen != bd.stex.d[elem].samplerGeneration
6542 || samplerId != bd.stex.d[elem].samplerId)
6544 rewriteDescSet =
true;
6545 bd.stex.d[elem].texId = texId;
6546 bd.stex.d[elem].texGeneration = texGen;
6547 bd.stex.d[elem].samplerId = samplerId;
6548 bd.stex.d[elem].samplerGeneration = samplerGen;
6553 case QRhiShaderResourceBinding::ImageLoad:
6554 case QRhiShaderResourceBinding::ImageStore:
6555 case QRhiShaderResourceBinding::ImageLoadStore:
6558 sanityCheckResourceOwnership(texD);
6559 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6562 if (b->type() == QRhiShaderResourceBinding::ImageLoad)
6564 else if (b->type() == QRhiShaderResourceBinding::ImageStore)
6569 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6570 const auto prevAccess = passResTracker
.textures().find(texD);
6571 if (prevAccess != passResTracker
.textures().end()) {
6575 addWriteBarrier =
true;
6576 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6577 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6585 if (texD
->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6586 rewriteDescSet =
true;
6587 bd.simage.id = texD->m_id;
6592 case QRhiShaderResourceBinding::BufferLoad:
6593 case QRhiShaderResourceBinding::BufferStore:
6594 case QRhiShaderResourceBinding::BufferLoadStore:
6597 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6598 sanityCheckResourceOwnership(bufD);
6600 if (bufD->m_type == QRhiBuffer::Dynamic)
6605 if (b->type() == QRhiShaderResourceBinding::BufferLoad)
6607 else if (b->type() == QRhiShaderResourceBinding::BufferStore)
6612 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6613 const auto prevAccess = passResTracker
.buffers().find(bufD);
6614 if (prevAccess != passResTracker
.buffers().end()) {
6618 addWriteBarrier =
true;
6619 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6620 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6623 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6627 if (bufD
->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6628 rewriteDescSet =
true;
6629 bd.sbuf.id = bufD->m_id;
6640 if (addWriteBarrier) {
6641 VkDependencyFlags dependencyFlags = cbD->recordingPass == QVkCommandBuffer::RenderPass ? VK_DEPENDENCY_BY_REGION_BIT : 0;
6642#ifdef VK_VERSION_1_1
6643 auto *rpd = cbD->currentTarget ?
static_cast<QVkRenderPassDescriptor*>(cbD->currentTarget->renderPassDescriptor()) :
nullptr;
6644 if (rpd && rpd->multiViewCount >= 2)
6645 dependencyFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
6648 VkMemoryBarrier barrier = {};
6649 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6650 barrier.pNext =
nullptr;
6651 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6652 barrier.srcAccessMask = barrier.dstAccessMask;
6653 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, dependencyFlags,
6660 cmd.args.memoryBarrier.dependencyFlags = dependencyFlags;
6661 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6662 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6663 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6664 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6670 updateShaderResourceBindings(srb);
6674 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6675 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6677 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6680 QVarLengthArray<uint32_t, 4> dynOfs;
6685 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6686 uint32_t offset = 0;
6687 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6688 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6689 if (bindingOffsetPair.first == bindingNumber) {
6690 offset = bindingOffsetPair.second;
6694 dynOfs.append(offset);
6698 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6699 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6700 gfxPsD ? gfxPsD->layout : compPsD->layout,
6701 0, 1, &srbD->descSets[currentFrameSlot],
6702 uint32_t(dynOfs.size()),
6703 dynOfs.size() ? dynOfs.constData() :
nullptr);
6707 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6708 : VK_PIPELINE_BIND_POINT_COMPUTE;
6709 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6710 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6711 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6712 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6713 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6717 cbD->currentGraphicsSrb = srb;
6718 cbD->currentComputeSrb =
nullptr;
6720 cbD->currentGraphicsSrb =
nullptr;
6721 cbD->currentComputeSrb = srb;
6731 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6732 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6738 bool needsBindVBuf =
false;
6739 for (
int i = 0; i < bindingCount; ++i) {
6740 const int inputSlot = startBinding + i;
6742 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6744 if (bufD->m_type == QRhiBuffer::Dynamic)
6747 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6748 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6749 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6751 needsBindVBuf =
true;
6752 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6753 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6757 if (needsBindVBuf) {
6758 QVarLengthArray<VkBuffer, 4> bufs;
6759 QVarLengthArray<VkDeviceSize, 4> ofs;
6760 for (
int i = 0; i < bindingCount; ++i) {
6762 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6763 bufs.append(bufD->buffers[slot]);
6764 ofs.append(bindings[i].second);
6771 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6772 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6776 cmd.args.bindVertexBuffer.startBinding = startBinding;
6777 cmd.args.bindVertexBuffer.count = bufs.size();
6778 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6779 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6780 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6781 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6787 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6789 if (ibufD->m_type == QRhiBuffer::Dynamic)
6792 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6793 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6794 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6795 : VK_INDEX_TYPE_UINT32;
6797 if (cbD->currentIndexBuffer != vkindexbuf
6798 || cbD->currentIndexOffset != indexOffset
6799 || cbD->currentIndexFormat != type)
6801 cbD->currentIndexBuffer = vkindexbuf;
6802 cbD->currentIndexOffset = indexOffset;
6803 cbD->currentIndexFormat = type;
6806 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6810 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6811 cmd.args.bindIndexBuffer.ofs = indexOffset;
6812 cmd.args.bindIndexBuffer.type = type;
6826 const QSize outputSize = cbD->currentTarget->pixelSize();
6827 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6828 float x = 0, y = 0, w = 0, h = 0;
6830 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6833 w = outputSize.width();
6834 h = outputSize.height();
6837 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6841 VkRect2D *s = &cmd.args.setScissor.scissor;
6842 s->offset.x = int32_t(x);
6843 s->offset.y = int32_t(y);
6844 s->extent.width = uint32_t(w);
6845 s->extent.height = uint32_t(h);
6848 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6849 cbD->commands.unget();
6859 const QSize outputSize = cbD->currentTarget->pixelSize();
6863 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6867 VkViewport *vp = &cmd.args.setViewport.viewport;
6872 vp->minDepth = viewport.minDepth();
6873 vp->maxDepth = viewport.maxDepth();
6876 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6877 cbD->commands.unget();
6882 cbD->currentViewport = viewport;
6883 if (cbD->currentGraphicsPipeline
6884 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6894 Q_ASSERT(!cbD->currentGraphicsPipeline
6896 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6897 const QSize outputSize = cbD->currentTarget->pixelSize();
6901 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6905 VkRect2D *s = &cmd.args.setScissor.scissor;
6908 s->extent.width = uint32_t(w);
6909 s->extent.height = uint32_t(h);
6912 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6913 cbD->commands.unget();
6927 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6928 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6932 cmd.args.setBlendConstants.c[0] = c.redF();
6933 cmd.args.setBlendConstants.c[1] = c.greenF();
6934 cmd.args.setBlendConstants.c[2] = c.blueF();
6935 cmd.args.setBlendConstants.c[3] = c.alphaF();
6942 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6946 cmd.args.setStencilRef.ref = refValue;
6956 recordStencilRef(cbD, refValue);
6957 cbD->currentStencilRef = refValue;
6965 VkPipelineLayout layout = VK_NULL_HANDLE;
6966 VkShaderStageFlags stages = 0;
6969 layout = psD->layout;
6970 stages = psD->pushConstantStages;
6974 layout = psD->layout;
6975 stages = psD->pushConstantStages;
6978 if (!layout || !stages) {
6979 qWarning(
"No pipeline with a push constant block is active; setPushConstants ignored");
6984 df->vkCmdPushConstants(cbD->activeSecondaryCbStack.last(), layout, stages, offset, size, data);
6986 const int dataIndex = cbD->pools.pushConstantData.size();
6987 cbD->pools.pushConstantData.append(
static_cast<
const char *>(data), size);
6990 cmd.args.setPushConstants.layout = layout;
6991 cmd.args.setPushConstants.stages = stages;
6992 cmd.args.setPushConstants.offset = offset;
6993 cmd.args.setPushConstants.size = size;
6994 cmd.args.setPushConstants.dataIndex = dataIndex;
7000#ifdef VK_KHR_fragment_shading_rate
7001 if (!vkCmdSetFragmentShadingRateKHR)
7004 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7005 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
7006 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
7008 VkFragmentShadingRateCombinerOpKHR ops[2] = {
7009 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
7010 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
7012 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
7013 if (cbD->passUsesSecondaryCb) {
7014 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
7016 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7017 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
7018 cmd.args.setShadingRate.w = size.width;
7019 cmd.args.setShadingRate.h = size.height;
7021 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
7022 cbD->hasShadingRateSet =
true;
7025 Q_UNUSED(coarsePixelSize);
7030 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
7036 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
7040 cmd.args.draw.vertexCount = vertexCount;
7041 cmd.args.draw.instanceCount = instanceCount;
7042 cmd.args.draw.firstVertex = firstVertex;
7043 cmd.args.draw.firstInstance = firstInstance;
7048 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
7054 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
7055 firstIndex, vertexOffset, firstInstance);
7059 cmd.args.drawIndexed.indexCount = indexCount;
7060 cmd.args.drawIndexed.instanceCount = instanceCount;
7061 cmd.args.drawIndexed.firstIndex = firstIndex;
7062 cmd.args.drawIndexed.vertexOffset = vertexOffset;
7063 cmd.args.drawIndexed.firstInstance = firstInstance;
7068 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
7076 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
7078 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
7082 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
7085 if (caps.drawIndirectMulti) {
7086 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
7087 indirectBufVk, indirectBufferOffset,
7090 VkDeviceSize offset = indirectBufferOffset;
7091 for (quint32 i = 0; i < drawCount; ++i) {
7092 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
7093 indirectBufVk, offset,
7099 if (caps.drawIndirectMulti) {
7102 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
7103 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
7104 cmd.args.drawIndirect.drawCount = drawCount;
7105 cmd.args.drawIndirect.stride = stride;
7107 VkDeviceSize offset = indirectBufferOffset;
7108 for (quint32 i = 0; i < drawCount; ++i) {
7111 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
7112 cmd.args.drawIndirect.indirectBufferOffset = offset;
7113 cmd.args.drawIndirect.drawCount = 1;
7114 cmd.args.drawIndirect.stride = stride;
7122 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
7130 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
7132 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
7136 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
7139 if (caps.drawIndirectMulti) {
7140 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
7141 indirectBufVk, indirectBufferOffset,
7144 VkDeviceSize offset = indirectBufferOffset;
7145 for (quint32 i = 0; i < drawCount; ++i) {
7146 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
7147 indirectBufVk, offset,
7153 if (caps.drawIndirectMulti) {
7156 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
7157 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
7158 cmd.args.drawIndexedIndirect.drawCount = drawCount;
7159 cmd.args.drawIndexedIndirect.stride = stride;
7161 VkDeviceSize offset = indirectBufferOffset;
7162 for (quint32 i = 0; i < drawCount; ++i) {
7165 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
7166 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
7167 cmd.args.drawIndexedIndirect.drawCount = 1;
7168 cmd.args.drawIndexedIndirect.stride = stride;
7177#ifdef VK_EXT_debug_utils
7178 if (!debugMarkers || !caps.debugUtils)
7181 VkDebugUtilsLabelEXT label = {};
7182 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
7184 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7185 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7186 label.pLabelName = name.constData();
7187 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
7189 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7190 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
7191 cmd.args.debugMarkerBegin.label = label;
7192 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
7193 cbD->pools.debugMarkerData.append(name);
7203#ifdef VK_EXT_debug_utils
7204 if (!debugMarkers || !caps.debugUtils)
7207 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7208 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7209 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
7211 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7212 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
7221#ifdef VK_EXT_debug_utils
7222 if (!debugMarkers || !caps.debugUtils)
7225 VkDebugUtilsLabelEXT label = {};
7226 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
7228 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7229 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7230 label.pLabelName = msg.constData();
7231 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
7233 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7234 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
7235 cmd.args.debugMarkerInsert.label = label;
7236 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
7237 cbD->pools.debugMarkerData.append(msg);
7247 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
7252 Q_ASSERT(cbD->currentTarget);
7255 switch (cbD->currentTarget->resourceType()) {
7256 case QRhiResource::SwapChainRenderTarget:
7259 case QRhiResource::TextureRenderTarget:
7291 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
7292 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
7296 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
7297 cbD->activeSecondaryCbStack.removeLast();
7298 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
7300 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
7302 cbD->activeSecondaryCbStack.append(extCb);
7314 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
7315 cbD->activeSecondaryCbStack.removeLast();
7316 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
7317 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
7331 if (!debugMarkers || name.isEmpty())
7334 QByteArray decoratedName = name;
7336 decoratedName +=
'/';
7337 decoratedName += QByteArray::number(slot);
7339 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
7344#ifdef VK_EXT_debug_utils
7345 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
7348 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
7349 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
7350 nameInfo.objectType = type;
7351 nameInfo.objectHandle = object;
7352 QByteArray decoratedName = name;
7354 decoratedName +=
'/';
7355 decoratedName += QByteArray::number(slot);
7357 nameInfo.pObjectName = decoratedName.constData();
7358 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
7370 if (usage.testFlag(QRhiBuffer::VertexBuffer))
7371 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
7372 if (usage.testFlag(QRhiBuffer::IndexBuffer))
7373 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
7374 if (usage.testFlag(QRhiBuffer::UniformBuffer))
7375 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
7376 if (usage.testFlag(QRhiBuffer::StorageBuffer))
7377 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
7378 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
7379 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
7380 return VkBufferUsageFlagBits(u);
7386 case QRhiSampler::Nearest:
7387 return VK_FILTER_NEAREST;
7388 case QRhiSampler::Linear:
7389 return VK_FILTER_LINEAR;
7391 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
7398 case QRhiSampler::None:
7399 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7400 case QRhiSampler::Nearest:
7401 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7402 case QRhiSampler::Linear:
7403 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
7405 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
7412 case QRhiSampler::Repeat:
7413 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
7414 case QRhiSampler::ClampToEdge:
7415 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
7416 case QRhiSampler::Mirror:
7417 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
7419 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
7426 case QRhiShaderStage::Vertex:
7427 return VK_SHADER_STAGE_VERTEX_BIT;
7428 case QRhiShaderStage::TessellationControl:
7429 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7430 case QRhiShaderStage::TessellationEvaluation:
7431 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7432 case QRhiShaderStage::Fragment:
7433 return VK_SHADER_STAGE_FRAGMENT_BIT;
7434 case QRhiShaderStage::Compute:
7435 return VK_SHADER_STAGE_COMPUTE_BIT;
7436 case QRhiShaderStage::Geometry:
7437 return VK_SHADER_STAGE_GEOMETRY_BIT;
7439 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
7446 case QRhiVertexInputAttribute::Float4:
7447 return VK_FORMAT_R32G32B32A32_SFLOAT;
7448 case QRhiVertexInputAttribute::Float3:
7449 return VK_FORMAT_R32G32B32_SFLOAT;
7450 case QRhiVertexInputAttribute::Float2:
7451 return VK_FORMAT_R32G32_SFLOAT;
7452 case QRhiVertexInputAttribute::Float:
7453 return VK_FORMAT_R32_SFLOAT;
7454 case QRhiVertexInputAttribute::UNormByte4:
7455 return VK_FORMAT_R8G8B8A8_UNORM;
7456 case QRhiVertexInputAttribute::UNormByte2:
7457 return VK_FORMAT_R8G8_UNORM;
7458 case QRhiVertexInputAttribute::UNormByte:
7459 return VK_FORMAT_R8_UNORM;
7460 case QRhiVertexInputAttribute::UInt4:
7461 return VK_FORMAT_R32G32B32A32_UINT;
7462 case QRhiVertexInputAttribute::UInt3:
7463 return VK_FORMAT_R32G32B32_UINT;
7464 case QRhiVertexInputAttribute::UInt2:
7465 return VK_FORMAT_R32G32_UINT;
7466 case QRhiVertexInputAttribute::UInt:
7467 return VK_FORMAT_R32_UINT;
7468 case QRhiVertexInputAttribute::SInt4:
7469 return VK_FORMAT_R32G32B32A32_SINT;
7470 case QRhiVertexInputAttribute::SInt3:
7471 return VK_FORMAT_R32G32B32_SINT;
7472 case QRhiVertexInputAttribute::SInt2:
7473 return VK_FORMAT_R32G32_SINT;
7474 case QRhiVertexInputAttribute::SInt:
7475 return VK_FORMAT_R32_SINT;
7476 case QRhiVertexInputAttribute::Half4:
7477 return VK_FORMAT_R16G16B16A16_SFLOAT;
7478 case QRhiVertexInputAttribute::Half3:
7479 return VK_FORMAT_R16G16B16_SFLOAT;
7480 case QRhiVertexInputAttribute::Half2:
7481 return VK_FORMAT_R16G16_SFLOAT;
7482 case QRhiVertexInputAttribute::Half:
7483 return VK_FORMAT_R16_SFLOAT;
7484 case QRhiVertexInputAttribute::UShort4:
7485 return VK_FORMAT_R16G16B16A16_UINT;
7486 case QRhiVertexInputAttribute::UShort3:
7487 return VK_FORMAT_R16G16B16_UINT;
7488 case QRhiVertexInputAttribute::UShort2:
7489 return VK_FORMAT_R16G16_UINT;
7490 case QRhiVertexInputAttribute::UShort:
7491 return VK_FORMAT_R16_UINT;
7492 case QRhiVertexInputAttribute::SShort4:
7493 return VK_FORMAT_R16G16B16A16_SINT;
7494 case QRhiVertexInputAttribute::SShort3:
7495 return VK_FORMAT_R16G16B16_SINT;
7496 case QRhiVertexInputAttribute::SShort2:
7497 return VK_FORMAT_R16G16_SINT;
7498 case QRhiVertexInputAttribute::SShort:
7499 return VK_FORMAT_R16_SINT;
7501 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
7508 case QRhiGraphicsPipeline::Triangles:
7509 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
7510 case QRhiGraphicsPipeline::TriangleStrip:
7511 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
7512 case QRhiGraphicsPipeline::TriangleFan:
7513 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
7514 case QRhiGraphicsPipeline::Lines:
7515 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
7516 case QRhiGraphicsPipeline::LineStrip:
7517 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7518 case QRhiGraphicsPipeline::Points:
7519 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
7520 case QRhiGraphicsPipeline::Patches:
7521 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7523 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
7530 case QRhiGraphicsPipeline::None:
7531 return VK_CULL_MODE_NONE;
7532 case QRhiGraphicsPipeline::Front:
7533 return VK_CULL_MODE_FRONT_BIT;
7534 case QRhiGraphicsPipeline::Back:
7535 return VK_CULL_MODE_BACK_BIT;
7537 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
7544 case QRhiGraphicsPipeline::CCW:
7545 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
7546 case QRhiGraphicsPipeline::CW:
7547 return VK_FRONT_FACE_CLOCKWISE;
7549 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
7556 if (c.testFlag(QRhiGraphicsPipeline::R))
7557 f |= VK_COLOR_COMPONENT_R_BIT;
7558 if (c.testFlag(QRhiGraphicsPipeline::G))
7559 f |= VK_COLOR_COMPONENT_G_BIT;
7560 if (c.testFlag(QRhiGraphicsPipeline::B))
7561 f |= VK_COLOR_COMPONENT_B_BIT;
7562 if (c.testFlag(QRhiGraphicsPipeline::A))
7563 f |= VK_COLOR_COMPONENT_A_BIT;
7564 return VkColorComponentFlags(f);
7570 case QRhiGraphicsPipeline::Zero:
7571 return VK_BLEND_FACTOR_ZERO;
7572 case QRhiGraphicsPipeline::One:
7573 return VK_BLEND_FACTOR_ONE;
7574 case QRhiGraphicsPipeline::SrcColor:
7575 return VK_BLEND_FACTOR_SRC_COLOR;
7576 case QRhiGraphicsPipeline::OneMinusSrcColor:
7577 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
7578 case QRhiGraphicsPipeline::DstColor:
7579 return VK_BLEND_FACTOR_DST_COLOR;
7580 case QRhiGraphicsPipeline::OneMinusDstColor:
7581 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
7582 case QRhiGraphicsPipeline::SrcAlpha:
7583 return VK_BLEND_FACTOR_SRC_ALPHA;
7584 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7585 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
7586 case QRhiGraphicsPipeline::DstAlpha:
7587 return VK_BLEND_FACTOR_DST_ALPHA;
7588 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7589 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7590 case QRhiGraphicsPipeline::ConstantColor:
7591 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7592 case QRhiGraphicsPipeline::OneMinusConstantColor:
7593 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7594 case QRhiGraphicsPipeline::ConstantAlpha:
7595 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7596 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7597 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7598 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7599 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7600 case QRhiGraphicsPipeline::Src1Color:
7601 return VK_BLEND_FACTOR_SRC1_COLOR;
7602 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7603 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7604 case QRhiGraphicsPipeline::Src1Alpha:
7605 return VK_BLEND_FACTOR_SRC1_ALPHA;
7606 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7607 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7609 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7616 case QRhiGraphicsPipeline::Add:
7617 return VK_BLEND_OP_ADD;
7618 case QRhiGraphicsPipeline::Subtract:
7619 return VK_BLEND_OP_SUBTRACT;
7620 case QRhiGraphicsPipeline::ReverseSubtract:
7621 return VK_BLEND_OP_REVERSE_SUBTRACT;
7622 case QRhiGraphicsPipeline::Min:
7623 return VK_BLEND_OP_MIN;
7624 case QRhiGraphicsPipeline::Max:
7625 return VK_BLEND_OP_MAX;
7627 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7634 case QRhiGraphicsPipeline::Never:
7635 return VK_COMPARE_OP_NEVER;
7636 case QRhiGraphicsPipeline::Less:
7637 return VK_COMPARE_OP_LESS;
7638 case QRhiGraphicsPipeline::Equal:
7639 return VK_COMPARE_OP_EQUAL;
7640 case QRhiGraphicsPipeline::LessOrEqual:
7641 return VK_COMPARE_OP_LESS_OR_EQUAL;
7642 case QRhiGraphicsPipeline::Greater:
7643 return VK_COMPARE_OP_GREATER;
7644 case QRhiGraphicsPipeline::NotEqual:
7645 return VK_COMPARE_OP_NOT_EQUAL;
7646 case QRhiGraphicsPipeline::GreaterOrEqual:
7647 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7648 case QRhiGraphicsPipeline::Always:
7649 return VK_COMPARE_OP_ALWAYS;
7651 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7658 case QRhiGraphicsPipeline::StencilZero:
7659 return VK_STENCIL_OP_ZERO;
7660 case QRhiGraphicsPipeline::Keep:
7661 return VK_STENCIL_OP_KEEP;
7662 case QRhiGraphicsPipeline::Replace:
7663 return VK_STENCIL_OP_REPLACE;
7664 case QRhiGraphicsPipeline::IncrementAndClamp:
7665 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7666 case QRhiGraphicsPipeline::DecrementAndClamp:
7667 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7668 case QRhiGraphicsPipeline::Invert:
7669 return VK_STENCIL_OP_INVERT;
7670 case QRhiGraphicsPipeline::IncrementAndWrap:
7671 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7672 case QRhiGraphicsPipeline::DecrementAndWrap:
7673 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7675 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7682 case QRhiGraphicsPipeline::Fill:
7683 return VK_POLYGON_MODE_FILL;
7684 case QRhiGraphicsPipeline::Line:
7685 return VK_POLYGON_MODE_LINE;
7687 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7693 dst->failOp = toVkStencilOp(src.failOp);
7694 dst->passOp = toVkStencilOp(src.passOp);
7695 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7696 dst->compareOp = toVkCompareOp(src.compareOp);
7701 switch (b->type()) {
7702 case QRhiShaderResourceBinding::UniformBuffer:
7703 return b->ubuf().hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7704 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7706 case QRhiShaderResourceBinding::SampledTexture:
7707 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7709 case QRhiShaderResourceBinding::Texture:
7710 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7712 case QRhiShaderResourceBinding::Sampler:
7713 return VK_DESCRIPTOR_TYPE_SAMPLER;
7715 case QRhiShaderResourceBinding::ImageLoad:
7716 case QRhiShaderResourceBinding::ImageStore:
7717 case QRhiShaderResourceBinding::ImageLoadStore:
7718 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7720 case QRhiShaderResourceBinding::BufferLoad:
7721 case QRhiShaderResourceBinding::BufferStore:
7722 case QRhiShaderResourceBinding::BufferLoadStore:
7723 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7726 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7733 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7734 s |= VK_SHADER_STAGE_VERTEX_BIT;
7735 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7736 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7737 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7738 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7739 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7740 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7741 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7742 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7743 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7744 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7745 return VkShaderStageFlags(s);
7751 case QRhiSampler::Never:
7752 return VK_COMPARE_OP_NEVER;
7753 case QRhiSampler::Less:
7754 return VK_COMPARE_OP_LESS;
7755 case QRhiSampler::Equal:
7756 return VK_COMPARE_OP_EQUAL;
7757 case QRhiSampler::LessOrEqual:
7758 return VK_COMPARE_OP_LESS_OR_EQUAL;
7759 case QRhiSampler::Greater:
7760 return VK_COMPARE_OP_GREATER;
7761 case QRhiSampler::NotEqual:
7762 return VK_COMPARE_OP_NOT_EQUAL;
7763 case QRhiSampler::GreaterOrEqual:
7764 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7765 case QRhiSampler::Always:
7766 return VK_COMPARE_OP_ALWAYS;
7768 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7776 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7796 e.buffer.buffers[i] = buffers[i];
7798 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7801 buffers[i] = VK_NULL_HANDLE;
7803 stagingBuffers[i] = VK_NULL_HANDLE;
7805 pendingDynamicUpdates[i].clear();
7813 rhiD->releaseQueue.append(e);
7814 rhiD->unregisterResource(
this);
7823 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7824 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7828 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7830 VkBufferCreateInfo bufferInfo = {};
7831 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7832 bufferInfo.size = nonZeroSize;
7833 bufferInfo.usage = toVkBufferUsage(m_usage);
7835 VmaAllocationCreateInfo allocInfo = {};
7837 if (m_type == Dynamic) {
7842 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7845 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7847 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7848 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7852 VkResult err = VK_SUCCESS;
7854 buffers[i] = VK_NULL_HANDLE;
7856 usageState[i].access = usageState[i].stage = 0;
7857 if (i == 0 || m_type == Dynamic) {
7858 VmaAllocation allocation;
7859 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7860 if (err != VK_SUCCESS)
7863 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7864 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7865 m_type == Dynamic ? i : -1);
7869 if (err != VK_SUCCESS) {
7870 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7871 rhiD->printExtraErrorInfo(err);
7877 rhiD->registerResource(
this);
7883 if (m_type == Dynamic) {
7889 b.objects[i] = &buffers[i];
7894 return { { &buffers[0] }, 1 };
7904 Q_ASSERT(m_type == Dynamic);
7906 Q_ASSERT(rhiD->inFrame);
7907 const int slot = rhiD->currentFrameSlot;
7909 VmaAllocation a = toVmaAllocation(allocations[slot]);
7910 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7911 if (err != VK_SUCCESS) {
7912 qWarning(
"Failed to map buffer: %d", err);
7915 return static_cast<
char *>(p);
7921 const int slot = rhiD->currentFrameSlot;
7922 VmaAllocation a = toVmaAllocation(allocations[slot]);
7923 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7924 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7928 int sampleCount, Flags flags,
7929 QRhiTexture::Format backingFormatHint)
7942 if (!memory && !backingTexture)
7949 e.renderBuffer.memory = memory;
7950 e.renderBuffer.image = image;
7951 e.renderBuffer.imageView = imageView;
7953 memory = VK_NULL_HANDLE;
7954 image = VK_NULL_HANDLE;
7955 imageView = VK_NULL_HANDLE;
7965 rhiD->releaseQueue.append(e);
7966 rhiD->unregisterResource(
this);
7972 if (memory || backingTexture)
7975 if (m_pixelSize.isEmpty())
7979 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7982 case QRhiRenderBuffer::Color:
7990 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7998 vkformat = backingTexture->vkformat;
8001 case QRhiRenderBuffer::DepthStencil:
8002 vkformat = rhiD->optimalDepthStencilFormat();
8003 if (!rhiD->createTransientImage(vkformat,
8005 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
8006 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
8015 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
8024 rhiD->registerResource(
this);
8030 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
8031 return m_backingFormatHint;
8033 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
8037 int arraySize,
int sampleCount, Flags flags)
8041 stagingBuffers[i] = VK_NULL_HANDLE;
8044 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
8045 perLevelImageViews[i] = VK_NULL_HANDLE;
8062 e.texture.image = owns ? image : VK_NULL_HANDLE;
8063 e.texture.imageView = imageView;
8067 e.texture.stagingBuffers[i] = stagingBuffers[i];
8070 stagingBuffers[i] = VK_NULL_HANDLE;
8074 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
8075 e.texture.extraImageViews[i] = perLevelImageViews[i];
8076 perLevelImageViews[i] = VK_NULL_HANDLE;
8079 image = VK_NULL_HANDLE;
8080 imageView = VK_NULL_HANDLE;
8085 rhiD->releaseQueue.append(e);
8086 rhiD->unregisterResource(
this);
8096 vkformat = toVkTextureFormat(m_format, m_flags);
8097 if (m_writeViewFormat.format != UnknownFormat)
8098 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
8100 viewFormat = vkformat;
8101 if (m_readViewFormat.format != UnknownFormat)
8102 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
8104 viewFormatForSampling = vkformat;
8106 VkFormatProperties props;
8107 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
8108 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
8109 if (!canSampleOptimal) {
8110 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
8114 const bool isCube = m_flags.testFlag(CubeMap);
8115 const bool isArray = m_flags.testFlag(TextureArray);
8116 const bool is3D = m_flags.testFlag(ThreeDimensional);
8117 const bool is1D = m_flags.testFlag(OneDimensional);
8118 const bool hasMipMaps = m_flags.testFlag(MipMapped);
8120 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
8121 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
8123 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
8124 const int maxLevels = QRhi::MAX_MIP_LEVELS;
8126 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain",
mipLevelCount, maxLevels);
8129 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
8130 if (samples > VK_SAMPLE_COUNT_1_BIT) {
8132 qWarning(
"Cubemap texture cannot be multisample");
8136 qWarning(
"3D texture cannot be multisample");
8140 qWarning(
"Multisample texture cannot have mipmaps");
8144 if (isCube && is3D) {
8145 qWarning(
"Texture cannot be both cube and 3D");
8148 if (isArray && is3D) {
8149 qWarning(
"Texture cannot be both array and 3D");
8152 if (isCube && is1D) {
8153 qWarning(
"Texture cannot be both cube and 1D");
8157 qWarning(
"Texture cannot be both 1D and 3D");
8160 if (m_depth > 1 && !is3D) {
8161 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
8164 if (m_arraySize > 0 && !isArray) {
8165 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
8168 if (m_arraySize < 1 && isArray) {
8169 qWarning(
"Texture is an array but array size is %d", m_arraySize);
8173 usageState.layout = VK_IMAGE_LAYOUT_UNDEFINED;
8174 usageState.access = 0;
8175 usageState.stage = 0;
8177 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
8181 *adjustedSize = size;
8190 const auto aspectMask = aspectMaskForTextureFormat(m_format);
8191 const bool isCube = m_flags.testFlag(CubeMap);
8192 const bool isArray = m_flags.testFlag(TextureArray);
8193 const bool is3D = m_flags.testFlag(ThreeDimensional);
8194 const bool is1D = m_flags.testFlag(OneDimensional);
8196 VkImageViewCreateInfo viewInfo = {};
8197 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8198 viewInfo.image = image;
8199 viewInfo.viewType = isCube
8200 ? VK_IMAGE_VIEW_TYPE_CUBE
8201 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8202 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8203 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8204 viewInfo.format = viewFormatForSampling;
8205 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8206 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8207 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8208 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8209 viewInfo.subresourceRange.aspectMask = aspectMask;
8212 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8214 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
8215 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
8216 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
8218 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8221 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
8222 if (err != VK_SUCCESS) {
8223 qWarning(
"Failed to create image view: %d", err);
8236 if (!prepareCreate(&size))
8240 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
8241 const bool isDepth = isDepthTextureFormat(m_format);
8242 const bool isCube = m_flags.testFlag(CubeMap);
8243 const bool isArray = m_flags.testFlag(TextureArray);
8244 const bool is3D = m_flags.testFlag(ThreeDimensional);
8245 const bool is1D = m_flags.testFlag(OneDimensional);
8247 VkImageCreateInfo imageInfo = {};
8248 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
8249 imageInfo.flags = 0;
8251 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
8252 if (viewFormat != vkformat || viewFormatForSampling != vkformat)
8253 imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
8255 if (is3D && isRenderTarget) {
8261 if (!rhiD->caps.texture3DSliceAs2D)
8262 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
8263#ifdef VK_VERSION_1_1
8264 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
8266 imageInfo.flags |= 0x00000020;
8270 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
8271 imageInfo.format = vkformat;
8272 imageInfo.extent.width = uint32_t(size.width());
8273 imageInfo.extent.height = uint32_t(size.height());
8274 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
8276 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8277 imageInfo.samples = samples;
8278 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
8281 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
8283 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
8284 if (isRenderTarget) {
8286 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
8288 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
8290 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
8291 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8292 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
8293 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8294 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
8295 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
8296#ifdef VK_KHR_fragment_shading_rate
8297 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
8298 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
8301 VmaAllocationCreateInfo allocInfo = {};
8302 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
8304 VmaAllocation allocation;
8305 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
8306 if (err != VK_SUCCESS) {
8307 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
8308 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
8309 int(imageInfo.format),
8310 imageInfo.mipLevels,
8311 imageInfo.arrayLayers,
8312 int(imageInfo.samples),
8314 rhiD->printExtraErrorInfo(err);
8318 rhiD->setAllocationName(allocation, m_objectName);
8323 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
8326 rhiD->registerResource(
this);
8332 VkImage img = VkImage(src.object);
8336 if (!prepareCreate())
8344 usageState.layout = VkImageLayout(src.layout);
8348 rhiD->registerResource(
this);
8354 return {quint64(image), usageState.layout};
8359 usageState.layout = VkImageLayout(layout);
8365 if (perLevelImageViews[level] != VK_NULL_HANDLE)
8366 return perLevelImageViews[level];
8368 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
8369 const bool isCube = m_flags.testFlag(CubeMap);
8370 const bool isArray = m_flags.testFlag(TextureArray);
8371 const bool is3D = m_flags.testFlag(ThreeDimensional);
8372 const bool is1D = m_flags.testFlag(OneDimensional);
8374 VkImageViewCreateInfo viewInfo = {};
8375 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8376 viewInfo.image = image;
8377 viewInfo.viewType = isCube
8378 ? VK_IMAGE_VIEW_TYPE_CUBE
8379 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8380 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8381 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8382 viewInfo.format = viewFormat;
8383 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8384 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8385 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8386 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8387 viewInfo.subresourceRange.aspectMask = aspectMask;
8388 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
8389 viewInfo.subresourceRange.levelCount = 1;
8390 viewInfo.subresourceRange.baseArrayLayer = 0;
8391 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8393 VkImageView v = VK_NULL_HANDLE;
8395 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
8396 if (err != VK_SUCCESS) {
8397 qWarning(
"Failed to create image view: %d", err);
8398 return VK_NULL_HANDLE;
8401 perLevelImageViews[level] = v;
8406 AddressMode u, AddressMode v, AddressMode w)
8425 e.sampler.sampler = sampler;
8426 sampler = VK_NULL_HANDLE;
8430 rhiD->releaseQueue.append(e);
8431 rhiD->unregisterResource(
this);
8440 VkSamplerCreateInfo samplerInfo = {};
8441 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
8442 samplerInfo.magFilter = toVkFilter(m_magFilter);
8443 samplerInfo.minFilter = toVkFilter(m_minFilter);
8444 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
8445 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
8446 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
8447 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
8448 samplerInfo.maxAnisotropy = 1.0f;
8449 samplerInfo.compareEnable = m_compareOp != Never;
8450 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
8451 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
8454 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
8455 if (err != VK_SUCCESS) {
8456 qWarning(
"Failed to create sampler: %d", err);
8462 rhiD->registerResource(
this);
8469 serializedFormatData.reserve(64);
8483 rp = VK_NULL_HANDLE;
8491 e.renderPass.rp = rp;
8493 rp = VK_NULL_HANDLE;
8497 rhiD->releaseQueue.append(e);
8498 rhiD->unregisterResource(
this);
8504 return a.format == b.format
8505 && a.samples == b.samples
8506 && a.loadOp == b.loadOp
8507 && a.storeOp == b.storeOp
8508 && a.stencilLoadOp == b.stencilLoadOp
8509 && a.stencilStoreOp == b.stencilStoreOp
8510 && a.initialLayout == b.initialLayout
8511 && a.finalLayout == b.finalLayout;
8524 if (attDescs.size() != o->attDescs.size())
8526 if (colorRefs.size() != o->colorRefs.size())
8528 if (resolveRefs.size() != o->resolveRefs.size())
8534 if (multiViewCount != o->multiViewCount)
8539 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8540 const uint32_t attIdx = colorRefs[i].attachment;
8541 if (attIdx != o->colorRefs[i].attachment)
8543 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8548 const uint32_t attIdx = dsRef.attachment;
8549 if (attIdx != o->dsRef.attachment)
8551 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8555 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8556 const uint32_t attIdx = resolveRefs[i].attachment;
8557 if (attIdx != o->resolveRefs[i].attachment)
8559 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8564 const uint32_t attIdx = dsResolveRef.attachment;
8565 if (attIdx != o->dsResolveRef.attachment)
8567 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8572 const uint32_t attIdx = shadingRateRef.attachment;
8573 if (attIdx != o->shadingRateRef.attachment)
8575 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8586 serializedFormatData.clear();
8587 auto p =
std::back_inserter(serializedFormatData);
8589 *p++ = attDescs.size();
8590 *p++ = colorRefs.size();
8591 *p++ = resolveRefs.size();
8595 *p++ = multiViewCount;
8597 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8598 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8599 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8600 *p++ = used ? a->format : 0;
8601 *p++ = used ? a->samples : 0;
8602 *p++ = used ? a->loadOp : 0;
8603 *p++ = used ? a->storeOp : 0;
8604 *p++ = used ? a->stencilLoadOp : 0;
8605 *p++ = used ? a->stencilStoreOp : 0;
8606 *p++ = used ? a->initialLayout : 0;
8607 *p++ = used ? a->finalLayout : 0;
8610 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8611 const uint32_t attIdx = colorRefs[i].attachment;
8613 serializeAttachmentData(attIdx);
8617 const uint32_t attIdx = dsRef.attachment;
8619 serializeAttachmentData(attIdx);
8622 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8623 const uint32_t attIdx = resolveRefs[i].attachment;
8625 serializeAttachmentData(attIdx);
8629 const uint32_t attIdx = dsResolveRef.attachment;
8631 serializeAttachmentData(attIdx);
8635 const uint32_t attIdx = shadingRateRef.attachment;
8637 serializeAttachmentData(attIdx);
8646 rpD->attDescs = attDescs;
8647 rpD->colorRefs = colorRefs;
8648 rpD->resolveRefs = resolveRefs;
8649 rpD->subpassDeps = subpassDeps;
8653 rpD->multiViewCount = multiViewCount;
8655 rpD->dsResolveRef = dsResolveRef;
8656 rpD->shadingRateRef = shadingRateRef;
8658 VkRenderPassCreateInfo rpInfo;
8659 VkSubpassDescription subpassDesc;
8660 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8664 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8669#ifdef VK_KHR_create_renderpass2
8670 if (rhiD->caps.renderPass2KHR) {
8672 VkRenderPassCreateInfo2KHR rpInfo2;
8673 RenderPass2SetupHelper rp2Helper(rhiD);
8674 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8678 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8679 if (err != VK_SUCCESS) {
8680 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8687 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8688 if (err != VK_SUCCESS) {
8689 qWarning(
"Failed to create renderpass: %d", err);
8696 rhiD->registerResource(rpD);
8702 return serializedFormatData;
8707 nativeHandlesStruct.renderPass = rp;
8708 return &nativeHandlesStruct;
8766 return d.sampleCount;
8770 const QRhiTextureRenderTargetDescription &desc,
8775 rtv[att] = VK_NULL_HANDLE;
8776 resrtv[att] = VK_NULL_HANDLE;
8794 e.textureRenderTarget.fb = d.fb;
8795 d.fb = VK_NULL_HANDLE;
8798 e.textureRenderTarget.rtv[att] = rtv[att];
8799 e.textureRenderTarget.resrtv[att] = resrtv[att];
8800 rtv[att] = VK_NULL_HANDLE;
8801 resrtv[att] = VK_NULL_HANDLE;
8804 e.textureRenderTarget.dsv = dsv;
8805 dsv = VK_NULL_HANDLE;
8806 e.textureRenderTarget.resdsv = resdsv;
8807 resdsv = VK_NULL_HANDLE;
8809 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8810 shadingRateMapView = VK_NULL_HANDLE;
8814 rhiD->releaseQueue.append(e);
8815 rhiD->unregisterResource(
this);
8825 if (!rhiD->createOffscreenRenderPass(rp,
8826 m_desc.cbeginColorAttachments(),
8827 m_desc.cendColorAttachments(),
8828 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8829 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8830 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8831 m_desc.depthStencilBuffer(),
8832 m_desc.depthTexture(),
8833 m_desc.depthResolveTexture(),
8834 m_desc.depthLayer(),
8835 m_desc.shadingRateMap()))
8843 rhiD->registerResource(rp);
8852 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8853 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8854 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8857 QVarLengthArray<VkImageView, 8> views;
8858 d.multiViewCount = 0;
8860 d.colorAttCount = 0;
8862 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8863 d.colorAttCount += 1;
8866 Q_ASSERT(texD || rbD);
8868 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8869 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8870 const bool isMultiView = it->multiViewCount() >= 2;
8871 if (isMultiView && d.multiViewCount == 0)
8872 d.multiViewCount = it->multiViewCount();
8873 VkImageViewCreateInfo viewInfo = {};
8874 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8875 viewInfo.image = texD->image;
8876 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8877 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8878 : VK_IMAGE_VIEW_TYPE_2D);
8879 viewInfo.format = texD->viewFormat;
8880 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8881 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8882 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8883 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8884 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8885 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8886 viewInfo.subresourceRange.levelCount = 1;
8887 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8888 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8889 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8890 if (err != VK_SUCCESS) {
8891 qWarning(
"Failed to create render target image view: %d", err);
8894 views.append(rtv[attIndex]);
8895 if (attIndex == 0) {
8896 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8897 d.sampleCount = texD->samples;
8902 if (attIndex == 0) {
8903 d.pixelSize = rbD->pixelSize();
8904 d.sampleCount = rbD->samples;
8910 if (hasDepthStencil) {
8911 if (m_desc.depthTexture()) {
8914 VkImageViewCreateInfo viewInfo = {};
8915 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8916 viewInfo.image = depthTexD->image;
8917 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8918 viewInfo.format = depthTexD->viewFormat;
8919 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8920 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8921 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8922 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8923 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8924 viewInfo.subresourceRange.levelCount = 1;
8925 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8926 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8927 viewInfo.subresourceRange.layerCount = 1;
8930 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8931 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8932 if (err != VK_SUCCESS) {
8933 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8937 if (d.colorAttCount == 0) {
8938 d.pixelSize = depthTexD->pixelSize();
8939 d.sampleCount = depthTexD->samples;
8943 views.append(depthRbD->imageView);
8944 if (d.colorAttCount == 0) {
8945 d.pixelSize = depthRbD->pixelSize();
8946 d.sampleCount = depthRbD->samples;
8954 d.resolveAttCount = 0;
8956 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8957 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8958 if (it->resolveTexture()) {
8960 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8961 d.resolveAttCount += 1;
8963 VkImageViewCreateInfo viewInfo = {};
8964 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8965 viewInfo.image = resTexD->image;
8966 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8967 : VK_IMAGE_VIEW_TYPE_2D;
8968 viewInfo.format = resTexD->viewFormat;
8969 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8970 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8971 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8972 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8973 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8974 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8975 viewInfo.subresourceRange.levelCount = 1;
8976 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8977 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8978 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8979 if (err != VK_SUCCESS) {
8980 qWarning(
"Failed to create render target resolve image view: %d", err);
8983 views.append(resrtv[attIndex]);
8987 if (m_desc.depthResolveTexture()) {
8989 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8991 VkImageViewCreateInfo viewInfo = {};
8992 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8993 viewInfo.image = resTexD->image;
8994 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8995 : VK_IMAGE_VIEW_TYPE_2D;
8996 viewInfo.format = resTexD->viewFormat;
8997 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8998 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8999 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
9000 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
9001 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
9002 viewInfo.subresourceRange.baseMipLevel = 0;
9003 viewInfo.subresourceRange.levelCount = 1;
9004 viewInfo.subresourceRange.baseArrayLayer = 0;
9005 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
9006 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
9007 if (err != VK_SUCCESS) {
9008 qWarning(
"Failed to create render target depth resolve image view: %d", err);
9011 views.append(resdsv);
9012 d.dsResolveAttCount = 1;
9014 d.dsResolveAttCount = 0;
9017 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
9019 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
9021 VkImageViewCreateInfo viewInfo = {};
9022 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
9023 viewInfo.image = texD->image;
9024 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
9025 : VK_IMAGE_VIEW_TYPE_2D;
9026 viewInfo.format = texD->viewFormat;
9027 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
9028 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
9029 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
9030 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
9031 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
9032 viewInfo.subresourceRange.baseMipLevel = 0;
9033 viewInfo.subresourceRange.levelCount = 1;
9034 viewInfo.subresourceRange.baseArrayLayer = 0;
9035 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
9036 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
9037 if (err != VK_SUCCESS) {
9038 qWarning(
"Failed to create render target shading rate map view: %d", err);
9041 views.append(shadingRateMapView);
9042 d.shadingRateAttCount = 1;
9044 d.shadingRateAttCount = 0;
9047 if (!m_renderPassDesc)
9048 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9050 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9051 Q_ASSERT(d.rp && d.rp->rp);
9053 VkFramebufferCreateInfo fbInfo = {};
9054 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9055 fbInfo.renderPass = d.rp->rp;
9056 fbInfo.attachmentCount = uint32_t(views.count());
9057 fbInfo.pAttachments = views.constData();
9058 fbInfo.width = uint32_t(d.pixelSize.width());
9059 fbInfo.height = uint32_t(d.pixelSize.height());
9062 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
9063 if (err != VK_SUCCESS) {
9064 qWarning(
"Failed to create framebuffer: %d", err);
9068 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
9071 rhiD->registerResource(
this);
9077 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
9090 return d.sampleCount;
9108 sortedBindings.clear();
9109 sortedDynamicOffsetBindingNumbers.clear();
9115 e.shaderResourceBindings.poolIndex =
poolIndex;
9116 e.shaderResourceBindings.layout = layout;
9119 layout = VK_NULL_HANDLE;
9120 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9121 descSets[i] = VK_NULL_HANDLE;
9125 rhiD->releaseQueue.append(e);
9126 rhiD->unregisterResource(
this);
9136 if (!rhiD->sanityCheckShaderResourceBindings(
this))
9139 rhiD->updateLayoutDesc(
this);
9141 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9142 descSets[i] = VK_NULL_HANDLE;
9144 sortedBindings.clear();
9145 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
9146 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
9148 sortedDynamicOffsetBindingNumbers.clear();
9149 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9150 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9151 if (b->type() == QRhiShaderResourceBinding::UniformBuffer && b->ubuf().buf) {
9152 if (b->ubuf().hasDynamicOffset)
9153 sortedDynamicOffsetBindingNumbers.append(b->binding);
9157 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
9158 vkbindings.reserve(sortedBindings.size());
9159 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9160 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9161 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
9162 vkbinding.binding = uint32_t(b->binding);
9163 vkbinding.descriptorType = toVkDescriptorType(b);
9164 if (b->type() == QRhiShaderResourceBinding::SampledTexture || b->type() == QRhiShaderResourceBinding::Texture)
9165 vkbinding.descriptorCount = b->stex().count();
9167 vkbinding.descriptorCount = 1;
9168 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
9171 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
9172 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
9173 layoutInfo.bindingCount = uint32_t(vkbindings.size());
9174 layoutInfo.pBindings = vkbindings.constData();
9176 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
9177 if (err != VK_SUCCESS) {
9178 qWarning(
"Failed to create descriptor set layout: %d", err);
9181 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
9183 VkDescriptorSetAllocateInfo allocInfo = {};
9184 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
9188 layouts[i] = layout;
9189 allocInfo.pSetLayouts = layouts;
9190 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
9194 boundResourceData[i].resize(sortedBindings.size());
9195 for (BoundResourceData &bd : boundResourceData[i])
9200 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
9204 rhiD->registerResource(
this);
9210 sortedBindings.clear();
9211 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
9212 if (!flags.testFlag(BindingsAreSorted))
9213 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
9215 sortedDynamicOffsetBindingNumbers.clear();
9216 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9217 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9218 if (b->type() == QRhiShaderResourceBinding::UniformBuffer && b->ubuf().buf) {
9219 if (b->ubuf().hasDynamicOffset)
9220 sortedDynamicOffsetBindingNumbers.append(b->binding);
9234 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
9235 for (BoundResourceData &bd : boundResourceData[i])
9254 if (!pipeline && !layout)
9261 e.pipelineState.pipeline = pipeline;
9262 e.pipelineState.layout = layout;
9264 pipeline = VK_NULL_HANDLE;
9265 layout = VK_NULL_HANDLE;
9269 rhiD->releaseQueue.append(e);
9270 rhiD->unregisterResource(
this);
9276 if (pipeline || layout)
9280 rhiD->pipelineCreationStart();
9281 if (!rhiD->sanityCheckGraphicsPipeline(
this))
9284 if (!rhiD->ensurePipelineCache())
9287 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9288 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9289 pipelineLayoutInfo.setLayoutCount = 1;
9291 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9292 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9293 VkPushConstantRange pushConstantRange = {};
9294 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
9295 for (
const QShaderDescription::PushConstantBlock &block : shaderStage.shader().description().pushConstantBlocks()) {
9296 pushConstantRange.stageFlags |= toVkShaderStage(shaderStage.type());
9297 pushConstantRange.size = qMax(pushConstantRange.size, uint32_t((block.size + 3) & ~3));
9300 if (pushConstantRange.size) {
9301 pipelineLayoutInfo.pushConstantRangeCount = 1;
9302 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
9304 pushConstantStages = pushConstantRange.stageFlags;
9305 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9306 if (err != VK_SUCCESS) {
9307 qWarning(
"Failed to create pipeline layout: %d", err);
9310 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9311 rhiD->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9312 layout = VK_NULL_HANDLE;
9315 VkGraphicsPipelineCreateInfo pipelineInfo = {};
9316 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
9318 QVarLengthArray<VkShaderModule, 4> shaders;
9319 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
9320 for (VkShaderModule shader : shaders)
9321 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9323 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
9324 QVarLengthArray<QByteArray, 4> entryPointNames;
9325 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
9326 const QShader bakedShader = shaderStage.shader();
9327 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
9328 if (spirv.shader().isEmpty()) {
9329 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9332 VkShaderModule shader = rhiD->createShader(spirv.shader());
9334 shaders.append(shader);
9335 VkPipelineShaderStageCreateInfo shaderInfo = {};
9336 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9337 shaderInfo.stage = toVkShaderStage(shaderStage.type());
9338 shaderInfo.module = shader;
9339 entryPointNames.append(spirv.entryPoint());
9340 shaderInfo.pName =
nullptr;
9341 shaderStageCreateInfos.append(shaderInfo);
9346 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
9347 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
9349 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
9350 pipelineInfo.pStages = shaderStageCreateInfos.constData();
9352 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
9353#ifdef VK_EXT_vertex_attribute_divisor
9354 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
9356 int bindingIndex = 0;
9357 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
9358 it != itEnd; ++it, ++bindingIndex)
9360 VkVertexInputBindingDescription bindingInfo = {
9361 uint32_t(bindingIndex),
9363 it->classification() == QRhiVertexInputBinding::PerVertex
9364 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
9366 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
9367#ifdef VK_EXT_vertex_attribute_divisor
9368 if (rhiD->caps.vertexAttribDivisor) {
9369 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
9373 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
9374 "VK_EXT_vertex_attribute_divisor on the device and "
9375 "VK_KHR_get_physical_device_properties2 on the instance");
9378 vertexBindings.append(bindingInfo);
9380 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
9381 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
9384 VkVertexInputAttributeDescription attributeInfo = {
9385 uint32_t(it->location()),
9386 uint32_t(it->binding()),
9387 toVkAttributeFormat(it->format()),
9390 vertexAttributes.append(attributeInfo);
9392 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
9393 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
9394 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
9395 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
9396 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
9397 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
9398#ifdef VK_EXT_vertex_attribute_divisor
9399 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
9400 if (!nonOneStepRates.isEmpty()) {
9401 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
9402 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
9403 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
9404 vertexInputInfo.pNext = &divisorInfo;
9407 pipelineInfo.pVertexInputState = &vertexInputInfo;
9409 QVarLengthArray<VkDynamicState, 8> dynEnable;
9410 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
9411 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
9412 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
9413 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
9414 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
9415 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
9416#ifdef VK_KHR_fragment_shading_rate
9417 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
9418 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
9421 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
9422 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
9423 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
9424 dynamicInfo.pDynamicStates = dynEnable.constData();
9425 pipelineInfo.pDynamicState = &dynamicInfo;
9427 VkPipelineViewportStateCreateInfo viewportInfo = {};
9428 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
9429 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
9430 pipelineInfo.pViewportState = &viewportInfo;
9432 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
9433 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
9434 inputAsmInfo.topology = toVkTopology(m_topology);
9435 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
9436 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
9438 VkPipelineTessellationStateCreateInfo tessInfo = {};
9439#ifdef VK_VERSION_1_1
9440 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
9442 if (m_topology == Patches) {
9443 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
9444 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
9451#ifdef VK_VERSION_1_1
9452 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
9453 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
9454 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
9455 tessInfo.pNext = &originInfo;
9457 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
9460 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
9463 pipelineInfo.pTessellationState = &tessInfo;
9466 VkPipelineRasterizationStateCreateInfo rastInfo = {};
9467 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
9468 if (m_depthClamp && rhiD->caps.depthClamp)
9469 rastInfo.depthClampEnable = m_depthClamp;
9470 rastInfo.cullMode = toVkCullMode(m_cullMode);
9471 rastInfo.frontFace = toVkFrontFace(m_frontFace);
9472 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
9473 rastInfo.depthBiasEnable =
true;
9474 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
9475 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
9477 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
9478 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
9479 pipelineInfo.pRasterizationState = &rastInfo;
9481 VkPipelineMultisampleStateCreateInfo msInfo = {};
9482 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
9483 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
9484 pipelineInfo.pMultisampleState = &msInfo;
9486 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
9487 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
9488 dsInfo.depthTestEnable = m_depthTest;
9489 dsInfo.depthWriteEnable = m_depthWrite;
9490 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
9491 dsInfo.stencilTestEnable = m_stencilTest;
9492 if (m_stencilTest) {
9493 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
9494 dsInfo.front.compareMask = m_stencilReadMask;
9495 dsInfo.front.writeMask = m_stencilWriteMask;
9496 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
9497 dsInfo.back.compareMask = m_stencilReadMask;
9498 dsInfo.back.writeMask = m_stencilWriteMask;
9500 pipelineInfo.pDepthStencilState = &dsInfo;
9502 VkPipelineColorBlendStateCreateInfo blendInfo = {};
9503 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
9504 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
9505 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
9506 VkPipelineColorBlendAttachmentState blend = {};
9507 blend.blendEnable = b.enable;
9508 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
9509 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
9510 blend.colorBlendOp = toVkBlendOp(b.opColor);
9511 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
9512 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
9513 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
9514 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
9515 vktargetBlends.append(blend);
9517 if (vktargetBlends.isEmpty()) {
9518 VkPipelineColorBlendAttachmentState blend = {};
9519 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
9520 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
9521 vktargetBlends.append(blend);
9523 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
9524 blendInfo.pAttachments = vktargetBlends.constData();
9525 pipelineInfo.pColorBlendState = &blendInfo;
9527 pipelineInfo.layout = layout;
9529 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
9530 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
9532 err = rhiD->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9534 if (err != VK_SUCCESS) {
9535 qWarning(
"Failed to create graphics pipeline: %d", err);
9538 pipelineLayoutCleanup.dismiss();
9540 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9542 rhiD->pipelineCreationEnd();
9543 lastActiveFrameSlot = -1;
9545 rhiD->registerResource(
this);
9549QVkComputePipeline::QVkComputePipeline(QRhiImplementation *rhi)
9550 : QRhiComputePipeline(rhi)
9554QVkComputePipeline::~QVkComputePipeline()
9559void QVkComputePipeline::destroy()
9561 if (!pipeline && !layout)
9564 QRhiVulkan::DeferredReleaseEntry e;
9565 e.type = QRhiVulkan::DeferredReleaseEntry::Pipeline;
9566 e.lastActiveFrameSlot = lastActiveFrameSlot;
9568 e.pipelineState.pipeline = pipeline;
9569 e.pipelineState.layout = layout;
9571 pipeline = VK_NULL_HANDLE;
9572 layout = VK_NULL_HANDLE;
9576 rhiD->releaseQueue.append(e);
9577 rhiD->unregisterResource(
this);
9581bool QVkComputePipeline::create()
9583 if (pipeline || layout)
9587 rhiD->pipelineCreationStart();
9588 if (!rhiD->ensurePipelineCache())
9591 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9592 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9593 pipelineLayoutInfo.setLayoutCount = 1;
9594 QVkShaderResourceBindings *srbD =
QRHI_RES(QVkShaderResourceBindings, m_shaderResourceBindings);
9595 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9596 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9597 VkPushConstantRange pushConstantRange = {};
9598 for (
const QShaderDescription::PushConstantBlock &block : m_shaderStage.shader().description().pushConstantBlocks()) {
9599 pushConstantRange.stageFlags |= VK_SHADER_STAGE_COMPUTE_BIT;
9600 pushConstantRange.size = qMax(pushConstantRange.size, uint32_t((block.size + 3) & ~3));
9602 if (pushConstantRange.size) {
9603 pipelineLayoutInfo.pushConstantRangeCount = 1;
9604 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
9606 pushConstantStages = pushConstantRange.stageFlags;
9607 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9608 if (err != VK_SUCCESS) {
9609 qWarning(
"Failed to create pipeline layout: %d", err);
9612 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9613 rhiD->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9614 layout = VK_NULL_HANDLE;
9617 VkComputePipelineCreateInfo pipelineInfo = {};
9618 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9619 pipelineInfo.layout = layout;
9621 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9622 qWarning(
"Compute pipeline requires a compute shader stage");
9625 const QShader bakedShader = m_shaderStage.shader();
9626 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9627 if (spirv.shader().isEmpty()) {
9628 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9631 if (bakedShader.stage() != QShader::ComputeStage) {
9632 qWarning() << bakedShader <<
"is not a compute shader";
9635 VkShaderModule shader = rhiD->createShader(spirv.shader());
9638 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9639 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9641 VkPipelineShaderStageCreateInfo shaderInfo = {};
9642 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9643 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9644 shaderInfo.module = shader;
9645 const QByteArray entryPointName = spirv.entryPoint();
9646 shaderInfo.pName = entryPointName.constData();
9647 pipelineInfo.stage = shaderInfo;
9649 err = rhiD->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9650 if (err != VK_SUCCESS) {
9651 qWarning(
"Failed to create graphics pipeline: %d", err);
9654 pipelineLayoutCleanup.dismiss();
9656 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9658 rhiD->pipelineCreationEnd();
9659 lastActiveFrameSlot = -1;
9661 rhiD->registerResource(
this);
9665QVkCommandBuffer::QVkCommandBuffer(QRhiImplementation *rhi)
9666 : QRhiCommandBuffer(rhi)
9671QVkCommandBuffer::~QVkCommandBuffer()
9676void QVkCommandBuffer::destroy()
9681const QRhiNativeHandles *QVkCommandBuffer::nativeHandles()
9689 if (recordingPass == QVkCommandBuffer::NoPass) {
9690 nativeHandlesStruct.commandBuffer = cb;
9692 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9693 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9695 nativeHandlesStruct.commandBuffer = cb;
9698 return &nativeHandlesStruct;
9701QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi)
9702 : QRhiSwapChain(rhi),
9703 rtWrapper(rhi,
this),
9704 rtWrapperRight(rhi,
this),
9709QVkSwapChain::~QVkSwapChain()
9714void QVkSwapChain::destroy()
9716 if (sc == VK_NULL_HANDLE)
9721 rhiD->swapchains.remove(
this);
9722 rhiD->releaseSwapChainResources(
this);
9725 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) {
9726 QVkSwapChain::FrameResources &frame(frameRes[i]);
9727 frame.cmdBuf = VK_NULL_HANDLE;
9728 frame.timestampQueryIndex = -1;
9731 surface = lastConnectedSurface = VK_NULL_HANDLE;
9734 rhiD->unregisterResource(
this);
9737QRhiCommandBuffer *QVkSwapChain::currentFrameCommandBuffer()
9742QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget()
9747QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
9749 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9752QSize QVkSwapChain::surfacePixelSize()
9754 if (!ensureSurface())
9759 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9761 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9762 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9763 if (bufferSize.width == uint32_t(-1)) {
9764 Q_ASSERT(bufferSize.height == uint32_t(-1));
9765 return m_window->size() * m_window->devicePixelRatio();
9767 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9770static inline bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f,
const VkSurfaceFormatKHR &s)
9773 case QRhiSwapChain::HDRExtendedSrgbLinear:
9774 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9775 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9776 case QRhiSwapChain::HDR10:
9777 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9778 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9779 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9780 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9781 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9788bool QVkSwapChain::isFormatSupported(Format f)
9794 qWarning(
"Attempted to call isFormatSupported() without a window set");
9799 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9802 uint32_t formatCount = 0;
9803 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9804 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9806 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9807 for (uint32_t i = 0; i < formatCount; ++i) {
9808 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9816QRhiSwapChainHdrInfo QVkSwapChain::hdrInfo()
9818 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
9820 QRHI_RES_RHI(QRhiVulkan);
9822 if (m_window && rhiD->adapterLuidValid)
9823 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9828QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor()
9832 if (!ensureSurface())
9836 QVkRenderPassDescriptor *rp =
new QVkRenderPassDescriptor(m_rhi);
9837 if (!rhiD->createDefaultRenderPass(rp,
9838 m_depthStencil !=
nullptr,
9848 rp->updateSerializedFormat();
9849 rhiD->registerResource(rp);
9853static inline bool isSrgbFormat(VkFormat format)
9856 case VK_FORMAT_R8_SRGB:
9857 case VK_FORMAT_R8G8_SRGB:
9858 case VK_FORMAT_R8G8B8_SRGB:
9859 case VK_FORMAT_B8G8R8_SRGB:
9860 case VK_FORMAT_R8G8B8A8_SRGB:
9861 case VK_FORMAT_B8G8R8A8_SRGB:
9862 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9869bool QVkSwapChain::ensureSurface()
9877 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9879 qWarning(
"Failed to get surface for window");
9882 if (surface == surf)
9888 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9889 qWarning(
"Presenting not supported on this window");
9893 quint32 formatCount = 0;
9894 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9895 QList<VkSurfaceFormatKHR> formats(formatCount);
9896 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9900 colorFormat = formats.constFirst().format;
9901 colorSpace = formats.constFirst().colorSpace;
9904 const bool srgbRequested = m_flags.testFlag(sRGB);
9905 bool foundBestFormat =
false;
9906 if (m_format == SDR) {
9907 for (
int i = 0; i <
int(formatCount); ++i) {
9909 if (srgbRequested) {
9910 ok = defaultSrgbColorFormat == formats[i].format;
9912 ok = defaultColorFormat == formats[i].format;
9915 foundBestFormat =
true;
9916 colorFormat = formats[i].format;
9917 colorSpace = formats[i].colorSpace;
9924 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9925 for (
int i = 0; i <
int(formatCount); ++i) {
9927 if (m_format != SDR) {
9928 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9929 }
else if (srgbRequested) {
9930 ok = isSrgbFormat(formats[i].format);
9933 colorFormat = formats[i].format;
9934 colorSpace = formats[i].colorSpace;
9941 if (m_format != SDR) {
9942 VkSurfaceFormatKHR format{};
9943 format.format = colorFormat;
9944 format.colorSpace = colorSpace;
9945 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9946 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9950 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9951 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9956#if QT_CONFIG(wayland)
9961 const bool hasPassThrough =
9962 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9963 return fmt.format == colorFormat
9964 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9966 if (hasPassThrough) {
9967 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9971 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9973 quint32 presModeCount = 0;
9974 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9975 supportedPresentationModes.resize(presModeCount);
9976 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9977 supportedPresentationModes.data());
9982bool QVkSwapChain::createOrResize()
9985 const bool needsRegistration = !window || window != m_window;
9992 if (window && window != m_window)
9996 m_currentPixelSize = surfacePixelSize();
9997 pixelSize = m_currentPixelSize;
9999 if (!rhiD->recreateSwapChain(
this)) {
10000 qWarning(
"Failed to create new swapchain");
10004 if (needsRegistration || !rhiD->swapchains.contains(
this))
10005 rhiD->swapchains.insert(
this);
10007 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
10008 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
10009 m_depthStencil->sampleCount(), m_sampleCount);
10011 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
10012 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
10013 m_depthStencil->setPixelSize(pixelSize);
10014 if (!m_depthStencil->create())
10015 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
10016 pixelSize.width(), pixelSize.height());
10018 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
10019 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
10020 pixelSize.width(), pixelSize.height());
10024 if (!m_renderPassDesc)
10025 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
10027 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
10028 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
10029 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
10031 rtWrapper.d.pixelSize = pixelSize;
10032 rtWrapper.d.dpr =
float(window->devicePixelRatio());
10033 rtWrapper.d.sampleCount = samples;
10034 rtWrapper.d.colorAttCount = 1;
10035 if (m_depthStencil) {
10036 rtWrapper.d.dsAttCount = 1;
10037 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
10039 rtWrapper.d.dsAttCount = 0;
10042 rtWrapper.d.dsResolveAttCount = 0;
10043 if (samples > VK_SAMPLE_COUNT_1_BIT)
10044 rtWrapper.d.resolveAttCount = 1;
10046 rtWrapper.d.resolveAttCount = 0;
10048 if (shadingRateMapView)
10049 rtWrapper.d.shadingRateAttCount = 1;
10051 rtWrapper.d.shadingRateAttCount = 0;
10053 for (
int i = 0; i < bufferCount; ++i) {
10054 QVkSwapChain::ImageResources &image(imageRes[i]);
10056 QVarLengthArray<VkImageView, 4> views;
10057 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
10059 views.append(ds->imageView);
10060 if (samples > VK_SAMPLE_COUNT_1_BIT)
10061 views.append(image.imageView);
10062 if (shadingRateMapView)
10063 views.append(shadingRateMapView);
10065 VkFramebufferCreateInfo fbInfo = {};
10066 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
10067 fbInfo.renderPass = rtWrapper.d.rp->rp;
10068 fbInfo.attachmentCount = uint32_t(views.count());
10069 fbInfo.pAttachments = views.constData();
10070 fbInfo.width = uint32_t(pixelSize.width());
10071 fbInfo.height = uint32_t(pixelSize.height());
10074 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
10075 if (err != VK_SUCCESS) {
10076 qWarning(
"Failed to create framebuffer: %d", err);
10082 rtWrapperRight.setRenderPassDescriptor(
10084 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
10085 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
10087 rtWrapperRight.d.pixelSize = pixelSize;
10088 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
10089 rtWrapperRight.d.sampleCount = samples;
10090 rtWrapperRight.d.colorAttCount = 1;
10091 if (m_depthStencil) {
10092 rtWrapperRight.d.dsAttCount = 1;
10093 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
10095 rtWrapperRight.d.dsAttCount = 0;
10098 rtWrapperRight.d.dsResolveAttCount = 0;
10099 if (samples > VK_SAMPLE_COUNT_1_BIT)
10100 rtWrapperRight.d.resolveAttCount = 1;
10102 rtWrapperRight.d.resolveAttCount = 0;
10104 for (
int i = 0; i < bufferCount; ++i) {
10105 QVkSwapChain::ImageResources &image(imageRes[i + bufferCount]);
10107 QVarLengthArray<VkImageView, 4> views;
10108 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
10110 views.append(ds->imageView);
10111 if (samples > VK_SAMPLE_COUNT_1_BIT)
10112 views.append(image.imageView);
10113 if (shadingRateMapView)
10114 views.append(shadingRateMapView);
10116 VkFramebufferCreateInfo fbInfo = {};
10117 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
10118 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
10119 fbInfo.attachmentCount = uint32_t(views.count());
10120 fbInfo.pAttachments = views.constData();
10121 fbInfo.width = uint32_t(pixelSize.width());
10122 fbInfo.height = uint32_t(pixelSize.height());
10125 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
10126 if (err != VK_SUCCESS) {
10127 qWarning(
"Failed to create framebuffer: %d", err);
10135 if (needsRegistration)
10136 rhiD->registerResource(
this);
const QRhiPassResourceMap< QRhiTexture *, Texture, 12 > & textures() const
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
const QRhiPassResourceMap< QRhiBuffer *, Buffer, 12 > & buffers() const
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker)
VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD=nullptr)
QRhiSwapChain * createSwapChain() override
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
int resourceLimit(QRhi::ResourceLimit limit) const override
bool isDeviceLost() const override
void prepareUploadSubres(QVkTexture *texD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, size_t *curOfs, void *mp, BufferImageCopyList *copyInfos)
void executeDeferredReleases(bool forced=false)
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex)
QRhi::FrameOpResult finish() override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples, VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count)
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void releaseCachedResources() override
QVkSwapChain * currentSwapChain
void collectComputeBarriers(QVkCommandBuffer *cbD, QVarLengthArray< VkImageMemoryBarrier, 8 > *imageBarriers, QVarLengthArray< VkBufferMemoryBarrier, 8 > *bufferBarriers)
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams=nullptr)
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
QList< int > supportedSampleCounts() const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb)
void setPushConstants(QRhiCommandBuffer *cb, quint32 offset, quint32 size, const void *data) override
void dispatchIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset) override
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
void drawIndexedIndirectCount(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, QRhiBuffer *countBuffer, quint32 countBufferOffset, quint32 maxDrawCount, quint32 stride) override
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot, VkAccessFlags access, VkPipelineStageFlags stage)
QRhi::FrameOpResult waitCommandCompletion(int frameSlot)
void endExternal(QRhiCommandBuffer *cb) override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex)
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
void drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride) override
VkResult createDescriptorPool(VkDescriptorPool *pool)
void prepareNewFrame(QRhiCommandBuffer *cb)
void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, int startLayer, int layerCount, int startLevel, int levelCount)
QList< QSize > supportedShadingRates(int sampleCount) const override
void printExtraErrorInfo(VkResult err)
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb)
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
void recordStencilRef(QVkCommandBuffer *cbD, quint32 refValue)
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, QVkTexture *texD, QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage)
bool releaseCachedResourcesCalledBeforeFrameStart
QRhiGraphicsPipeline * createGraphicsPipeline() override
QRhiComputePipeline * createComputePipeline() override
void setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot=-1)
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
const QRhiNativeHandles * nativeHandles(QRhiCommandBuffer *cb) override
bool recreateSwapChain(QRhiSwapChain *swapChain)
Q_DECL_COLD_FUNCTION void printDeviceLossErrorInfo() const
bool ensurePipelineCache(const void *initialData=nullptr, size_t initialDataSize=0)
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD)
void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD, VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
VkShaderModule createShader(const QByteArray &spirv)
void enqueueTransitionPassResources(QVkCommandBuffer *cbD)
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
bool create(QRhi::Flags flags) override
QVulkanDeviceFunctions * df
void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot=-1)
bool isFeatureSupported(QRhi::Feature feature) const override
void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
bool isYUpInFramebuffer() const override
void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override
void debugMarkEnd(QRhiCommandBuffer *cb) override
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
void releaseSwapChainResources(QRhiSwapChain *swapChain)
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, int depthLayer, QRhiShadingRateMap *shadingRateMap)
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, QVkBuffer *bufD, int slot, QRhiPassResourceTracker::BufferAccess access, QRhiPassResourceTracker::BufferStage stage)
VkFormat optimalDepthStencilFormat()
QRhiStats statistics() override
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
void drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride) override
void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD)
void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
void setDefaultScissor(QVkCommandBuffer *cbD)
bool isYUpInNDC() const override
const QRhiNativeHandles * nativeHandles() override
QRhiShadingRateMap * createShadingRateMap() override
void setPipelineCacheData(const QByteArray &data) override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
QRhiShaderResourceBindings * createShaderResourceBindings() override
void finishActiveReadbacks(bool forced=false)
void ensureCommandPoolForNewFrame()
QByteArray pipelineCacheData() override
void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD)
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void drawIndirectCount(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, QRhiBuffer *countBuffer, quint32 countBufferOffset, quint32 maxDrawCount, quint32 stride) override
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
bool isClipDepthZeroToOne() const override
void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
QMatrix4x4 clipSpaceCorrMatrix() const override
int ubufAlignment() const override
QRhiDriverInfo driverInfo() const override
void beginExternal(QRhiCommandBuffer *cb) override
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat, QRhiShadingRateMap *shadingRateMap)
QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence, VkSemaphore *waitSem, VkSemaphore *signalSem)
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount)
bool makeThreadLocalNativeContextCurrent() override
QRhiDriverInfo info() const override
Combined button and popup list for selecting options.
static VkPolygonMode toVkPolygonMode(QRhiGraphicsPipeline::PolygonMode mode)
static VkCullModeFlags toVkCullMode(QRhiGraphicsPipeline::CullMode c)
static bool accessIsWrite(VkAccessFlags access)
static VkCompareOp toVkTextureCompareOp(QRhiSampler::CompareOp op)
static QVulkanInstance * globalVulkanInstance
static VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
static QRhiTexture::Format swapchainReadbackTextureFormat(VkFormat format, QRhiTexture::Flags *flags)
static VkStencilOp toVkStencilOp(QRhiGraphicsPipeline::StencilOp op)
static bool qvk_debug_filter(QVulkanInstance::DebugMessageSeverityFlags severity, QVulkanInstance::DebugMessageTypeFlags type, const void *callbackData)
static QVkBuffer::UsageState toVkBufferUsageState(QRhiPassResourceTracker::UsageState usage)
static bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::TextureStage stage)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::BufferAccess access)
static VkImageLayout toVkLayout(QRhiPassResourceTracker::TextureAccess access)
static VkFormat toVkAttributeFormat(QRhiVertexInputAttribute::Format format)
static QVkTexture::UsageState toVkTextureUsageState(QRhiPassResourceTracker::UsageState usage)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::BufferStage stage)
static QRhiDriverInfo::DeviceType toRhiDeviceType(VkPhysicalDeviceType type)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkBuffer::UsageState &bufUsage)
static VkColorComponentFlags toVkColorComponents(QRhiGraphicsPipeline::ColorMask c)
static VkFilter toVkFilter(QRhiSampler::Filter f)
static VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t)
static void qrhivk_releaseTexture(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df, void *allocator)
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::TextureAccess access)
static VmaAllocator toVmaAllocator(QVkAllocator a)
static VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
static constexpr bool isDepthTextureFormat(QRhiTexture::Format format)
static void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphicsPipeline::StencilOpState &src)
static VkShaderStageFlags toVkShaderStageFlags(QRhiShaderResourceBinding::StageFlags stage)
static constexpr VkImageAspectFlags aspectMaskForTextureFormat(QRhiTexture::Format format)
static VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
static VkBlendFactor toVkBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
static void fillDriverInfo(QRhiDriverInfo *info, const VkPhysicalDeviceProperties &physDevProperties)
static VkBlendOp toVkBlendOp(QRhiGraphicsPipeline::BlendOp op)
static void qrhivk_releaseRenderBuffer(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static VkFrontFace toVkFrontFace(QRhiGraphicsPipeline::FrontFace f)
void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource, QRhiShaderResourceBinding::Type bindingType, int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
static VkFormat toVkTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
static VkCompareOp toVkCompareOp(QRhiGraphicsPipeline::CompareOp op)
static void fillRenderPassCreateInfo(VkRenderPassCreateInfo *rpInfo, VkSubpassDescription *subpassDesc, QVkRenderPassDescriptor *rpD)
static VkSamplerMipmapMode toVkMipmapMode(QRhiSampler::Filter f)
static void qrhivk_releaseSampler(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static constexpr bool isStencilTextureFormat(QRhiTexture::Format format)
static QVkRenderTargetData * maybeRenderTargetData(QVkCommandBuffer *cbD)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkTexture::UsageState &texUsage)
static VmaAllocation toVmaAllocation(QVkAlloc a)
static void addToChain(T *head, void *entry)
static void addSelfDependency(QVkRenderPassDescriptor *rpD)
static VkShaderStageFlagBits toVkShaderStage(QRhiShaderStage::Type type)
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS
static const int QVK_DESC_SETS_PER_POOL
static const int QVK_FRAMES_IN_FLIGHT
bool prepare(VkRenderPassCreateInfo *rpInfo, int multiViewCount, bool multiViewCap)
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
QRhiBuffer::NativeBuffer nativeBuffer() override
bool create() override
Creates the corresponding native graphics resources.
char * beginFullDynamicBufferUpdateForCurrentFrame() override
@ TransitionPassResources
@ DrawIndexedIndirectCount
uint currentSrbGeneration
int currentPassResTrackerIndex
uint currentPipelineGeneration
QVkGraphicsPipeline(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags, QRhiTexture::Format backingFormatHint)
QRhiTexture::Format backingFormat() const override
bool create() override
Creates the corresponding native graphics resources.
QVkTexture * backingTexture
const QRhiNativeHandles * nativeHandles() override
void updateSerializedFormat()
bool hasDepthStencilResolve
~QVkRenderPassDescriptor()
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVector< quint32 > serializedFormat() const override
QVkRenderPassDescriptor(QRhiImplementation *rhi)
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QVkRenderPassDescriptor * rp
static const int MAX_COLOR_ATTACHMENTS
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
void updateResources(UpdateFlags flags) override
QVkShaderResourceBindings(QRhiImplementation *rhi)
bool create() override
Creates the corresponding resource binding set.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
~QVkShaderResourceBindings()
bool createFrom(QRhiTexture *src) override
Sets up the shading rate map to use the texture src as the image containing the per-tile shading rate...
QVkShadingRateMap(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QSize pixelSize() const override
int sampleCount() const override
float devicePixelRatio() const override
~QVkSwapChainRenderTarget()
QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
@ ScImageUseTransferSource
QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
~QVkTextureRenderTarget()
float devicePixelRatio() const override
bool create() override
Creates the corresponding native graphics resources.
int sampleCount() const override
QSize pixelSize() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
VkImageView perLevelImageViewForLoadStore(int level)
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
void setNativeLayout(int layout) override
With some graphics APIs, such as Vulkan, integrating custom rendering code that uses the graphics API...
QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
NativeTexture nativeTexture() override
bool prepareCreate(QSize *adjustedSize=nullptr)