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);
583 if (!inst->isValid()) {
584 qWarning(
"Vulkan instance is not valid");
589 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
591 globalVulkanInstance = inst;
592 f = inst->functions();
593 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
594 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
595 const QByteArrayList extensions = inst->extensions();
596 for (
const char *ext : extensions)
597 qCDebug(QRHI_LOG_INFO,
" %s", ext);
601 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
603 QList<VkQueueFamilyProperties> queueFamilyProps;
604 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
605 uint32_t queueCount = 0;
606 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
607 queueFamilyProps.resize(
int(queueCount));
608 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
613 uint32_t physDevCount = 0;
614 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
616 qWarning(
"No physical devices");
619 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
620 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
621 if (err != VK_SUCCESS || !physDevCount) {
622 qWarning(
"Failed to enumerate physical devices: %d", err);
626 int physDevIndex = -1;
627 int requestedPhysDevIndex = -1;
628 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
629 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
631 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
632 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
633 for (
int i = 0; i <
int(physDevCount); ++i) {
634 if (physDevs[i] == requestedPhysDev) {
635 requestedPhysDevIndex = i;
641 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
642 for (
int i = 0; i <
int(physDevCount); ++i) {
643 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
644 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
645 requestedPhysDevIndex = i;
651 for (
int i = 0; i <
int(physDevCount); ++i) {
652 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
653 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
655 physDevProperties.deviceName,
656 VK_VERSION_MAJOR(physDevProperties.driverVersion),
657 VK_VERSION_MINOR(physDevProperties.driverVersion),
658 VK_VERSION_PATCH(physDevProperties.driverVersion),
659 VK_VERSION_MAJOR(physDevProperties.apiVersion),
660 VK_VERSION_MINOR(physDevProperties.apiVersion),
661 VK_VERSION_PATCH(physDevProperties.apiVersion),
662 physDevProperties.vendorID,
663 physDevProperties.deviceID,
664 physDevProperties.deviceType);
665 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
667 qCDebug(QRHI_LOG_INFO,
" using this physical device");
671 if (physDevIndex < 0) {
672 qWarning(
"No matching physical device");
675 physDev = physDevs[physDevIndex];
676 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
678 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
679 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
680 physDevProperties.deviceName,
681 VK_VERSION_MAJOR(physDevProperties.driverVersion),
682 VK_VERSION_MINOR(physDevProperties.driverVersion),
683 VK_VERSION_PATCH(physDevProperties.driverVersion),
684 VK_VERSION_MAJOR(physDevProperties.apiVersion),
685 VK_VERSION_MINOR(physDevProperties.apiVersion),
686 VK_VERSION_PATCH(physDevProperties.apiVersion),
687 physDevProperties.vendorID,
688 physDevProperties.deviceID,
689 physDevProperties.deviceType);
692 caps.apiVersion = inst->apiVersion();
698 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
699 VK_VERSION_MINOR(physDevProperties.apiVersion));
700 if (physDevApiVersion < caps.apiVersion) {
701 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
702 <<
"whereas the chosen physical device has" << physDevApiVersion
703 <<
"- restricting to the latter";
704 caps.apiVersion = physDevApiVersion;
709 QVulkanInfoVector<QVulkanExtension> devExts;
710 uint32_t devExtCount = 0;
711 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
713 QList<VkExtensionProperties> extProps(devExtCount);
714 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
715 for (
const VkExtensionProperties &p : std::as_const(extProps))
716 devExts.append({ p.extensionName, p.specVersion });
718 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
720 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
722 bool featuresQueried =
false;
724 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
725 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
728#ifdef VK_KHR_fragment_shading_rate
729 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
730 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
731 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
732 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
734#ifdef VK_EXT_device_fault
735 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
736 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
737 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
738 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
741 QVkPhysicalDevicePortabilitySubsetFeatures portabilitySubsetFeatures = {};
742 portabilitySubsetFeatures.sType = QVK_STRUCTURE_TYPE_PDPSF;
743 if (hasPhysDevProp2 && devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset")))
744 addToChain(&physDevFeaturesChainable, &portabilitySubsetFeatures);
749 if (!featuresQueried) {
751 if (caps.apiVersion >= QVersionNumber(1, 2)) {
752 physDevFeatures11IfApi12OrNewer = {};
753 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
754 physDevFeatures12 = {};
755 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
757 physDevFeatures13 = {};
758 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
760 physDevFeatures14 = {};
761 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
764 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
765 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
767 if (caps.apiVersion >= QVersionNumber(1, 3))
768 physDevFeatures12.pNext = &physDevFeatures13;
770 if (caps.apiVersion >= QVersionNumber(1, 4))
771 physDevFeatures13.pNext = &physDevFeatures14;
774 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
775 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
776 featuresQueried =
true;
783 if (!featuresQueried) {
791 if (caps.apiVersion == QVersionNumber(1, 1)) {
793 multiviewFeaturesIfApi11 = {};
794 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
795 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
798 shaderDrawParametersFeaturesIfApi11 = {};
799 shaderDrawParametersFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
800 addToChain(&physDevFeaturesChainable, &shaderDrawParametersFeaturesIfApi11);
802 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
803 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
804 featuresQueried =
true;
809 if (!featuresQueried) {
812 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
813 featuresQueried =
true;
821 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
822 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
823 queryQueueFamilyProps();
824 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
825 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
826 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
827 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
828 if (!gfxQueueFamilyIdxOpt.has_value()
829 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
830 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
832 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
833 gfxQueueFamilyIdxOpt = i;
834 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
835 computelessGfxQueueCandidateIdxOpt = i;
838 if (gfxQueueFamilyIdxOpt.has_value()) {
839 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
841 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
842 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
844 qWarning(
"No graphics (or no graphics+present) queue family found");
849 VkDeviceQueueCreateInfo queueInfo = {};
850 const float prio[] = { 0 };
851 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
852 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
853 queueInfo.queueCount = 1;
854 queueInfo.pQueuePriorities = prio;
856 QList<
const char *> requestedDevExts;
857 requestedDevExts.append(
"VK_KHR_swapchain");
859 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
860 if (hasPhysDevProp2) {
861 requestedDevExts.append(
"VK_KHR_portability_subset");
863 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
864 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
869#ifdef VK_EXT_vertex_attribute_divisor
870 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
871 if (hasPhysDevProp2) {
872 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
873 caps.vertexAttribDivisor =
true;
878#ifdef VK_KHR_create_renderpass2
879 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
883 bool canEnable =
true;
884 if (caps.apiVersion < QVersionNumber(1, 1)) {
885 canEnable = hasPhysDevProp2
886 && devExts.contains(QByteArrayLiteral(
"VK_KHR_multiview"))
887 && devExts.contains(QByteArrayLiteral(
"VK_KHR_maintenance2"));
889 requestedDevExts.append(
"VK_KHR_multiview");
890 requestedDevExts.append(
"VK_KHR_maintenance2");
894 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
895 caps.renderPass2KHR =
true;
900#ifdef VK_KHR_depth_stencil_resolve
902 const bool hasRenderPass2Dep = caps.renderPass2KHR || caps.apiVersion >= QVersionNumber(1, 2);
903 if (hasRenderPass2Dep && devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
904 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
905 caps.depthStencilResolveKHR =
true;
910#ifdef VK_KHR_fragment_shading_rate
912 const bool hasRenderPass2Dep = caps.renderPass2KHR || caps.apiVersion >= QVersionNumber(1, 2);
913 if (hasRenderPass2Dep && devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
914 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
918#ifdef VK_EXT_device_fault
919 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
920 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
921 caps.deviceFault =
true;
925 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
926 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
927 if (devExts.contains(ext)) {
928 requestedDevExts.append(ext.constData());
930 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
936 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
937 for (
const QByteArray &ext : envExtList) {
938 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
939 if (devExts.contains(ext)) {
940 requestedDevExts.append(ext.constData());
942 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
948 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
949 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
950 for (
const char *ext : std::as_const(requestedDevExts))
951 qCDebug(QRHI_LOG_INFO,
" %s", ext);
954 VkDeviceCreateInfo devInfo = {};
955 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
956 devInfo.queueCreateInfoCount = 1;
957 devInfo.pQueueCreateInfos = &queueInfo;
959 devInfo.enabledLayerCount = 0;
960 devInfo.ppEnabledLayerNames =
nullptr;
961 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
962 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
978 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
981 physDevFeatures13.robustImageAccess = VK_FALSE;
985 if (caps.apiVersion >= QVersionNumber(1, 1)) {
992 devInfo.pNext = &physDevFeaturesChainable;
996 physDevFeatures.robustBufferAccess = VK_FALSE;
997 devInfo.pEnabledFeatures = &physDevFeatures;
1000 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
1001 if (err != VK_SUCCESS) {
1002 qWarning(
"Failed to create device: %d", err);
1006 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
1011 caps.deviceFault =
true;
1012 caps.vertexAttribDivisor =
true;
1013 caps.renderPass2KHR =
true;
1014 caps.depthStencilResolveKHR =
true;
1017 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
1018 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
1019 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
1020 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
1021 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
1022 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
1024 df = inst->deviceFunctions(dev);
1026 VkCommandPoolCreateInfo poolInfo = {};
1027 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1028 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
1030 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
1031 if (err != VK_SUCCESS) {
1032 qWarning(
"Failed to create command pool: %d", err);
1037 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
1038 gfxQueueFamilyIdx, gfxQueueIdx);
1041 if (gfxQueueFlags && caps.apiVersion >= QVersionNumber(1, 1)) {
1042 VkDeviceQueueInfo2 queueInfo = {};
1043 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
1044 queueInfo.flags = gfxQueueFlags;
1045 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
1046 queueInfo.queueIndex = gfxQueueIdx;
1047 df->vkGetDeviceQueue2(dev, &queueInfo, &gfxQueue);
1050 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
1052 if (queueFamilyProps.isEmpty())
1053 queryQueueFamilyProps();
1055 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
1056 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
1058 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
1061 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
1063 caps.depthClamp = physDevFeatures.depthClamp;
1065 caps.wideLines = physDevFeatures.wideLines;
1067 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
1069 caps.tessellation = physDevFeatures.tessellationShader;
1070 caps.geometryShader = physDevFeatures.geometryShader;
1072 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
1074 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
1076#ifdef VK_VERSION_1_2
1077 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1078 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1079 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
1082 caps.drawIndirectCount = physDevFeatures12.drawIndirectCount && caps.drawIndirectMulti;
1086#ifdef VK_VERSION_1_1
1087 if (caps.apiVersion == QVersionNumber(1, 1)) {
1088 caps.multiView = multiviewFeaturesIfApi11.multiview;
1089 caps.shaderDrawParameters = shaderDrawParametersFeaturesIfApi11.shaderDrawParameters;
1093#ifdef VK_KHR_fragment_shading_rate
1094 fragmentShadingRates.clear();
1095 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1096 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1097 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1098 if (caps.imageBasedShadingRate) {
1099 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1100 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1101 VkPhysicalDeviceProperties2 props2 = {};
1102 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1103 props2.pNext = &shadingRateProps;
1104 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1105 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1108 if (caps.perDrawShadingRate) {
1109 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1110 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1111 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1112 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1114 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1115 fragmentShadingRates.resize(count);
1116 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1118 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1120 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1122 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1123 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1132#ifdef VK_KHR_create_renderpass2
1133 if (caps.renderPass2KHR) {
1134 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1135 if (!vkCreateRenderPass2KHR)
1136 caps.renderPass2KHR =
false;
1140#ifdef VK_VERSION_1_2
1141 if (caps.drawIndirectCount) {
1142 vkCmdDrawIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndirectCount>(
1143 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndirectCount"));
1144 vkCmdDrawIndexedIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirectCount>(
1145 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndexedIndirectCount"));
1146 if (!vkCmdDrawIndirectCount || !vkCmdDrawIndexedIndirectCount) {
1147 qWarning(
"Failed to resolve vkCmdDrawIndirectCount/vkCmdDrawIndexedIndirectCount; disabling DrawIndirectCount feature.");
1148 caps.drawIndirectCount =
false;
1155 adapterLuidValid =
false;
1157#ifdef VK_VERSION_1_2
1158 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1159 VkPhysicalDeviceVulkan11Properties v11props = {};
1160 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1161 VkPhysicalDeviceProperties2 props2 = {};
1162 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1163 props2.pNext = &v11props;
1164 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1165 if (v11props.deviceLUIDValid) {
1166 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1167 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1168 adapterLuidValid =
true;
1169 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1170 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1171 adapterLuid.LowPart, adapterLuid.HighPart);
1178 VmaVulkanFunctions funcs = {};
1179 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1180 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1182 VmaAllocatorCreateInfo allocatorInfo = {};
1185 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1186 allocatorInfo.physicalDevice = physDev;
1187 allocatorInfo.device = dev;
1188 allocatorInfo.pVulkanFunctions = &funcs;
1189 allocatorInfo.instance = inst->vkInstance();
1197#ifdef VK_VERSION_1_4
1198 if (caps.apiVersion >= QVersionNumber(1, 4))
1199 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1202#ifdef VK_VERSION_1_3
1203 if (caps.apiVersion >= QVersionNumber(1, 3))
1204 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1207#ifdef VK_VERSION_1_2
1208 if (caps.apiVersion >= QVersionNumber(1, 2))
1209 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1212#ifdef VK_VERSION_1_1
1213 if (caps.apiVersion >= QVersionNumber(1, 1))
1214 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1217#ifdef VK_VERSION_1_0
1218 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1221 VmaAllocator vmaallocator;
1222 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1223 if (err != VK_SUCCESS) {
1224 qWarning(
"Failed to create allocator: %d", err);
1230 inst->installDebugOutputFilter(qvk_debug_filter);
1232 VkDescriptorPool pool;
1233 VkResult err = createDescriptorPool(&pool);
1234 if (err == VK_SUCCESS)
1235 descriptorPools.append(pool);
1237 qWarning(
"Failed to create initial descriptor pool: %d", err);
1239 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1240 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1241 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1243 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1244 if (err != VK_SUCCESS) {
1245 qWarning(
"Failed to create timestamp query pool: %d", err);
1248 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1249 timestampQueryPoolMap.fill(
false);
1251#ifdef VK_EXT_debug_utils
1252 if (caps.debugUtils) {
1253 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1254 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1255 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1256 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1260#ifdef VK_EXT_device_fault
1261 if (caps.deviceFault) {
1262 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1268 nativeHandlesStruct.physDev = physDev;
1269 nativeHandlesStruct.dev = dev;
1270 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1271 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1272 nativeHandlesStruct.gfxQueueFlags = gfxQueueFlags;
1273 nativeHandlesStruct.gfxQueue = gfxQueue;
1274 nativeHandlesStruct.vmemAllocator = allocator;
1275 nativeHandlesStruct.inst = inst;
1286 df->vkQueueWaitIdle(gfxQueue);
1293 dxgiHdrInfo =
nullptr;
1297 if (ofr.cmdFence[i]) {
1298 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1299 ofr.cmdFence[i] = VK_NULL_HANDLE;
1301 ofr.cmdFenceWaitable[i] =
false;
1304 if (pipelineCache) {
1305 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1306 pipelineCache = VK_NULL_HANDLE;
1309 for (
const DescriptorPoolData &pool : descriptorPools)
1310 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1312 descriptorPools.clear();
1314 if (timestampQueryPool) {
1315 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1316 timestampQueryPool = VK_NULL_HANDLE;
1320 vmaDestroyAllocator(toVmaAllocator(allocator));
1326 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1327 cmdPool[i] = VK_NULL_HANDLE;
1329 freeSecondaryCbs[i].clear();
1330 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1333 if (!importedDevice && dev) {
1334 df->vkDestroyDevice(dev,
nullptr);
1335 inst->resetDeviceFunctions(dev);
1336 dev = VK_NULL_HANDLE;
1346QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1348 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1349 if (nativeHandles) {
1350 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1351 requestedPhysDev = h->physDev;
1354 QRhi::AdapterList list;
1355 QVulkanFunctions *f = inst->functions();
1356 uint32_t physDevCount = 0;
1357 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1361 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1362 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1363 if (err != VK_SUCCESS || !physDevCount)
1366 VkPhysicalDeviceProperties physDevProperties = {};
1367 for (uint32_t i = 0; i < physDevCount; ++i) {
1368 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1371 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1372 QVulkanAdapter *a =
new QVulkanAdapter;
1373 a->physDev = physDevs[i];
1374 fillDriverInfo(&a->adapterInfo, physDevProperties);
1388 VkDescriptorPoolSize descPoolSizes[] = {
1389 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1390 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1391 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1392 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1393 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1394 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1395 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1397 VkDescriptorPoolCreateInfo descPoolInfo = {};
1398 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1402 descPoolInfo.flags = 0;
1404 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1405 descPoolInfo.pPoolSizes = descPoolSizes;
1406 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1411 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1412 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1413 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1414 if (r == VK_SUCCESS)
1415 descriptorPools[poolIndex].refCount += 1;
1419 int lastPoolIdx = descriptorPools.size() - 1;
1420 for (
int i = lastPoolIdx; i >= 0; --i) {
1421 if (descriptorPools[i].refCount == 0) {
1422 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1423 descriptorPools[i].allocedDescSets = 0;
1425 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1426 VkResult err = tryAllocate(i);
1427 if (err == VK_SUCCESS) {
1428 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1429 *resultPoolIndex = i;
1435 VkDescriptorPool newPool;
1436 VkResult poolErr = createDescriptorPool(&newPool);
1437 if (poolErr == VK_SUCCESS) {
1438 descriptorPools.append(newPool);
1439 lastPoolIdx = descriptorPools.size() - 1;
1440 VkResult err = tryAllocate(lastPoolIdx);
1441 if (err != VK_SUCCESS) {
1442 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1445 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1446 *resultPoolIndex = lastPoolIdx;
1449 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1456 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1458 case QRhiTexture::RGBA8:
1459 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1460 case QRhiTexture::BGRA8:
1461 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1462 case QRhiTexture::R8:
1463 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1464 case QRhiTexture::RG8:
1465 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1466 case QRhiTexture::R16:
1467 return VK_FORMAT_R16_UNORM;
1468 case QRhiTexture::RG16:
1469 return VK_FORMAT_R16G16_UNORM;
1470 case QRhiTexture::RED_OR_ALPHA8:
1471 return VK_FORMAT_R8_UNORM;
1473 case QRhiTexture::RGBA16F:
1474 return VK_FORMAT_R16G16B16A16_SFLOAT;
1475 case QRhiTexture::RGBA32F:
1476 return VK_FORMAT_R32G32B32A32_SFLOAT;
1477 case QRhiTexture::R16F:
1478 return VK_FORMAT_R16_SFLOAT;
1479 case QRhiTexture::R32F:
1480 return VK_FORMAT_R32_SFLOAT;
1482 case QRhiTexture::RGB10A2:
1484 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1486 case QRhiTexture::R8SI:
1487 return VK_FORMAT_R8_SINT;
1488 case QRhiTexture::R32SI:
1489 return VK_FORMAT_R32_SINT;
1490 case QRhiTexture::RG32SI:
1491 return VK_FORMAT_R32G32_SINT;
1492 case QRhiTexture::RGBA32SI:
1493 return VK_FORMAT_R32G32B32A32_SINT;
1495 case QRhiTexture::R8UI:
1496 return VK_FORMAT_R8_UINT;
1497 case QRhiTexture::R32UI:
1498 return VK_FORMAT_R32_UINT;
1499 case QRhiTexture::RG32UI:
1500 return VK_FORMAT_R32G32_UINT;
1501 case QRhiTexture::RGBA32UI:
1502 return VK_FORMAT_R32G32B32A32_UINT;
1504 case QRhiTexture::D16:
1505 return VK_FORMAT_D16_UNORM;
1506 case QRhiTexture::D24:
1507 return VK_FORMAT_X8_D24_UNORM_PACK32;
1508 case QRhiTexture::D24S8:
1509 return VK_FORMAT_D24_UNORM_S8_UINT;
1510 case QRhiTexture::D32F:
1511 return VK_FORMAT_D32_SFLOAT;
1512 case QRhiTexture::D32FS8:
1513 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1515 case QRhiTexture::BC1:
1516 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1517 case QRhiTexture::BC2:
1518 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1519 case QRhiTexture::BC3:
1520 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1521 case QRhiTexture::BC4:
1522 return VK_FORMAT_BC4_UNORM_BLOCK;
1523 case QRhiTexture::BC5:
1524 return VK_FORMAT_BC5_UNORM_BLOCK;
1525 case QRhiTexture::BC6H:
1526 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1527 case QRhiTexture::BC7:
1528 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1530 case QRhiTexture::ETC2_RGB8:
1531 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1532 case QRhiTexture::ETC2_RGB8A1:
1533 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1534 case QRhiTexture::ETC2_RGBA8:
1535 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1537 case QRhiTexture::ASTC_4x4:
1538 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1539 case QRhiTexture::ASTC_5x4:
1540 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1541 case QRhiTexture::ASTC_5x5:
1542 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1543 case QRhiTexture::ASTC_6x5:
1544 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1545 case QRhiTexture::ASTC_6x6:
1546 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1547 case QRhiTexture::ASTC_8x5:
1548 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1549 case QRhiTexture::ASTC_8x6:
1550 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1551 case QRhiTexture::ASTC_8x8:
1552 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1553 case QRhiTexture::ASTC_10x5:
1554 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1555 case QRhiTexture::ASTC_10x6:
1556 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1557 case QRhiTexture::ASTC_10x8:
1558 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1559 case QRhiTexture::ASTC_10x10:
1560 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1561 case QRhiTexture::ASTC_12x10:
1562 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1563 case QRhiTexture::ASTC_12x12:
1564 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1567 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1574 case VK_FORMAT_R8G8B8A8_UNORM:
1575 return QRhiTexture::RGBA8;
1576 case VK_FORMAT_R8G8B8A8_SRGB:
1578 (*flags) |= QRhiTexture::sRGB;
1579 return QRhiTexture::RGBA8;
1580 case VK_FORMAT_B8G8R8A8_UNORM:
1581 return QRhiTexture::BGRA8;
1582 case VK_FORMAT_B8G8R8A8_SRGB:
1584 (*flags) |= QRhiTexture::sRGB;
1585 return QRhiTexture::BGRA8;
1586 case VK_FORMAT_R16G16B16A16_SFLOAT:
1587 return QRhiTexture::RGBA16F;
1588 case VK_FORMAT_R32G32B32A32_SFLOAT:
1589 return QRhiTexture::RGBA32F;
1590 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1591 return QRhiTexture::RGB10A2;
1593 qWarning(
"VkFormat %d cannot be read back", format);
1596 return QRhiTexture::UnknownFormat;
1602 case QRhiTexture::Format::D16:
1603 case QRhiTexture::Format::D24:
1604 case QRhiTexture::Format::D24S8:
1605 case QRhiTexture::Format::D32F:
1606 case QRhiTexture::Format::D32FS8:
1617 case QRhiTexture::Format::D24S8:
1618 case QRhiTexture::Format::D32FS8:
1628 if (isDepthTextureFormat(format)) {
1629 if (isStencilTextureFormat(format))
1630 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1632 return VK_IMAGE_ASPECT_DEPTH_BIT;
1634 return VK_IMAGE_ASPECT_COLOR_BIT;
1645 VkPhysicalDeviceMemoryProperties physDevMemProps;
1646 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1648 VkMemoryRequirements memReq;
1649 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1650 uint32_t memTypeIndex = uint32_t(-1);
1652 if (memReq.memoryTypeBits) {
1654 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1655 bool foundDevLocal =
false;
1656 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1657 if (memReq.memoryTypeBits & (1 << i)) {
1658 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1659 if (!foundDevLocal) {
1660 foundDevLocal =
true;
1663 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1672 return memTypeIndex;
1676 const QSize &pixelSize,
1677 VkImageUsageFlags usage,
1678 VkImageAspectFlags aspectMask,
1679 VkSampleCountFlagBits samples,
1680 VkDeviceMemory *mem,
1685 VkMemoryRequirements memReq;
1688 *mem = VK_NULL_HANDLE;
1689 for (
int i = 0; i < count; ++i) {
1690 images[i] = VK_NULL_HANDLE;
1691 views[i] = VK_NULL_HANDLE;
1694 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1695 for (
int i = 0; i < count; ++i) {
1697 df->vkDestroyImageView(dev, views[i],
nullptr);
1698 views[i] = VK_NULL_HANDLE;
1701 df->vkDestroyImage(dev, images[i],
nullptr);
1702 images[i] = VK_NULL_HANDLE;
1706 df->vkFreeMemory(dev, *mem,
nullptr);
1707 *mem = VK_NULL_HANDLE;
1711 for (
int i = 0; i < count; ++i) {
1712 VkImageCreateInfo imgInfo = {};
1713 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1714 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1715 imgInfo.format = format;
1716 imgInfo.extent.width = uint32_t(pixelSize.width());
1717 imgInfo.extent.height = uint32_t(pixelSize.height());
1718 imgInfo.extent.depth = 1;
1719 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1720 imgInfo.samples = samples;
1721 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1722 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1723 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1725 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1726 if (err != VK_SUCCESS) {
1727 qWarning(
"Failed to create image: %d", err);
1734 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1737 VkMemoryAllocateInfo memInfo = {};
1738 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1739 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1741 uint32_t startIndex = 0;
1743 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1744 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1745 qWarning(
"No suitable memory type found");
1748 startIndex = memInfo.memoryTypeIndex + 1;
1749 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1750 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1751 qWarning(
"Failed to allocate image memory: %d", err);
1754 }
while (err != VK_SUCCESS);
1756 VkDeviceSize ofs = 0;
1757 for (
int i = 0; i < count; ++i) {
1758 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1759 if (err != VK_SUCCESS) {
1760 qWarning(
"Failed to bind image memory: %d", err);
1763 ofs += aligned(memReq.size, memReq.alignment);
1765 VkImageViewCreateInfo imgViewInfo = {};
1766 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1767 imgViewInfo.image = images[i];
1768 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1769 imgViewInfo.format = format;
1770 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1771 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1772 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1773 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1774 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1775 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1777 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1778 if (err != VK_SUCCESS) {
1779 qWarning(
"Failed to create image view: %d", err);
1790 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1791 return optimalDsFormat;
1793 const VkFormat dsFormatCandidates[] = {
1794 VK_FORMAT_D24_UNORM_S8_UINT,
1795 VK_FORMAT_D32_SFLOAT_S8_UINT,
1796 VK_FORMAT_D16_UNORM_S8_UINT
1798 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1799 int dsFormatIdx = 0;
1800 while (dsFormatIdx < dsFormatCandidateCount) {
1801 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1802 VkFormatProperties fmtProp;
1803 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1804 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1808 if (dsFormatIdx == dsFormatCandidateCount)
1809 qWarning(
"Failed to find an optimal depth-stencil format");
1811 return optimalDsFormat;
1816 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1818 if (multiViewCount < 2)
1820 if (!multiViewCap) {
1821 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1824#ifdef VK_VERSION_1_1
1825 uint32_t allViewsMask = 0;
1826 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1827 allViewsMask |= (1 << i);
1828 multiViewMask = allViewsMask;
1829 multiViewCorrelationMask = allViewsMask;
1830 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1831 multiViewInfo.subpassCount = 1;
1832 multiViewInfo.pViewMasks = &multiViewMask;
1833 multiViewInfo.correlationMaskCount = 1;
1834 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1835 rpInfo->pNext = &multiViewInfo;
1840#ifdef VK_VERSION_1_1
1847#ifdef VK_KHR_create_renderpass2
1851struct RenderPass2SetupHelper
1853 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1855 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1859 if (multiViewCount >= 2) {
1860 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1861 viewMask |= (1 << i);
1864 attDescs2.resize(rpInfo->attachmentCount);
1865 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1866 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1867 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1869 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1870 att2.flags = att.flags;
1871 att2.format = att.format;
1872 att2.samples = att.samples;
1873 att2.loadOp = att.loadOp;
1874 att2.storeOp = att.storeOp;
1875 att2.stencilLoadOp = att.stencilLoadOp;
1876 att2.stencilStoreOp = att.stencilStoreOp;
1877 att2.initialLayout = att.initialLayout;
1878 att2.finalLayout = att.finalLayout;
1883 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1884 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1885 subpass2.flags = subpassDesc.flags;
1886 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1887 if (multiViewCount >= 2)
1888 subpass2.viewMask = viewMask;
1891 qsizetype startIndex = attRefs2.count();
1892 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1893 attRefs2.append({});
1894 VkAttachmentReference2KHR &attref2(attRefs2.last());
1895 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1896 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1897 attref2.attachment = attref.attachment;
1898 attref2.layout = attref.layout;
1899 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1901 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1902 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1905 if (subpassDesc.pResolveAttachments) {
1906 startIndex = attRefs2.count();
1907 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1908 attRefs2.append({});
1909 VkAttachmentReference2KHR &attref2(attRefs2.last());
1910 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1911 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1912 attref2.attachment = attref.attachment;
1913 attref2.layout = attref.layout;
1914 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1916 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1920 if (subpassDesc.pDepthStencilAttachment) {
1921 startIndex = attRefs2.count();
1922 attRefs2.append({});
1923 VkAttachmentReference2KHR &attref2(attRefs2.last());
1924 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1925 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1926 attref2.attachment = attref.attachment;
1927 attref2.layout = attref.layout;
1928 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1929 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1933#ifdef VK_KHR_depth_stencil_resolve
1935 if (rpD->hasDepthStencilResolve) {
1936 startIndex = attRefs2.count();
1937 attRefs2.append({});
1938 VkAttachmentReference2KHR &attref2(attRefs2.last());
1939 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1940 attref2.attachment = rpD->dsResolveRef.attachment;
1941 attref2.layout = rpD->dsResolveRef.layout;
1942 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1943 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1944 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1945 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1946 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1947 addToChain(&subpass2, &dsResolveDesc);
1951#ifdef VK_KHR_fragment_shading_rate
1952 shadingRateAttInfo = {};
1953 if (rpD->hasShadingRateMap) {
1954 startIndex = attRefs2.count();
1955 attRefs2.append({});
1956 VkAttachmentReference2KHR &attref2(attRefs2.last());
1957 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1958 attref2.attachment = rpD->shadingRateRef.attachment;
1959 attref2.layout = rpD->shadingRateRef.layout;
1960 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1961 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1962 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1963 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1964 addToChain(&subpass2, &shadingRateAttInfo);
1970 subpassDeps2.clear();
1971 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1972 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1973 subpassDeps2.append({});
1974 VkSubpassDependency2 &dep2(subpassDeps2.last());
1975 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1976 dep2.srcSubpass = dep.srcSubpass;
1977 dep2.dstSubpass = dep.dstSubpass;
1978 dep2.srcStageMask = dep.srcStageMask;
1979 dep2.dstStageMask = dep.dstStageMask;
1980 dep2.srcAccessMask = dep.srcAccessMask;
1981 dep2.dstAccessMask = dep.dstAccessMask;
1982 dep2.dependencyFlags = dep.dependencyFlags;
1985 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1986 rpInfo2->pNext =
nullptr;
1987 rpInfo2->flags = rpInfo->flags;
1988 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1989 rpInfo2->pAttachments = attDescs2.constData();
1990 rpInfo2->subpassCount = 1;
1991 rpInfo2->pSubpasses = &subpass2;
1992 rpInfo2->dependencyCount = subpassDeps2.count();
1993 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1994 if (multiViewCount >= 2) {
1995 rpInfo2->correlatedViewMaskCount = 1;
1996 rpInfo2->pCorrelatedViewMasks = &viewMask;
2002 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
2003 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
2004 VkSubpassDescription2KHR subpass2;
2005 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
2006#ifdef VK_KHR_depth_stencil_resolve
2007 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
2009#ifdef VK_KHR_fragment_shading_rate
2010 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
2017 VkSubpassDescription *subpassDesc,
2020 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
2021 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
2022 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
2023 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
2024 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
2025 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
2027 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
2028 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
2029 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
2030 rpInfo->pAttachments = rpD->attDescs.constData();
2031 rpInfo->subpassCount = 1;
2032 rpInfo->pSubpasses = subpassDesc;
2033 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
2034 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
2038 bool hasDepthStencil,
2039 VkSampleCountFlagBits samples,
2040 VkFormat colorFormat,
2041 QRhiShadingRateMap *shadingRateMap)
2045 VkAttachmentDescription attDesc = {};
2046 attDesc.format = colorFormat;
2047 attDesc.samples = samples;
2048 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2049 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2050 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2051 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2052 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2053 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2054 rpD->attDescs.append(attDesc);
2056 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2061 rpD->multiViewCount = 0;
2063 if (hasDepthStencil) {
2067 attDesc.format = optimalDepthStencilFormat();
2068 attDesc.samples = samples;
2069 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2070 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2071 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2072 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2073 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2074 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2075 rpD->attDescs.append(attDesc);
2077 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2082 if (samples > VK_SAMPLE_COUNT_1_BIT) {
2084 attDesc.format = colorFormat;
2085 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2086 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2087 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2088 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2089 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2090 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2091 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2092 rpD->attDescs.append(attDesc);
2094 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2097 rpD->dsResolveRef = {};
2099 rpD->shadingRateRef = {};
2100#ifdef VK_KHR_fragment_shading_rate
2101 if (shadingRateMap) {
2103 attDesc.format = VK_FORMAT_R8_UINT;
2104 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2105 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2106 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2107 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2108 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2109 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2110 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2111 rpD->attDescs.append(attDesc);
2113 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2118 VkSubpassDependency subpassDep = {};
2119 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2120 subpassDep.dstSubpass = 0;
2121 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2122 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2123 subpassDep.srcAccessMask = 0;
2124 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2125 rpD->subpassDeps.append(subpassDep);
2126 if (hasDepthStencil) {
2127 memset(&subpassDep, 0,
sizeof(subpassDep));
2128 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2129 subpassDep.dstSubpass = 0;
2130 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2131 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2132 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2133 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2134 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2135 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2136 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2137 rpD->subpassDeps.append(subpassDep);
2140 VkRenderPassCreateInfo rpInfo;
2141 VkSubpassDescription subpassDesc;
2142 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2144#ifdef VK_KHR_create_renderpass2
2145 if (caps.renderPass2KHR) {
2147 VkRenderPassCreateInfo2KHR rpInfo2;
2148 RenderPass2SetupHelper rp2Helper(
this);
2149 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2151 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2152 if (err != VK_SUCCESS) {
2153 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2160 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2161 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2162 if (err != VK_SUCCESS) {
2163 qWarning(
"Failed to create renderpass: %d", err);
2172 const QRhiColorAttachment *colorAttachmentsBegin,
2173 const QRhiColorAttachment *colorAttachmentsEnd,
2177 QRhiRenderBuffer *depthStencilBuffer,
2178 QRhiTexture *depthTexture,
2179 QRhiTexture *depthResolveTexture,
2181 QRhiShadingRateMap *shadingRateMap)
2185 int multiViewCount = 0;
2186 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2189 Q_ASSERT(texD || rbD);
2190 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2191 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2193 VkAttachmentDescription attDesc = {};
2194 attDesc.format = vkformat;
2195 attDesc.samples = samples;
2196 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2197 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2198 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2199 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2201 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2202 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2203 rpD->attDescs.append(attDesc);
2205 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2206 rpD->colorRefs.append(ref);
2208 if (it->multiViewCount() >= 2) {
2209 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2210 qWarning(
"Inconsistent multiViewCount in color attachment set");
2212 multiViewCount = it->multiViewCount();
2213 }
else if (multiViewCount > 0) {
2214 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2217 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2218 rpD->multiViewCount = uint32_t(multiViewCount);
2222 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2223 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2224 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2225 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2226 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2227 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2228 VkAttachmentDescription attDesc = {};
2229 attDesc.format = dsFormat;
2230 attDesc.samples = samples;
2231 attDesc.loadOp = loadOp;
2232 attDesc.storeOp = storeOp;
2233 attDesc.stencilLoadOp = loadOp;
2234 attDesc.stencilStoreOp = storeOp;
2235 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2236 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2237 rpD->attDescs.append(attDesc);
2238 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2239 multiViewCount = depthTexture->arraySize();
2240 rpD->multiViewCount = multiViewCount;
2242 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2247 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2248 if (it->resolveTexture()) {
2250 const VkFormat dstFormat = rtexD->vkformat;
2251 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2252 qWarning(
"Resolving into a multisample texture is not supported");
2256 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2257 if (srcFormat != dstFormat) {
2261 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2262 int(srcFormat),
int(dstFormat));
2265 VkAttachmentDescription attDesc = {};
2266 attDesc.format = rtexD->viewFormat;
2267 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2268 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2269 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2270 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2271 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2272 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2273 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2274 rpD->attDescs.append(attDesc);
2276 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2277 rpD->resolveRefs.append(ref);
2279 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2280 rpD->resolveRefs.append(ref);
2283 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2288 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2289 qWarning(
"Resolving into a multisample depth texture is not supported");
2290 const VkFormat dstFormat = rtexD->vkformat;
2294 Q_ASSERT(texD || rbD);
2295 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2296 if (srcFormat != dstFormat) {
2297 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2298 int(srcFormat),
int(dstFormat));
2301 VkAttachmentDescription attDesc = {};
2302 attDesc.format = rtexD->viewFormat;
2303 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2304 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2305 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2306 attDesc.stencilLoadOp = attDesc.loadOp;
2307 attDesc.stencilStoreOp = attDesc.storeOp;
2308 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2309 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2310 rpD->attDescs.append(attDesc);
2311 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2313 rpD->dsResolveRef = {};
2317 rpD->shadingRateRef = {};
2318#ifdef VK_KHR_fragment_shading_rate
2319 if (shadingRateMap) {
2320 VkAttachmentDescription attDesc = {};
2321 attDesc.format = VK_FORMAT_R8_UINT;
2322 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2323 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2324 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2325 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2326 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2327 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2328 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2329 rpD->attDescs.append(attDesc);
2330 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2335 VkSubpassDependency selfDependency = {};
2336 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2337 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2338 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2339 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2340 selfDependency.srcSubpass = 0;
2341 selfDependency.dstSubpass = 0;
2342 selfDependency.srcStageMask = stageMask;
2343 selfDependency.dstStageMask = stageMask;
2344 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2345 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2346 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2347#ifdef VK_VERSION_1_1
2348 if (rpD->multiViewCount >= 2)
2349 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2351 selfDependency.dependencyFlags = depFlags;
2352 rpD->subpassDeps.append(selfDependency);
2359 VkRenderPassCreateInfo rpInfo;
2360 VkSubpassDescription subpassDesc;
2361 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2364 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2367#ifdef VK_KHR_create_renderpass2
2368 if (caps.renderPass2KHR) {
2370 VkRenderPassCreateInfo2KHR rpInfo2;
2371 RenderPass2SetupHelper rp2Helper(
this);
2372 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2375 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2376 if (err != VK_SUCCESS) {
2377 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2384 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2385 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2388 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2389 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2390 if (err != VK_SUCCESS) {
2391 qWarning(
"Failed to create renderpass: %d", err);
2402 if (swapChainD->pixelSize.isEmpty()) {
2403 qWarning(
"Surface size is 0, cannot create swapchain");
2408 df->vkQueueWaitIdle(gfxQueue);
2410 if (!vkCreateSwapchainKHR) {
2411 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2412 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2413 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2414 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2415 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2416 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2417 qWarning(
"Swapchain functions not available");
2422 VkSurfaceCapabilitiesKHR surfaceCaps;
2423 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2424 quint32 reqBufferCount;
2425 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2426 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2428 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2430 VkSurfaceTransformFlagBitsKHR preTransform =
2431 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2432 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2433 : surfaceCaps.currentTransform;
2459 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2460 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2461 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2462 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2464 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2465 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2466 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2467 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2468 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2469 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2470 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2471 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2472 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2473 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2476 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2477 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2478 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2479 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2481 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2482 && surfaceCaps.maxImageArrayLayers > 1;
2485 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2486 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2490 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2491 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2492 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2493 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2501 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2503 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2504 reuseExisting ?
"recycled" :
"new",
2505 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2507 VkSwapchainCreateInfoKHR swapChainInfo = {};
2508 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2509 swapChainInfo.surface = swapChainD->surface;
2510 swapChainInfo.minImageCount = reqBufferCount;
2511 swapChainInfo.imageFormat = swapChainD->colorFormat;
2512 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2513 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2514 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2515 swapChainInfo.imageUsage = usage;
2516 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2517 swapChainInfo.preTransform = preTransform;
2518 swapChainInfo.compositeAlpha = compositeAlpha;
2519 swapChainInfo.presentMode = presentMode;
2520 swapChainInfo.clipped =
true;
2521 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2523 VkSwapchainKHR newSwapChain;
2524 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2525 if (err != VK_SUCCESS) {
2526 qWarning(
"Failed to create swapchain: %d", err);
2529 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2534 swapChainD->sc = newSwapChain;
2535 swapChainD->lastConnectedSurface = swapChainD->surface;
2537 quint32 actualSwapChainBufferCount = 0;
2538 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2539 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2540 qWarning(
"Failed to get swapchain images: %d", err);
2544 if (actualSwapChainBufferCount != reqBufferCount)
2545 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2548 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2549 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2550 if (err != VK_SUCCESS) {
2551 qWarning(
"Failed to get swapchain images: %d", err);
2555 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2556 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2557 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2558 if (!createTransientImage(swapChainD->colorFormat,
2559 swapChainD->pixelSize,
2560 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2561 VK_IMAGE_ASPECT_COLOR_BIT,
2562 swapChainD->samples,
2563 &swapChainD->msaaImageMem,
2566 swapChainD->bufferCount))
2568 qWarning(
"Failed to create transient image for MSAA color buffer");
2573 VkFenceCreateInfo fenceInfo = {};
2574 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2575 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2578 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2582 image.image = swapChainImages[i];
2583 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2584 image.msaaImage = msaaImages[i];
2585 image.msaaImageView = msaaViews[i];
2588 VkImageViewCreateInfo imgViewInfo = {};
2589 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2590 imgViewInfo.image = swapChainImages[i];
2591 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2592 imgViewInfo.format = swapChainD->colorFormat;
2593 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2594 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2595 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2596 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2597 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2598 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2599 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2600 if (err != VK_SUCCESS) {
2601 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2607 VkSemaphoreCreateInfo semInfo = {};
2608 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2609 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2614 image.image = swapChainImages[i];
2615 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2616 image.msaaImage = msaaImages[i];
2617 image.msaaImageView = msaaViews[i];
2620 VkImageViewCreateInfo imgViewInfo = {};
2621 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2622 imgViewInfo.image = swapChainImages[i];
2623 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2624 imgViewInfo.format = swapChainD->colorFormat;
2625 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2626 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2627 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2628 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2629 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2630 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2631 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2632 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2633 if (err != VK_SUCCESS) {
2634 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2638 VkSemaphoreCreateInfo semInfo = {};
2639 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2640 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2646 swapChainD->currentImageIndex = 0;
2648 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2650 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2651 VkImageViewCreateInfo viewInfo = {};
2652 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2653 viewInfo.image = texD->image;
2654 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2655 viewInfo.format = texD->viewFormat;
2656 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2657 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2658 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2659 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2660 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2661 viewInfo.subresourceRange.baseMipLevel = 0;
2662 viewInfo.subresourceRange.levelCount = 1;
2663 viewInfo.subresourceRange.baseArrayLayer = 0;
2664 viewInfo.subresourceRange.layerCount = 1;
2665 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2666 if (err != VK_SUCCESS) {
2667 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2672 VkSemaphoreCreateInfo semInfo = {};
2673 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2681 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2683 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2684 if (err != VK_SUCCESS) {
2685 qWarning(
"Failed to create command buffer fence: %d", err);
2698 if (swapChainD->sc == VK_NULL_HANDLE)
2702 df->vkQueueWaitIdle(gfxQueue);
2706 if (frame.cmdFence) {
2708 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2709 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2710 frame.cmdFence = VK_NULL_HANDLE;
2713 if (frame.imageSem) {
2714 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2715 frame.imageSem = VK_NULL_HANDLE;
2722 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2723 image.fb = VK_NULL_HANDLE;
2725 if (image.imageView) {
2726 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2727 image.imageView = VK_NULL_HANDLE;
2729 if (image.msaaImageView) {
2730 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2731 image.msaaImageView = VK_NULL_HANDLE;
2733 if (image.msaaImage) {
2734 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2735 image.msaaImage = VK_NULL_HANDLE;
2737 if (image.drawSem) {
2738 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2739 image.drawSem = VK_NULL_HANDLE;
2743 if (swapChainD->msaaImageMem) {
2744 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2745 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2748 if (swapChainD->shadingRateMapView) {
2749 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2750 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2753 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2754 swapChainD->sc = VK_NULL_HANDLE;
2761 VkCommandPoolResetFlags flags = 0;
2766 if (releaseCachedResourcesCalledBeforeFrameStart)
2767 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2770 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2776 for (quint64 i = 0; i < timestampValidBits; i += 8)
2777 mask |= 0xFFULL << i;
2778 const quint64 ts0 = timestamp[0] & mask;
2779 const quint64 ts1 = timestamp[1] & mask;
2780 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2781 if (!qFuzzyIsNull(nsecsPerTick)) {
2782 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2783 const double elapsedSec = elapsedMs / 1000.0;
2794 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2797 inst->handle()->beginFrame(swapChainD->window);
2798 auto instEndFrameOnErrorGuard = qScopeGuard([
this, swapChainD] {
2799 inst->handle()->endFrame(swapChainD->window);
2810 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2811 if (waitResult != QRhi::FrameOpSuccess)
2816 uint32_t imageIndex = 0;
2817 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2818 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2820 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2821 swapChainD->currentImageIndex = imageIndex;
2824 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2825 return QRhi::FrameOpSwapChainOutOfDate;
2827 if (err == VK_ERROR_DEVICE_LOST) {
2828 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2829 printExtraErrorInfo(err);
2831 return QRhi::FrameOpDeviceLost;
2833 qWarning(
"Failed to acquire next swapchain image: %d", err);
2834 return QRhi::FrameOpError;
2840 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2846 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2847 if (cbres != QRhi::FrameOpSuccess)
2850 swapChainD->cbWrapper.cb = frame.cmdBuf;
2853 swapChainD->rtWrapper.d.fb = image.fb;
2857 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2858 swapChainD->rtWrapperRight.d.fb = image.fb;
2865 quint64 timestamp[2] = { 0, 0 };
2866 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2867 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2868 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2869 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2871 if (err == VK_SUCCESS) {
2873 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2875 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2877 qWarning(
"Failed to query timestamp: %d", err);
2882 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2883 int timestampQueryIdx = -1;
2884 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2885 if (!timestampQueryPoolMap.testBit(i)) {
2886 timestampQueryPoolMap.setBit(i);
2887 timestampQueryIdx = i * 2;
2891 if (timestampQueryIdx >= 0) {
2892 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2894 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2895 timestampQueryPool, uint32_t(timestampQueryIdx));
2900 instEndFrameOnErrorGuard.dismiss();
2901 return QRhi::FrameOpSuccess;
2909 auto cleanup = qScopeGuard([
this, swapChainD] {
2910 inst->handle()->endFrame(swapChainD->window);
2915 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2920 VkImageMemoryBarrier presTrans = {};
2921 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2922 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2923 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2924 presTrans.image = image.image;
2925 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2926 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2930 presTrans.srcAccessMask = 0;
2931 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2932 df->vkCmdPipelineBarrier(frame.cmdBuf,
2933 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2934 0, 0,
nullptr, 0,
nullptr,
2938 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2939 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2940 df->vkCmdPipelineBarrier(frame.cmdBuf,
2941 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2942 0, 0,
nullptr, 0,
nullptr,
2950 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2956 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2957 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2959 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2960 needsPresent ? &image.drawSem :
nullptr);
2961 if (submitres != QRhi::FrameOpSuccess)
2969 VkPresentInfoKHR presInfo = {};
2970 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2971 presInfo.swapchainCount = 1;
2972 presInfo.pSwapchains = &swapChainD->sc;
2973 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2974 waitSemaphoresForPresent.append(image.drawSem);
2975 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2976 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2980 inst->presentAboutToBeQueued(swapChainD->window);
2982 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2983 waitSemaphoresForPresent.clear();
2984 if (err != VK_SUCCESS) {
2985 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2986 return QRhi::FrameOpSwapChainOutOfDate;
2987 }
else if (err != VK_SUBOPTIMAL_KHR) {
2988 if (err == VK_ERROR_DEVICE_LOST) {
2989 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2990 printExtraErrorInfo(err);
2992 return QRhi::FrameOpDeviceLost;
2994 qWarning(
"Failed to present: %d", err);
2995 return QRhi::FrameOpError;
3001 inst->presentQueued(swapChainD->window);
3006 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3011 return QRhi::FrameOpSuccess;
3025 QRHI_RES(QVkCommandBuffer, cb)->resetState();
3035 VkCommandBufferAllocateInfo cmdBufInfo = {};
3036 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3037 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3038 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
3039 cmdBufInfo.commandBufferCount = 1;
3041 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
3042 if (err != VK_SUCCESS) {
3043 if (err == VK_ERROR_DEVICE_LOST) {
3044 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
3045 printExtraErrorInfo(err);
3047 return QRhi::FrameOpDeviceLost;
3049 qWarning(
"Failed to allocate frame command buffer: %d", err);
3050 return QRhi::FrameOpError;
3054 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3055 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3057 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
3058 if (err != VK_SUCCESS) {
3059 if (err == VK_ERROR_DEVICE_LOST) {
3060 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
3061 printExtraErrorInfo(err);
3063 return QRhi::FrameOpDeviceLost;
3065 qWarning(
"Failed to begin frame command buffer: %d", err);
3066 return QRhi::FrameOpError;
3069 return QRhi::FrameOpSuccess;
3073 VkSemaphore *waitSem, VkSemaphore *signalSem)
3075 VkResult err =
df->vkEndCommandBuffer(cb);
3076 if (err != VK_SUCCESS) {
3077 if (err == VK_ERROR_DEVICE_LOST) {
3078 qWarning(
"Device loss detected in vkEndCommandBuffer()");
3079 printExtraErrorInfo(err);
3081 return QRhi::FrameOpDeviceLost;
3083 qWarning(
"Failed to end frame command buffer: %d", err);
3084 return QRhi::FrameOpError;
3087 VkSubmitInfo submitInfo = {};
3088 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
3089 submitInfo.commandBufferCount = 1;
3090 submitInfo.pCommandBuffers = &cb;
3093 waitSemaphoresForQueueSubmit.append(*waitSem);
3095 signalSemaphoresForQueueSubmit.append(*signalSem);
3097 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
3098 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
3099 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
3100 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3101 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
3103 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3104 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3105 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3108 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3110 waitSemaphoresForQueueSubmit.clear();
3111 signalSemaphoresForQueueSubmit.clear();
3113 if (err != VK_SUCCESS) {
3114 if (err == VK_ERROR_DEVICE_LOST) {
3115 qWarning(
"Device loss detected in vkQueueSubmit()");
3116 printExtraErrorInfo(err);
3118 return QRhi::FrameOpDeviceLost;
3120 qWarning(
"Failed to submit to graphics queue: %d", err);
3121 return QRhi::FrameOpError;
3124 return QRhi::FrameOpSuccess;
3129 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3130 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3131 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3132 if (frame.cmdFenceWaitable) {
3133 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3135 if (err != VK_SUCCESS) {
3136 if (err == VK_ERROR_DEVICE_LOST) {
3137 qWarning(
"Device loss detected in vkWaitForFences()");
3138 printExtraErrorInfo(err);
3140 return QRhi::FrameOpDeviceLost;
3142 qWarning(
"Failed to wait for fence: %d", err);
3143 return QRhi::FrameOpError;
3146 df->vkResetFences(dev, 1, &frame.cmdFence);
3147 frame.cmdFenceWaitable =
false;
3151 if (ofr.cmdFenceWaitable[frameSlot]) {
3152 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3153 if (err != VK_SUCCESS) {
3154 if (err == VK_ERROR_DEVICE_LOST) {
3155 qWarning(
"Device loss detected in vkWaitForFences()");
3156 printExtraErrorInfo(err);
3158 return QRhi::FrameOpDeviceLost;
3160 qWarning(
"Failed to wait for offscreen fence: %d", err);
3161 return QRhi::FrameOpError;
3163 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3164 ofr.cmdFenceWaitable[frameSlot] =
false;
3167 return QRhi::FrameOpSuccess;
3172 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3173 if (waitResult != QRhi::FrameOpSuccess)
3179 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3180 if (cbres != QRhi::FrameOpSuccess)
3186 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3187 quint64 timestamp[2] = { 0, 0 };
3188 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3189 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3190 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3191 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3192 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3193 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3194 if (err == VK_SUCCESS) {
3196 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3200 qWarning(
"Failed to query timestamp: %d", err);
3204 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3205 int timestampQueryIdx = -1;
3206 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3207 if (!timestampQueryPoolMap.testBit(i)) {
3208 timestampQueryPoolMap.setBit(i);
3209 timestampQueryIdx = i * 2;
3213 if (timestampQueryIdx >= 0) {
3214 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3216 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3217 timestampQueryPool, uint32_t(timestampQueryIdx));
3218 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3223 return QRhi::FrameOpSuccess;
3229 Q_ASSERT(ofr.active);
3235 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3239 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3240 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3241 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3244 if (!ofr.cmdFence[currentFrameSlot]) {
3245 VkFenceCreateInfo fenceInfo = {};
3246 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3247 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3248 if (err != VK_SUCCESS) {
3249 qWarning(
"Failed to create command buffer fence: %d", err);
3250 return QRhi::FrameOpError;
3254 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3255 if (submitres != QRhi::FrameOpSuccess)
3258 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3261 if (readbacksPending) {
3262 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3263 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3264 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3271 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3273 return QRhi::FrameOpSuccess;
3295 swapChainFrameRes = &swapChainD->frameRes[swapChainD->bufferCount > 1 ? currentFrameSlot : 0];
3297 swapChainD->cbWrapper.resetCommands();
3298 cb = swapChainD->cbWrapper.cb;
3301 ? &swapChainFrameRes->imageSem
3303 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE, waitSem,
nullptr);
3304 if (submitres != QRhi::FrameOpSuccess)
3310 df->vkQueueWaitIdle(gfxQueue);
3317 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3319 startPrimaryCommandBuffer(&swapChainFrameRes->cmdBuf);
3320 swapChainD->cbWrapper.cb = swapChainFrameRes->cmdBuf;
3327 return QRhi::FrameOpSuccess;
3334 u
.access =
int(bufUsage.access);
3335 u
.stage =
int(bufUsage.stage);
3343 u
.access =
int(texUsage.access);
3344 u
.stage =
int(texUsage.stage);
3350 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3353 rtD->lastActiveFrameSlot = currentFrameSlot;
3354 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3356 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3364 texD->lastActiveFrameSlot = currentFrameSlot;
3369 rbD->lastActiveFrameSlot = currentFrameSlot;
3375 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3378 if (rtD->m_desc.depthStencilBuffer()) {
3380 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3387 rbD->lastActiveFrameSlot = currentFrameSlot;
3389 if (rtD->m_desc.depthTexture()) {
3394 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3396 if (rtD->m_desc.depthResolveTexture()) {
3401 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3403 if (rtD->m_desc.shadingRateMap()) {
3408 texD->lastActiveFrameSlot = currentFrameSlot;
3422 VkCommandBuffer secondaryCb;
3424 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3425 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3426 freeSecondaryCbs[currentFrameSlot].removeLast();
3428 VkCommandBufferAllocateInfo cmdBufInfo = {};
3429 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3430 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3431 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3432 cmdBufInfo.commandBufferCount = 1;
3434 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3435 if (err != VK_SUCCESS) {
3436 qWarning(
"Failed to create secondary command buffer: %d", err);
3437 return VK_NULL_HANDLE;
3441 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3442 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3443 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3444 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3445 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3446 cmdBufInheritInfo.subpass = 0;
3448 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3449 cmdBufInheritInfo.framebuffer = rtD->fb;
3451 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3453 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3454 if (err != VK_SUCCESS) {
3455 qWarning(
"Failed to begin secondary command buffer: %d", err);
3456 return VK_NULL_HANDLE;
3464 VkResult err =
df->vkEndCommandBuffer(cb);
3465 if (err != VK_SUCCESS)
3466 qWarning(
"Failed to end secondary command buffer: %d", err);
3470 cmd.args.executeSecondary.cb = cb;
3474 e.lastActiveFrameSlot = currentFrameSlot;
3475 e.secondaryCommandBuffer.cb = cb;
3476 releaseQueue.append(e);
3480 QRhiRenderTarget *rt,
3481 const QColor &colorClearValue,
3482 const QRhiDepthStencilClearValue &depthStencilClearValue,
3483 QRhiResourceUpdateBatch *resourceUpdates,
3484 QRhiCommandBuffer::BeginPassFlags flags)
3489 if (resourceUpdates)
3499 switch (rt->resourceType()) {
3500 case QRhiResource::SwapChainRenderTarget:
3502 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3512 texD->lastActiveFrameSlot = currentFrameSlot;
3515 case QRhiResource::TextureRenderTarget:
3529 cbD->currentTarget = rt;
3534 VkRenderPassBeginInfo rpBeginInfo = {};
3535 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3536 rpBeginInfo.renderPass = rtD
->rp->rp;
3537 rpBeginInfo.framebuffer = rtD->fb;
3538 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3539 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3541 const bool rpHasAnyClearOp =
std::any_of(rtD
->rp->attDescs.cbegin(), rtD
->rp->attDescs.cend(),
3542 [](
const VkAttachmentDescription &attDesc) {
3543 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3544 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3547 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3548 if (rpHasAnyClearOp) {
3550 VkClearValue cv = {};
3551 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3552 colorClearValue.alphaF() } };
3556 VkClearValue cv = {};
3557 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3561 VkClearValue cv = {};
3562 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3563 colorClearValue.alphaF() } };
3567 VkClearValue cv = {};
3568 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3572 VkClearValue cv = {};
3573 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3577 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3578 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3582 cmd.args.beginRenderPass.desc = rpBeginInfo;
3583 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3585 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3588 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3593 rateCmd.args.setShadingRate.w = 1;
3594 rateCmd.args.setShadingRate.h = 1;
3606 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3607 cbD->activeSecondaryCbStack.removeLast();
3608 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3615 cbD->currentTarget =
nullptr;
3617 if (resourceUpdates)
3622 QRhiResourceUpdateBatch *resourceUpdates,
3623 QRhiCommandBuffer::BeginPassFlags flags)
3628 if (resourceUpdates)
3636 cbD->computePassState.reset();
3639 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3650 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3651 cbD->activeSecondaryCbStack.removeLast();
3652 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3657 if (resourceUpdates)
3664 Q_ASSERT(psD->pipeline);
3670 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3674 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3675 cmd.args.bindPipeline.pipeline = psD->pipeline;
3678 cbD->currentGraphicsPipeline =
nullptr;
3679 cbD->currentComputePipeline = ps;
3683 psD->lastActiveFrameSlot = currentFrameSlot;
3688 QRhiShaderResourceBinding::Type bindingType,
3689 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3691 VkAccessFlags access = 0;
3692 if (bindingType == loadTypeVal) {
3693 access = VK_ACCESS_SHADER_READ_BIT;
3695 access = VK_ACCESS_SHADER_WRITE_BIT;
3696 if (bindingType == loadStoreTypeVal)
3697 access |= VK_ACCESS_SHADER_READ_BIT;
3699 auto it = writtenResources->find(resource);
3700 if (it != writtenResources->end())
3701 it->second.accessFlags |= access;
3702 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3703 writtenResources->insert(resource, { access,
true });
3708 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3709 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3710 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3711 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3712 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3713 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3719 QVarLengthArray<VkImageMemoryBarrier, 8> *imageBarriers,
3720 QVarLengthArray<VkBufferMemoryBarrier, 8> *bufferBarriers)
3722 if (!cbD->currentComputeSrb)
3728 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3729 accessAndIsNewFlag = { 0,
false };
3732 for (
auto &binding : srbD->m_bindings) {
3733 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3735 case QRhiShaderResourceBinding::ImageLoad:
3736 case QRhiShaderResourceBinding::ImageStore:
3737 case QRhiShaderResourceBinding::ImageLoadStore:
3738 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3741 QRhiShaderResourceBinding::ImageLoad,
3742 QRhiShaderResourceBinding::ImageStore,
3743 QRhiShaderResourceBinding::ImageLoadStore);
3745 case QRhiShaderResourceBinding::BufferLoad:
3746 case QRhiShaderResourceBinding::BufferStore:
3747 case QRhiShaderResourceBinding::BufferLoadStore:
3748 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3751 QRhiShaderResourceBinding::BufferLoad,
3752 QRhiShaderResourceBinding::BufferStore,
3753 QRhiShaderResourceBinding::BufferLoadStore);
3760 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3761 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3762 const bool isNewInThisDispatch = it->second.isNew;
3763 if (accessInThisDispatch && !isNewInThisDispatch) {
3764 if (it.key()->resourceType() == QRhiResource::Texture) {
3766 VkImageMemoryBarrier barrier = {};
3767 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3768 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3770 barrier.subresourceRange.baseMipLevel = 0;
3771 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3772 barrier.subresourceRange.baseArrayLayer = 0;
3773 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3774 barrier.oldLayout = texD->usageState.layout;
3775 barrier.newLayout = texD->usageState.layout;
3776 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3777 barrier.dstAccessMask = accessInThisDispatch;
3778 barrier.image = texD->image;
3779 imageBarriers->append(barrier);
3782 VkBufferMemoryBarrier barrier = {};
3783 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3784 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3785 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3786 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3787 barrier.dstAccessMask = accessInThisDispatch;
3788 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3789 barrier.size = VK_WHOLE_SIZE;
3790 bufferBarriers->append(barrier);
3796 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3797 it = cbD->computePassState.writtenResources.erase(it);
3808 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3809 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3810 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
3813 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3814 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3815 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3817 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3818 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3820 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3822 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3825 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3826 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3827 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3828 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3829 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3830 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3831 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3832 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3836 cmd.args.dispatch.x = x;
3837 cmd.args.dispatch.y = y;
3838 cmd.args.dispatch.z = z;
3843 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3844 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3845 quint32 maxDrawCount, quint32 stride)
3847 if (!caps.drawIndirectCount) {
3848 qWarning(
"drawIndirectCount called but the DrawIndirectCount feature is not supported");
3857 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3858 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3860 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3864 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3867 countBufD->lastActiveFrameSlot = currentFrameSlot;
3868 if (countBufD->m_type == QRhiBuffer::Dynamic)
3870 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3874 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3877#ifdef VK_VERSION_1_2
3878 vkCmdDrawIndirectCount(cbD->activeSecondaryCbStack.last(),
3879 indirectBufVk, indirectBufferOffset,
3880 countBufVk, countBufferOffset,
3881 maxDrawCount, stride);
3886 cmd.args.drawIndirectCount.indirectBuffer = indirectBufVk;
3887 cmd.args.drawIndirectCount.indirectBufferOffset = indirectBufferOffset;
3888 cmd.args.drawIndirectCount.countBuffer = countBufVk;
3889 cmd.args.drawIndirectCount.countBufferOffset = countBufferOffset;
3890 cmd.args.drawIndirectCount.maxDrawCount = maxDrawCount;
3891 cmd.args.drawIndirectCount.stride = stride;
3896 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3897 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3898 quint32 maxDrawCount, quint32 stride)
3900 if (!caps.drawIndirectCount) {
3901 qWarning(
"drawIndexedIndirectCount called but the DrawIndirectCount feature is not supported");
3910 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3911 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3913 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3917 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3920 countBufD->lastActiveFrameSlot = currentFrameSlot;
3921 if (countBufD->m_type == QRhiBuffer::Dynamic)
3923 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3927 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3930#ifdef VK_VERSION_1_2
3931 vkCmdDrawIndexedIndirectCount(cbD->activeSecondaryCbStack.last(),
3932 indirectBufVk, indirectBufferOffset,
3933 countBufVk, countBufferOffset,
3934 maxDrawCount, stride);
3939 cmd.args.drawIndexedIndirectCount.indirectBuffer = indirectBufVk;
3940 cmd.args.drawIndexedIndirectCount.indirectBufferOffset = indirectBufferOffset;
3941 cmd.args.drawIndexedIndirectCount.countBuffer = countBufVk;
3942 cmd.args.drawIndexedIndirectCount.countBufferOffset = countBufferOffset;
3943 cmd.args.drawIndexedIndirectCount.maxDrawCount = maxDrawCount;
3944 cmd.args.drawIndexedIndirectCount.stride = stride;
3949 quint32 indirectBufferOffset)
3956 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3957 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3959 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3960 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3965 VkAccessFlags indirectSrcAccess = 0;
3966 VkPipelineStageFlags indirectSrcStage = 0;
3971 if (cbD->computePassState.writtenResources.contains(indirectBufD)) {
3972 indirectSrcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
3973 indirectSrcStage |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3981 const auto trackedIt = passResTracker
.buffers().find(indirectBufD);
3982 if (trackedIt != passResTracker
.buffers().cend()
3985 indirectSrcAccess |= VkAccessFlags(trackedIt->second.stateAtPassBegin.access);
3986 indirectSrcStage |= VkPipelineStageFlags(trackedIt->second.stateAtPassBegin.stage);
3989 u.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
3990 u.stage |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
3997 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3998 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3999 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
4001 VkBufferMemoryBarrier indirectBarrier = {};
4002 const bool needsIndirectBarrier = indirectSrcStage != 0 && accessIsWrite(indirectSrcAccess);
4003 if (needsIndirectBarrier) {
4004 indirectBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4005 indirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4006 indirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4007 indirectBarrier.srcAccessMask = indirectSrcAccess;
4008 indirectBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
4009 indirectBarrier.buffer = indirectBufVk;
4010 indirectBarrier.size = VK_WHOLE_SIZE;
4014 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
4015 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
4016 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
4018 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
4019 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
4021 if (needsIndirectBarrier) {
4022 df->vkCmdPipelineBarrier(secondaryCb, indirectSrcStage, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
4024 1, &indirectBarrier,
4027 df->vkCmdDispatchIndirect(secondaryCb, indirectBufVk, VkDeviceSize(indirectBufferOffset));
4029 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
4032 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4033 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4034 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
4035 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
4036 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
4037 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
4038 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
4039 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
4041 if (needsIndirectBarrier) {
4044 cmd.args.bufferBarrier.srcStageMask = indirectSrcStage;
4045 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
4046 cmd.args.bufferBarrier.count = 1;
4047 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4048 cbD->pools.bufferBarrier.append(indirectBarrier);
4052 cmd.args.dispatchIndirect.indirectBuffer = indirectBufVk;
4053 cmd.args.dispatchIndirect.indirectBufferOffset = VkDeviceSize(indirectBufferOffset);
4059 VkShaderModuleCreateInfo shaderInfo = {};
4060 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
4061 shaderInfo.codeSize = size_t(spirv.size());
4062 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
4063 VkShaderModule shaderModule;
4064 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
4065 if (err != VK_SUCCESS) {
4066 qWarning(
"Failed to create shader module: %d", err);
4067 return VK_NULL_HANDLE;
4069 return shaderModule;
4077 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
4078 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
4079 pipelineCacheInfo.initialDataSize = initialDataSize;
4080 pipelineCacheInfo.pInitialData = initialData;
4081 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
4082 if (err != VK_SUCCESS) {
4083 qWarning(
"Failed to create pipeline cache: %d", err);
4093 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
4094 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
4095 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
4096 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
4097 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
4099 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
4100 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
4103 VkWriteDescriptorSet writeInfo = {};
4104 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
4105 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
4106 writeInfo.dstBinding = uint32_t(b->binding);
4107 writeInfo.descriptorCount = 1;
4109 int bufferInfoIndex = -1;
4110 int imageInfoIndex = -1;
4113 case QRhiShaderResourceBinding::UniformBuffer:
4115 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
4116 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
4117 QRhiBuffer *buf = b->u.ubuf.buf;
4119 bd.ubuf.id = bufD->m_id;
4121 VkDescriptorBufferInfo bufInfo = {};
4122 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4123 bufInfo.offset = b->u.ubuf.offset;
4124 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
4126 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
4127 bufferInfoIndex = bufferInfos.size();
4128 bufferInfos.append(bufInfo);
4131 case QRhiShaderResourceBinding::SampledTexture:
4133 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
4134 writeInfo.descriptorCount = data->count();
4135 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
4136 ArrayOfImageDesc imageInfo(data->count());
4137 bd.stex.d.resize(data->count());
4138 for (
int elem = 0; elem < data->count(); ++elem) {
4141 bd.stex.d[elem].texId = texD->m_id;
4143 bd.stex.d[elem].samplerId = samplerD->m_id;
4144 bd.stex.d[elem].samplerGeneration = samplerD
->generation;
4145 imageInfo[elem].sampler = samplerD->sampler;
4146 imageInfo[elem].imageView = texD->imageView;
4147 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4149 imageInfoIndex = imageInfos.size();
4150 imageInfos.append(imageInfo);
4153 case QRhiShaderResourceBinding::Texture:
4155 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
4156 writeInfo.descriptorCount = data->count();
4157 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
4158 ArrayOfImageDesc imageInfo(data->count());
4159 bd.stex.d.resize(data->count());
4160 for (
int elem = 0; elem < data->count(); ++elem) {
4162 bd.stex.d[elem].texId = texD->m_id;
4164 bd.stex.d[elem].samplerId = 0;
4165 bd.stex.d[elem].samplerGeneration = 0;
4166 imageInfo[elem].sampler = VK_NULL_HANDLE;
4167 imageInfo[elem].imageView = texD->imageView;
4168 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4170 imageInfoIndex = imageInfos.size();
4171 imageInfos.append(imageInfo);
4174 case QRhiShaderResourceBinding::Sampler:
4177 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
4178 bd.stex.d.resize(1);
4179 bd.stex.d[0].texId = 0;
4180 bd.stex.d[0].texGeneration = 0;
4181 bd.stex.d[0].samplerId = samplerD->m_id;
4183 ArrayOfImageDesc imageInfo(1);
4184 imageInfo[0].sampler = samplerD->sampler;
4185 imageInfo[0].imageView = VK_NULL_HANDLE;
4186 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4187 imageInfoIndex = imageInfos.size();
4188 imageInfos.append(imageInfo);
4191 case QRhiShaderResourceBinding::ImageLoad:
4192 case QRhiShaderResourceBinding::ImageStore:
4193 case QRhiShaderResourceBinding::ImageLoadStore:
4196 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
4198 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
4199 bd.simage.id = texD->m_id;
4201 ArrayOfImageDesc imageInfo(1);
4202 imageInfo[0].sampler = VK_NULL_HANDLE;
4203 imageInfo[0].imageView = view;
4204 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4205 imageInfoIndex = imageInfos.size();
4206 imageInfos.append(imageInfo);
4210 case QRhiShaderResourceBinding::BufferLoad:
4211 case QRhiShaderResourceBinding::BufferStore:
4212 case QRhiShaderResourceBinding::BufferLoadStore:
4215 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
4216 bd.sbuf.id = bufD->m_id;
4218 VkDescriptorBufferInfo bufInfo = {};
4219 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4220 bufInfo.offset = b->u.sbuf.offset;
4221 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
4222 bufferInfoIndex = bufferInfos.size();
4223 bufferInfos.append(bufInfo);
4230 writeInfos.append(writeInfo);
4231 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
4234 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
4235 const int bufferInfoIndex = infoIndices[i].first;
4236 const int imageInfoIndex = infoIndices[i].second;
4237 if (bufferInfoIndex >= 0)
4238 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
4239 else if (imageInfoIndex >= 0)
4240 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
4243 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
4247 VkAccessFlags access, VkPipelineStageFlags stage)
4250 Q_ASSERT(access && stage);
4258 if (s.access == access && s.stage == stage) {
4261 if (!accessIsWrite(access))
4265 VkBufferMemoryBarrier bufMemBarrier = {};
4266 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4267 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4268 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4269 bufMemBarrier.srcAccessMask = s.access;
4270 bufMemBarrier.dstAccessMask = access;
4271 bufMemBarrier.buffer = bufD->buffers[slot];
4272 bufMemBarrier.size = VK_WHOLE_SIZE;
4276 cmd.args.bufferBarrier.srcStageMask = s.stage;
4277 cmd.args.bufferBarrier.dstStageMask = stage;
4278 cmd.args.bufferBarrier.count = 1;
4279 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4280 cbD->pools.bufferBarrier.append(bufMemBarrier);
4287 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
4290 Q_ASSERT(layout && access && stage);
4292 if (s.access == access && s.stage == stage && s.layout == layout) {
4293 if (!accessIsWrite(access))
4297 VkImageMemoryBarrier barrier = {};
4298 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4299 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
4300 barrier.subresourceRange.baseMipLevel = 0;
4301 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4302 barrier.subresourceRange.baseArrayLayer = 0;
4303 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4304 barrier.oldLayout = s.layout;
4305 barrier.newLayout = layout;
4306 barrier.srcAccessMask = s.access;
4307 barrier.dstAccessMask = access;
4308 barrier.image = texD->image;
4310 VkPipelineStageFlags srcStage = s.stage;
4313 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4317 cmd.args.imageBarrier.srcStageMask = srcStage;
4318 cmd.args.imageBarrier.dstStageMask = stage;
4319 cmd.args.imageBarrier.count = 1;
4320 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4321 cbD->pools.imageBarrier.append(barrier);
4332 VkImageMemoryBarrier barrier = {};
4333 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4334 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4335 barrier.subresourceRange.baseMipLevel = 0;
4336 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4337 barrier.subresourceRange.baseArrayLayer = 0;
4338 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4339 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4340 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4341 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4342 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4343 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4344 barrier.image = rbD->image;
4346 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4347 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4351 cmd.args.imageBarrier.srcStageMask = stages;
4352 cmd.args.imageBarrier.dstStageMask = stages;
4353 cmd.args.imageBarrier.count = 1;
4354 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4355 cbD->pools.imageBarrier.append(barrier);
4359 VkImageLayout oldLayout, VkImageLayout newLayout,
4360 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4361 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4362 int startLayer,
int layerCount,
4363 int startLevel,
int levelCount)
4366 VkImageMemoryBarrier barrier = {};
4367 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4368 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4369 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4370 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4371 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4372 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4373 barrier.oldLayout = oldLayout;
4374 barrier.newLayout = newLayout;
4375 barrier.srcAccessMask = srcAccess;
4376 barrier.dstAccessMask = dstAccess;
4377 barrier.image = image;
4381 cmd.args.imageBarrier.srcStageMask = srcStage;
4382 cmd.args.imageBarrier.dstStageMask = dstStage;
4383 cmd.args.imageBarrier.count = 1;
4384 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4385 cbD->pools.imageBarrier.append(barrier);
4390 VkDeviceSize size = 0;
4391 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4392 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4393 if (imageSizeBytes > 0)
4394 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4399 const QRhiTextureSubresourceUploadDescription &subresDesc,
4400 size_t *curOfs,
void *mp,
4401 BufferImageCopyList *copyInfos)
4403 qsizetype copySizeBytes = 0;
4404 qsizetype imageSizeBytes = 0;
4405 const void *src =
nullptr;
4406 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4407 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4409 VkBufferImageCopy copyInfo = {};
4410 copyInfo.bufferOffset = *curOfs;
4411 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4412 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4413 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4414 copyInfo.imageSubresource.layerCount = 1;
4415 copyInfo.imageExtent.depth = 1;
4417 copyInfo.imageOffset.z = uint32_t(layer);
4419 copyInfo.imageOffset.y = uint32_t(layer);
4421 const QByteArray rawData = subresDesc.data();
4422 const QPoint dp = subresDesc.destinationTopLeft();
4423 QImage image = subresDesc.image();
4424 if (!image.isNull()) {
4425 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4426 QSize size = image.size();
4427 src = image.constBits();
4430 int bpc = qMax(1, image.depth() / 8);
4432 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4433 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4434 const int sx = subresDesc.sourceTopLeft().x();
4435 const int sy = subresDesc.sourceTopLeft().y();
4436 if (!subresDesc.sourceSize().isEmpty())
4437 size = subresDesc.sourceSize();
4438 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4439 if (size.width() == image.width()) {
4442 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4443 copySizeBytes = size.height() * image.bytesPerLine();
4445 image = image.copy(sx, sy, size.width(), size.height());
4446 src = image.constBits();
4449 copySizeBytes = image.sizeInBytes();
4450 bpc = qMax(1, image.depth() / 8);
4451 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4454 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4456 copyInfo.imageOffset.x = dp.x();
4457 copyInfo.imageOffset.y = dp.y();
4458 copyInfo.imageExtent.width = uint32_t(size.width());
4459 copyInfo.imageExtent.height = uint32_t(size.height());
4460 copyInfos->append(copyInfo);
4461 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4462 copySizeBytes = imageSizeBytes = rawData.size();
4463 src = rawData.constData();
4464 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4465 const int subresw = size.width();
4466 const int subresh = size.height();
4467 if (!subresDesc.sourceSize().isEmpty())
4468 size = subresDesc.sourceSize();
4469 const int w = size.width();
4470 const int h = size.height();
4472 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4474 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4475 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4478 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4479 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4480 copyInfos->append(copyInfo);
4481 }
else if (!rawData.isEmpty()) {
4482 copySizeBytes = imageSizeBytes = rawData.size();
4483 src = rawData.constData();
4484 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4485 if (!subresDesc.sourceSize().isEmpty())
4486 size = subresDesc.sourceSize();
4487 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4489 quint32 bytesPerPixel = 0;
4490 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4491 if (subresDesc.dataStride() && bytesPerPixel)
4492 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4494 size = clampedSubResourceUploadSizeForSourceData(size, subresDesc.dataStride(),
4495 bytesPerPixel, rawData.size());
4497 if (!size.isEmpty()) {
4498 copyInfo.imageOffset.x = dp.x();
4499 copyInfo.imageOffset.y = dp.y();
4500 copyInfo.imageExtent.width = uint32_t(size.width());
4501 copyInfo.imageExtent.height = uint32_t(size.height());
4502 copyInfos->append(copyInfo);
4505 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4509 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4510 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4516 if (err == VK_ERROR_DEVICE_LOST)
4517 printDeviceLossErrorInfo();
4518 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4519 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4524#ifdef VK_EXT_device_fault
4525 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4528 VkDeviceFaultCountsEXT faultCounts{};
4529 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4530 faultCounts.pNext =
nullptr;
4532 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4533 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4534 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4537 faultCounts.vendorBinarySize = 0;
4539 const auto numAddressInfos = faultCounts.addressInfoCount;
4540 const auto addressInfos
4541 = q20::make_unique_for_overwrite<VkDeviceFaultAddressInfoEXT[]>(numAddressInfos);
4543 const auto numVendorInfos = faultCounts.vendorInfoCount;
4544 const auto vendorInfos
4545 = q20::make_unique_for_overwrite<VkDeviceFaultVendorInfoEXT[]>(numVendorInfos);
4547 VkDeviceFaultInfoEXT info{};
4548 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4549 info.pNext =
nullptr;
4550 info.pAddressInfos = numAddressInfos ? addressInfos.get() :
nullptr;
4551 info.pVendorInfos = numVendorInfos ? vendorInfos.get() :
nullptr;
4552 info.pVendorBinaryData =
nullptr;
4554 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4555 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4556 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4560 const char *desc = info.description[0] ? info.description :
"n/a";
4561 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4562 faultCounts.addressInfoCount,
4563 faultCounts.vendorInfoCount,
4564 (
unsigned long long)faultCounts.vendorBinarySize,
4567 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4568 const auto &a = addressInfos[i];
4569 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4571 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4572 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4573 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4574 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4575 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4576 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4577 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4578 default:
return "UNKNOWN";
4581 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4583 addressTypeString(a.addressType),
4584 (
unsigned long long)a.reportedAddress,
4585 (
unsigned long long)a.addressPrecision);
4588 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4589 const auto &v = vendorInfos[i];
4590 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4592 (
unsigned long long)v.vendorFaultCode,
4593 (
unsigned long long)v.vendorFaultData,
4607 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4609 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4610 bufD->pendingDynamicUpdates[i].clear();
4611 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4615 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4616 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4618 if (!bufD->stagingBuffers[currentFrameSlot]) {
4619 VkBufferCreateInfo bufferInfo = {};
4620 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4623 bufferInfo.size = bufD->m_size;
4624 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4626 VmaAllocationCreateInfo allocInfo = {};
4627 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4629 VmaAllocation allocation;
4630 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4631 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4632 if (err == VK_SUCCESS) {
4633 bufD->stagingAllocations[currentFrameSlot] = allocation;
4634 setAllocationName(allocation, bufD->name());
4636 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4637 printExtraErrorInfo(err);
4642 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4643 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4644 u.offset, u
.data.size());
4645 if (err != VK_SUCCESS) {
4646 qWarning(
"Failed to copy memory to buffer: %d", err);
4650 trackedBufferBarrier(cbD, bufD, 0,
4651 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4653 VkBufferCopy copyInfo = {};
4654 copyInfo.srcOffset = u.offset;
4655 copyInfo.dstOffset = u.offset;
4656 copyInfo.size = u
.data.size();
4660 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4661 cmd.args.copyBuffer.dst = bufD->buffers[0];
4662 cmd.args.copyBuffer.desc = copyInfo;
4671 bufD->lastActiveFrameSlot = currentFrameSlot;
4673 if (bufD->m_type == QRhiBuffer::Immutable) {
4676 e.lastActiveFrameSlot = currentFrameSlot;
4677 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4678 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4679 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4680 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4681 releaseQueue.append(e);
4685 if (bufD->m_type == QRhiBuffer::Dynamic) {
4687 u.result->data.resizeForOverwrite(u.readSize);
4688 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4689 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4690 u.offset, u.result->data.data(), u.readSize);
4691 if (err != VK_SUCCESS) {
4692 qWarning(
"Failed to copy memory from buffer: %d", err);
4693 u.result->data.clear();
4695 if (u.result->completed)
4696 u.result->completed();
4705 readback.activeFrameSlot = currentFrameSlot;
4706 readback.result = u.result;
4707 readback.byteSize = u.readSize;
4709 VkBufferCreateInfo bufferInfo = {};
4710 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4711 bufferInfo.size = readback.byteSize;
4712 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4714 VmaAllocationCreateInfo allocInfo = {};
4715 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4717 VmaAllocation allocation;
4718 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4719 if (err == VK_SUCCESS) {
4721 setAllocationName(allocation, bufD->name());
4723 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4724 printExtraErrorInfo(err);
4728 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4730 VkBufferCopy copyInfo = {};
4731 copyInfo.srcOffset = u.offset;
4732 copyInfo.size = u.readSize;
4736 cmd.args.copyBuffer.src = bufD->buffers[0];
4737 cmd.args.copyBuffer.dst = readback.stagingBuf;
4738 cmd.args.copyBuffer.desc = copyInfo;
4740 bufD->lastActiveFrameSlot = currentFrameSlot;
4742 activeBufferReadbacks.append(readback);
4747 Q_ASSERT(dstD->m_type != QRhiBuffer::Dynamic && srcD->m_type != QRhiBuffer::Dynamic);
4749 trackedBufferBarrier(cbD, srcD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4750 trackedBufferBarrier(cbD, dstD, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4752 VkBufferCopy copyInfo = {};
4753 copyInfo.srcOffset = u.srcOffset;
4754 copyInfo.dstOffset = u.offset;
4755 copyInfo.size = u.readSize;
4759 cmd.args.copyBuffer.src = srcD->buffers[0];
4760 cmd.args.copyBuffer.dst = dstD->buffers[0];
4761 cmd.args.copyBuffer.desc = copyInfo;
4763 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4766 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4768 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4772 cmd.args.fillBuffer.dst = bufD->buffers[0];
4773 cmd.args.fillBuffer.offset = u.offset;
4774 cmd.args.fillBuffer.size = u.readSize;
4775 cmd.args.fillBuffer.data = u.fillValue32();
4777 bufD->lastActiveFrameSlot = currentFrameSlot;
4786 VkDeviceSize stagingSize = 0;
4787 for (
const auto &subres : u.subresDesc)
4788 stagingSize += subresUploadByteSize(subres.desc);
4790 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4791 VkBufferCreateInfo bufferInfo = {};
4792 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4793 bufferInfo.size = stagingSize;
4794 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4796 VmaAllocationCreateInfo allocInfo = {};
4797 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4799 VmaAllocation allocation;
4800 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4801 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4802 if (err != VK_SUCCESS) {
4803 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4804 printExtraErrorInfo(err);
4807 utexD->stagingAllocations[currentFrameSlot] = allocation;
4808 setAllocationName(allocation, utexD->name());
4810 BufferImageCopyList copyInfos;
4813 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4814 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4815 if (err != VK_SUCCESS) {
4816 qWarning(
"Failed to map image data: %d", err);
4817 vmaDestroyBuffer(toVmaAllocator(allocator), utexD->stagingBuffers[currentFrameSlot], a);
4818 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4819 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4823 for (
const auto &subres : u.subresDesc)
4824 prepareUploadSubres(utexD, subres.layer, subres.level, subres.desc, &curOfs, mp, ©Infos);
4825 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4826 vmaUnmapMemory(toVmaAllocator(allocator), a);
4828 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4829 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4831 if (!copyInfos.isEmpty()) {
4834 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4835 cmd.args.copyBufferToImage.dst = utexD->image;
4836 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4837 cmd.args.copyBufferToImage.count = copyInfos.size();
4838 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4839 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4845 e.lastActiveFrameSlot = currentFrameSlot;
4846 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4847 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4848 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4849 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4850 releaseQueue.append(e);
4855 utexD->lastActiveFrameSlot = currentFrameSlot;
4859 qWarning(
"Texture copy with matching source and destination is not supported");
4864 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4865 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4867 VkImageCopy region = {};
4868 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4869 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4870 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4871 region.srcSubresource.layerCount = 1;
4873 region.srcOffset.x = u.desc.sourceTopLeft().x();
4874 region.srcOffset.y = u.desc.sourceTopLeft().y();
4876 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4878 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4879 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4880 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4881 region.dstSubresource.layerCount = 1;
4883 region.dstOffset.x = u.desc.destinationTopLeft().x();
4884 region.dstOffset.y = u.desc.destinationTopLeft().y();
4886 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4888 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4889 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4890 region.extent.width = uint32_t(copySize.width());
4891 region.extent.height = uint32_t(copySize.height());
4892 region.extent.depth = 1;
4894 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4895 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4896 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4897 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4901 cmd.args.copyImage.src = srcD->image;
4902 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4903 cmd.args.copyImage.dst = dstD->image;
4904 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4905 cmd.args.copyImage.desc = region;
4907 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4910 readback.activeFrameSlot = currentFrameSlot;
4911 readback.desc = u.rb;
4912 readback.result = u.result;
4918 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4919 qWarning(
"Multisample texture cannot be read back");
4922 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4923 if (u.rb.rect().isValid())
4924 readback.rect = u.rb.rect();
4926 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4927 readback.format = texD->m_format;
4928 texD->lastActiveFrameSlot = currentFrameSlot;
4933 qWarning(
"Swapchain does not support readback");
4936 if (u.rb.rect().isValid())
4937 readback.rect = u.rb.rect();
4939 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4940 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4941 if (readback.format == QRhiTexture::UnknownFormat)
4947 if (!textureFormatInfo(readback.format, readback.rect.size(),
nullptr,
4948 &readback.byteSize,
nullptr))
4956 const bool combinedDepthStencil = texD && isStencilTextureFormat(readback.format);
4961 const quint64 pixelCount =
4962 quint64(readback.rect.width()) * quint64(readback.rect.height());
4963 const quint64 depthPlaneByteSize = pixelCount * 4;
4964 const quint64 stagingByteSize = combinedDepthStencil
4965 ? depthPlaneByteSize + pixelCount
4966 : readback.byteSize;
4967 if (stagingByteSize > std::numeric_limits<quint32>::max()) {
4968 qWarning(
"Readback of texture of size %dx%d would need %llu bytes "
4969 "which is too large to be handled",
4970 readback.rect.width(), readback.rect.height(), stagingByteSize);
4975 VkBufferCreateInfo bufferInfo = {};
4976 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4977 bufferInfo.size = stagingByteSize;
4978 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4980 VmaAllocationCreateInfo allocInfo = {};
4981 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4983 VmaAllocation allocation;
4984 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4985 if (err == VK_SUCCESS) {
4987 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4989 qWarning(
"Failed to create readback buffer of size %llu: %d", stagingByteSize, err);
4990 printExtraErrorInfo(err);
4995 VkBufferImageCopy copyDesc = {};
4996 copyDesc.bufferOffset = 0;
4997 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4998 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4999 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
5000 copyDesc.imageSubresource.layerCount = 1;
5001 copyDesc.imageOffset.x = readback.rect.x();
5002 copyDesc.imageOffset.y = readback.rect.y();
5004 copyDesc.imageOffset.z = u.rb.layer();
5005 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
5006 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
5007 copyDesc.imageExtent.depth = 1;
5009 const int bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
5010 if (combinedDepthStencil) {
5011 copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
5012 cbD->pools.bufferImageCopy.append(copyDesc);
5013 copyDesc.bufferOffset = depthPlaneByteSize;
5014 copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
5016 cbD->pools.bufferImageCopy.append(copyDesc);
5017 const int copyCount = cbD->pools.bufferImageCopy.size() - bufferImageCopyIndex;
5020 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5021 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
5024 cmd.args.copyImageToBuffer.src = texD->image;
5025 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
5026 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
5027 cmd.args.copyImageToBuffer.count = copyCount;
5028 cmd.args.copyImageToBuffer.bufferImageCopyIndex = bufferImageCopyIndex;
5032 VkImage image = imageRes.image;
5035 qWarning(
"Attempted to read back undefined swapchain image content, "
5036 "results are undefined. (do a render pass first)");
5038 subresourceBarrier(cbD, image,
5039 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5040 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
5041 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5049 cmd.args.copyImageToBuffer.src = image;
5050 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5051 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
5052 cmd.args.copyImageToBuffer.count = copyCount;
5053 cmd.args.copyImageToBuffer.bufferImageCopyIndex = bufferImageCopyIndex;
5056 activeTextureReadbacks.append(readback);
5059 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
5060 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
5061 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
5062 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
5064 VkImageLayout origLayout = utexD->usageState.layout;
5065 VkAccessFlags origAccess = utexD->usageState.access;
5066 VkPipelineStageFlags origStage = utexD->usageState.stage;
5068 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5070 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
5071 int w = utexD->m_pixelSize.width();
5072 int h = utexD->m_pixelSize.height();
5073 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
5076 subresourceBarrier(cbD, utexD->image,
5077 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5078 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
5079 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
5083 subresourceBarrier(cbD, utexD->image,
5084 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5085 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
5086 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5091 subresourceBarrier(cbD, utexD->image,
5092 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5093 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
5094 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
5098 VkImageBlit region = {};
5099 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5100 region.srcSubresource.mipLevel = uint32_t(level) - 1;
5101 region.srcSubresource.baseArrayLayer = uint32_t(layer);
5102 region.srcSubresource.layerCount = 1;
5104 region.srcOffsets[1].x = qMax(1, w);
5105 region.srcOffsets[1].y = qMax(1, h);
5106 region.srcOffsets[1].z = qMax(1, depth);
5108 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5109 region.dstSubresource.mipLevel = uint32_t(level);
5110 region.dstSubresource.baseArrayLayer = uint32_t(layer);
5111 region.dstSubresource.layerCount = 1;
5113 region.dstOffsets[1].x = qMax(1, w >> 1);
5114 region.dstOffsets[1].y = qMax(1, h >> 1);
5115 region.dstOffsets[1].z = qMax(1, depth >> 1);
5119 cmd.args.blitImage.src = utexD->image;
5120 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5121 cmd.args.blitImage.dst = utexD->image;
5122 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5123 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
5124 cmd.args.blitImage.desc = region;
5132 subresourceBarrier(cbD, utexD->image,
5133 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
5134 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
5135 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5137 0,
int(utexD->mipLevelCount) - 1);
5138 subresourceBarrier(cbD, utexD->image,
5139 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
5140 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
5141 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5143 int(utexD->mipLevelCount) - 1, 1);
5146 utexD->lastActiveFrameSlot = currentFrameSlot;
5155 if (bufD->pendingDynamicUpdates[slot].isEmpty())
5158 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
5160 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
5164 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
5165 if (err != VK_SUCCESS) {
5166 qWarning(
"Failed to map buffer: %d", err);
5169 quint32 changeBegin = UINT32_MAX;
5170 quint32 changeEnd = 0;
5171 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
5172 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
5173 if (u.offset < changeBegin)
5174 changeBegin = u.offset;
5175 if (u.offset + u.data.size() > changeEnd)
5176 changeEnd = u.offset + u.data.size();
5178 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
5179 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
5180 vmaUnmapMemory(toVmaAllocator(allocator), a);
5182 bufD->pendingDynamicUpdates[slot].clear();
5188 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
5189 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
5195 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
5196 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
5197 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
5202 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
5203 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
5205 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
5206 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
5207 if (e.texture.extraImageViews[i])
5208 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
5214 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
5219 qsizetype keepBegin = releaseQueue.size();
5220 for (qsizetype i = keepBegin - 1; i >= 0; --i) {
5222 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
5225 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
5226 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
5229 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
5230 if (e.shaderResourceBindings.poolIndex >= 0) {
5231 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
5232 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
5239 qrhivk_releaseRenderBuffer(e, dev,
df);
5245 qrhivk_releaseSampler(e, dev,
df);
5248 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
5250 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
5251 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
5253 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
5254 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
5255 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
5258 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
5261 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
5263 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
5264 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
5270 }
else if (--keepBegin != i) {
5271 releaseQueue[keepBegin] = std::move(releaseQueue[i]);
5275 releaseQueue.remove(0, keepBegin);
5280 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5282 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
5284 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5285 readback.result->format = readback.format;
5286 readback.result->pixelSize = readback.rect.size();
5287 readback.result->data.resizeForOverwrite(readback.byteSize);
5289 if (isStencilTextureFormat(readback.format)) {
5297 const quint64 pixelCount =
5298 quint64(readback.rect.width()) * quint64(readback.rect.height());
5299 const quint64 depthPlaneByteSize = pixelCount * 4;
5301 planar.resizeForOverwrite(qsizetype(depthPlaneByteSize + pixelCount));
5302 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5303 toVmaAllocation(readback.stagingAlloc),
5304 0, planar.data(), size_t(planar.size()));
5305 if (err == VK_SUCCESS) {
5306 const quint32 *depthPlane =
reinterpret_cast<
const quint32 *>(planar.constData());
5307 const quint8 *stencilPlane =
reinterpret_cast<
const quint8 *>(planar.constData() + depthPlaneByteSize);
5308 char *dst = readback.result->data.data();
5309 if (readback.format == QRhiTexture::D32FS8) {
5312 for (quint32 px = 0; px < pixelCount; ++px) {
5313 const quint32 stencilWord = stencilPlane[px];
5314 memcpy(dst + px * 8, &depthPlane[px],
sizeof(quint32));
5315 memcpy(dst + px * 8 + 4, &stencilWord,
sizeof(quint32));
5320 for (quint32 px = 0; px < pixelCount; ++px) {
5323 const quint32 combined = ((depthPlane[px] & 0x00FFFFFFu) << 8) | stencilPlane[px];
5324 memcpy(dst + px * 4, &combined,
sizeof(quint32));
5328 qWarning(
"Failed to copy texture readback buffer of size %lld: %d",
5329 qint64(planar.size()), err);
5330 readback.result->data.clear();
5333 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5334 toVmaAllocation(readback.stagingAlloc),
5335 0, readback.result->data.data(), readback.byteSize);
5336 if (err != VK_SUCCESS) {
5337 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
5338 readback.result->data.clear();
5339 }
else if (readback.format == QRhiTexture::D24) {
5344 char *p = readback.result->data.data();
5345 for (quint32 px = 0, count = readback.byteSize / 4; px < count; ++px)
5346 qToUnaligned((qFromUnaligned<quint32>(p + px * 4) & 0x00FFFFFFu) << 8, p + px * 4);
5350 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5352 if (readback.result->completed)
5353 completedCallbacks.append(readback.result->completed);
5355 activeTextureReadbacks.remove(i);
5359 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
5361 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5362 readback.result->data.resizeForOverwrite(readback.byteSize);
5363 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5364 toVmaAllocation(readback.stagingAlloc),
5365 0, readback.result->data.data(), readback.byteSize);
5366 if (err != VK_SUCCESS) {
5367 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
5368 readback.result->data.clear();
5371 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5373 if (readback.result->completed)
5374 completedCallbacks.append(readback.result->completed);
5376 activeBufferReadbacks.remove(i);
5380 for (
const auto &f : completedCallbacks)
5387} qvk_sampleCounts[] = {
5389 { VK_SAMPLE_COUNT_1_BIT, 1 },
5390 { VK_SAMPLE_COUNT_2_BIT, 2 },
5391 { VK_SAMPLE_COUNT_4_BIT, 4 },
5392 { VK_SAMPLE_COUNT_8_BIT, 8 },
5393 { VK_SAMPLE_COUNT_16_BIT, 16 },
5394 { VK_SAMPLE_COUNT_32_BIT, 32 },
5395 { VK_SAMPLE_COUNT_64_BIT, 64 }
5400 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
5401 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
5402 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
5403 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
5406 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5407 if ((color & qvk_sampleCount.mask)
5408 && (depth & qvk_sampleCount.mask)
5409 && (stencil & qvk_sampleCount.mask))
5411 result.append(qvk_sampleCount.count);
5420 const int s = effectiveSampleCount(sampleCount);
5422 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5423 if (qvk_sampleCount.count == s)
5424 return qvk_sampleCount.mask;
5427 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
5432 QList<QSize> result;
5433#ifdef VK_KHR_fragment_shading_rate
5434 sampleCount = qMax(1, sampleCount);
5435 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
5436 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5437 if (qvk_sampleCount.count == sampleCount) {
5438 mask = qvk_sampleCount.mask;
5442 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
5443 if (s.sampleCounts & mask)
5444 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
5447 Q_UNUSED(sampleCount);
5448 result.append(QSize(1, 1));
5455 cbD->passResTrackers.emplace_back();
5460 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5467 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5471 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5472 1, &cmd.args.copyBuffer.desc);
5475 df->vkCmdFillBuffer(cbD->cb, cmd.args.fillBuffer.dst, cmd.args.fillBuffer.offset,
5476 cmd.args.fillBuffer.size, cmd.args.fillBuffer.data);
5479 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5480 cmd.args.copyBufferToImage.dstLayout,
5481 uint32_t(cmd.args.copyBufferToImage.count),
5482 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5485 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5486 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5487 1, &cmd.args.copyImage.desc);
5490 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5491 cmd.args.copyImageToBuffer.dst,
5492 uint32_t(cmd.args.copyImageToBuffer.count),
5493 cbD->pools.bufferImageCopy.constData() + cmd.args.copyImageToBuffer.bufferImageCopyIndex);
5496 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5497 0, 0,
nullptr, 0,
nullptr,
5498 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5501 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5503 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5507 const auto &barrier = cmd.args.imageAndBufferBarrier;
5508 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5509 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5510 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5511 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5512 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5514 barrier.bufferCount, bufferBarrierData,
5515 barrier.imageCount, imageBarrierData);
5518 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5519 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5520 1, &cmd.args.blitImage.desc,
5521 cmd.args.blitImage.filter);
5524 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5525 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5526 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5527 : VK_SUBPASS_CONTENTS_INLINE);
5530 VkMemoryBarrier barrier = {};
5531 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5532 barrier.pNext =
nullptr;
5533 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5534 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5535 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5541 df->vkCmdEndRenderPass(cbD->cb);
5544 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5548 const uint32_t *offsets =
nullptr;
5549 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5550 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5551 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5552 cmd.args.bindDescriptorSet.pipelineLayout,
5553 0, 1, &cmd.args.bindDescriptorSet.descSet,
5554 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5559 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5560 uint32_t(cmd.args.bindVertexBuffer.count),
5561 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5562 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5565 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5566 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5569 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5572 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5575 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5578 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5581 df->vkCmdPushConstants(cbD->cb,
5582 cmd.args.setPushConstants.layout,
5583 cmd.args.setPushConstants.stages,
5584 cmd.args.setPushConstants.offset,
5585 cmd.args.setPushConstants.size,
5586 cbD->pools.pushConstantData.constData() + cmd.args.setPushConstants.dataIndex);
5589 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5590 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5593 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5594 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5595 cmd.args.drawIndexed.firstInstance);
5598 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5599 cmd.args.drawIndirect.indirectBufferOffset,
5600 cmd.args.drawIndirect.drawCount,
5601 cmd.args.drawIndirect.stride);
5604 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5605 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5606 cmd.args.drawIndexedIndirect.drawCount,
5607 cmd.args.drawIndexedIndirect.stride);
5609#ifdef VK_VERSION_1_2
5610 case QVkCommandBuffer::Command::DrawIndirectCount:
5611 vkCmdDrawIndirectCount(cbD->cb,
5612 cmd.args.drawIndirectCount.indirectBuffer,
5613 cmd.args.drawIndirectCount.indirectBufferOffset,
5614 cmd.args.drawIndirectCount.countBuffer,
5615 cmd.args.drawIndirectCount.countBufferOffset,
5616 cmd.args.drawIndirectCount.maxDrawCount,
5617 cmd.args.drawIndirectCount.stride);
5619 case QVkCommandBuffer::Command::DrawIndexedIndirectCount:
5620 vkCmdDrawIndexedIndirectCount(cbD->cb,
5621 cmd.args.drawIndexedIndirectCount.indirectBuffer,
5622 cmd.args.drawIndexedIndirectCount.indirectBufferOffset,
5623 cmd.args.drawIndexedIndirectCount.countBuffer,
5624 cmd.args.drawIndexedIndirectCount.countBufferOffset,
5625 cmd.args.drawIndexedIndirectCount.maxDrawCount,
5626 cmd.args.drawIndexedIndirectCount.stride);
5630#ifdef VK_EXT_debug_utils
5631 cmd.args.debugMarkerBegin.label.pLabelName =
5632 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5633 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5637#ifdef VK_EXT_debug_utils
5638 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5642#ifdef VK_EXT_debug_utils
5643 cmd.args.debugMarkerInsert.label.pLabelName =
5644 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5645 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5652 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5655 df->vkCmdDispatchIndirect(cbD->cb,
5656 cmd.args.dispatchIndirect.indirectBuffer,
5657 cmd.args.dispatchIndirect.indirectBufferOffset);
5660 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5664#ifdef VK_KHR_fragment_shading_rate
5665 VkFragmentShadingRateCombinerOpKHR op[2] = {
5666 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5667 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5669 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5670 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5683 case QRhiPassResourceTracker::BufIndirectDraw:
5684 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5685 case QRhiPassResourceTracker::BufVertexInput:
5686 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5687 case QRhiPassResourceTracker::BufIndexRead:
5688 return VK_ACCESS_INDEX_READ_BIT;
5689 case QRhiPassResourceTracker::BufUniformRead:
5690 return VK_ACCESS_UNIFORM_READ_BIT;
5691 case QRhiPassResourceTracker::BufStorageLoad:
5692 return VK_ACCESS_SHADER_READ_BIT;
5693 case QRhiPassResourceTracker::BufStorageStore:
5694 return VK_ACCESS_SHADER_WRITE_BIT;
5695 case QRhiPassResourceTracker::BufStorageLoadStore:
5696 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5707 case QRhiPassResourceTracker::BufIndirectDrawStage:
5708 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5709 case QRhiPassResourceTracker::BufVertexInputStage:
5710 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5711 case QRhiPassResourceTracker::BufVertexStage:
5712 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5713 case QRhiPassResourceTracker::BufTCStage:
5714 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5715 case QRhiPassResourceTracker::BufTEStage:
5716 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5717 case QRhiPassResourceTracker::BufFragmentStage:
5718 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5719 case QRhiPassResourceTracker::BufComputeStage:
5720 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5721 case QRhiPassResourceTracker::BufGeometryStage:
5722 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5733 u.access = VkAccessFlags(usage
.access);
5734 u.stage = VkPipelineStageFlags(usage
.stage);
5741 case QRhiPassResourceTracker::TexSample:
5742 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5743 case QRhiPassResourceTracker::TexColorOutput:
5744 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5745 case QRhiPassResourceTracker::TexDepthOutput:
5746 case QRhiPassResourceTracker::TexDepthResolveOutput:
5747 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5748 case QRhiPassResourceTracker::TexStorageLoad:
5749 case QRhiPassResourceTracker::TexStorageStore:
5750 case QRhiPassResourceTracker::TexStorageLoadStore:
5751 return VK_IMAGE_LAYOUT_GENERAL;
5752 case QRhiPassResourceTracker::TexShadingRate:
5753#ifdef VK_KHR_fragment_shading_rate
5754 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5756 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5762 return VK_IMAGE_LAYOUT_GENERAL;
5768 case QRhiPassResourceTracker::TexSample:
5769 return VK_ACCESS_SHADER_READ_BIT;
5770 case QRhiPassResourceTracker::TexColorOutput:
5771 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5772 case QRhiPassResourceTracker::TexDepthOutput:
5773 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5774 case QRhiPassResourceTracker::TexDepthResolveOutput:
5777 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5778 case QRhiPassResourceTracker::TexStorageLoad:
5779 return VK_ACCESS_SHADER_READ_BIT;
5780 case QRhiPassResourceTracker::TexStorageStore:
5781 return VK_ACCESS_SHADER_WRITE_BIT;
5782 case QRhiPassResourceTracker::TexStorageLoadStore:
5783 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5796 case QRhiPassResourceTracker::TexVertexStage:
5797 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5798 case QRhiPassResourceTracker::TexTCStage:
5799 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5800 case QRhiPassResourceTracker::TexTEStage:
5801 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5802 case QRhiPassResourceTracker::TexFragmentStage:
5803 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5804 case QRhiPassResourceTracker::TexColorOutputStage:
5805 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5806 case QRhiPassResourceTracker::TexDepthOutputStage:
5807 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5808 case QRhiPassResourceTracker::TexComputeStage:
5809 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5810 case QRhiPassResourceTracker::TexGeometryStage:
5811 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5822 u.layout = VkImageLayout(usage
.layout);
5823 u.access = VkAccessFlags(usage
.access);
5824 u.stage = VkPipelineStageFlags(usage
.stage);
5835 const VkAccessFlags newAccess = toVkAccess(access);
5836 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5837 if (u.access == newAccess && u.stage == newStage) {
5838 if (!accessIsWrite(newAccess))
5842 u.access = newAccess;
5852 const VkAccessFlags newAccess = toVkAccess(access);
5853 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5854 const VkImageLayout newLayout = toVkLayout(access);
5855 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5856 if (!accessIsWrite(newAccess))
5860 u.layout = newLayout;
5861 u.access = newAccess;
5870 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5871 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5872 VkAccessFlags access = toVkAccess(trackedB.access);
5873 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5874 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5877 if (s.access == access && s.stage == stage) {
5878 if (!accessIsWrite(access))
5881 VkBufferMemoryBarrier bufMemBarrier = {};
5882 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5883 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5884 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5885 bufMemBarrier.srcAccessMask = s.access;
5886 bufMemBarrier.dstAccessMask = access;
5887 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5888 bufMemBarrier.size = VK_WHOLE_SIZE;
5889 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5895 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5896 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5897 VkImageLayout layout = toVkLayout(trackedT.access);
5898 VkAccessFlags access = toVkAccess(trackedT.access);
5899 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5900 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5901 if (s.access == access && s.stage == stage && s.layout == layout) {
5902 if (!accessIsWrite(access))
5905 VkImageMemoryBarrier barrier = {};
5906 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5907 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5908 barrier.subresourceRange.baseMipLevel = 0;
5909 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5910 barrier.subresourceRange.baseArrayLayer = 0;
5911 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5912 barrier.oldLayout = s.layout;
5913 barrier.newLayout = layout;
5914 barrier.srcAccessMask = s.access;
5915 barrier.dstAccessMask = access;
5916 barrier.image = texD->image;
5917 VkPipelineStageFlags srcStage = s.stage;
5920 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5921 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5930 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5931 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5932 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5934 qWarning(
"Physical device surface queries not available");
5938 return new QVkSwapChain(
this);
5941QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5943 return new QVkBuffer(
this, type, usage, size);
5948 return int(ubufAlign);
5971 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
5972 0.0f, -1.0f, 0.0f, 0.0f,
5973 0.0f, 0.0f, 0.5f, 0.5f,
5974 0.0f, 0.0f, 0.0f, 1.0f);
5983 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5984 if (!physDevFeatures.textureCompressionBC)
5988 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5989 if (!physDevFeatures.textureCompressionETC2)
5993 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5994 if (!physDevFeatures.textureCompressionASTC_LDR)
5998 VkFormat vkformat = toVkTextureFormat(format, flags);
5999 VkFormatProperties props;
6000 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
6001 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
6007 case QRhi::MultisampleTexture:
6009 case QRhi::MultisampleRenderBuffer:
6011 case QRhi::DebugMarkers:
6012 return caps.debugUtils;
6013 case QRhi::Timestamps:
6014 return timestampValidBits != 0;
6015 case QRhi::Instancing:
6017 case QRhi::CustomInstanceStepRate:
6018 return caps.vertexAttribDivisor;
6019 case QRhi::PrimitiveRestart:
6021 case QRhi::NonDynamicUniformBuffers:
6023 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
6025 case QRhi::NPOTTextureRepeat:
6027 case QRhi::RedOrAlpha8IsRed:
6029 case QRhi::ElementIndexUint:
6032 return caps.compute;
6033 case QRhi::WideLines:
6034 return caps.wideLines;
6035 case QRhi::VertexShaderPointSize:
6037 case QRhi::BaseVertex:
6039 case QRhi::BaseInstance:
6041 case QRhi::TriangleFanTopology:
6043 case QRhi::ReadBackNonUniformBuffer:
6045 case QRhi::ReadBackNonBaseMipLevel:
6047 case QRhi::TexelFetch:
6049 case QRhi::RenderToNonBaseMipLevel:
6051 case QRhi::IntAttributes:
6053 case QRhi::ScreenSpaceDerivatives:
6055 case QRhi::ReadBackAnyTextureFormat:
6057 case QRhi::PipelineCacheDataLoadSave:
6059 case QRhi::ImageDataStride:
6061 case QRhi::RenderBufferImport:
6063 case QRhi::ThreeDimensionalTextures:
6065 case QRhi::RenderTo3DTextureSlice:
6066 return caps.texture3DSliceAs2D;
6067 case QRhi::TextureArrays:
6069 case QRhi::Tessellation:
6070 return caps.tessellation;
6071 case QRhi::GeometryShader:
6072 return caps.geometryShader;
6073 case QRhi::TextureArrayRange:
6075 case QRhi::NonFillPolygonMode:
6076 return caps.nonFillPolygonMode;
6077 case QRhi::OneDimensionalTextures:
6079 case QRhi::OneDimensionalTextureMipmaps:
6081 case QRhi::HalfAttributes:
6083 case QRhi::RenderToOneDimensionalTexture:
6085 case QRhi::ThreeDimensionalTextureMipmaps:
6087 case QRhi::MultiView:
6088 return caps.multiView;
6089 case QRhi::TextureViewFormat:
6091 case QRhi::ResolveDepthStencil:
6092 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
6093 case QRhi::VariableRateShading:
6094 return caps.renderPass2KHR && caps.perDrawShadingRate;
6095 case QRhi::VariableRateShadingMap:
6096 case QRhi::VariableRateShadingMapWithTexture:
6097 return caps.renderPass2KHR && caps.imageBasedShadingRate;
6098 case QRhi::PerRenderTargetBlending:
6099 case QRhi::SampleVariables:
6101 case QRhi::InstanceIndexIncludesBaseInstance:
6103 case QRhi::DepthClamp:
6104 return caps.depthClamp;
6105 case QRhi::DrawIndirect:
6107 case QRhi::DrawIndirectMulti:
6108 return caps.drawIndirectMulti;
6109 case QRhi::ShaderDrawParameters:
6110 return caps.shaderDrawParameters;
6111 case QRhi::DispatchIndirect:
6113 case QRhi::PushConstants:
6115 case QRhi::DrawIndirectCount:
6116 return caps.drawIndirectCount;
6117 case QRhi::BufferToBufferCopy:
6119 case QRhi::StaticBuffersOnGpuTimeline:
6122 Q_UNREACHABLE_RETURN(
false);
6129 case QRhi::TextureSizeMin:
6131 case QRhi::TextureSizeMax:
6132 return int(physDevProperties.limits.maxImageDimension2D);
6133 case QRhi::MaxColorAttachments:
6134 return int(physDevProperties.limits.maxColorAttachments);
6135 case QRhi::FramesInFlight:
6137 case QRhi::MaxAsyncReadbackFrames:
6139 case QRhi::MaxThreadGroupsPerDimension:
6140 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
6141 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
6142 physDevProperties.limits.maxComputeWorkGroupCount[2])));
6143 case QRhi::MaxThreadsPerThreadGroup:
6144 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
6145 case QRhi::MaxThreadGroupX:
6146 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
6147 case QRhi::MaxThreadGroupY:
6148 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
6149 case QRhi::MaxThreadGroupZ:
6150 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
6151 case QRhi::TextureArraySizeMax:
6152 return int(physDevProperties.limits.maxImageArrayLayers);
6153 case QRhi::MaxUniformBufferRange:
6154 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
6155 case QRhi::MaxVertexInputs:
6156 return physDevProperties.limits.maxVertexInputAttributes;
6157 case QRhi::MaxVertexOutputs:
6158 return physDevProperties.limits.maxVertexOutputComponents / 4;
6159 case QRhi::MaxPushConstantsSize:
6160 return int(physDevProperties.limits.maxPushConstantsSize);
6161 case QRhi::MaxVertexStorageBuffers:
6162 case QRhi::MaxFragmentStorageBuffers:
6163 return int(physDevProperties.limits.maxPerStageDescriptorStorageBuffers);
6164 case QRhi::ShadingRateImageTileSize:
6165 return caps.imageBasedShadingRateTileSize;
6167 Q_UNREACHABLE_RETURN(0);
6173 return &nativeHandlesStruct;
6178 return driverInfoStruct;
6184 result.totalPipelineCreationTime = totalPipelineCreationTime();
6186 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
6187 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
6189 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
6190 for (uint32_t i = 0; i < count; ++i) {
6191 const VmaStatistics &stats(budgets[i].statistics);
6192 result.blockCount += stats.blockCount;
6193 result.allocCount += stats.allocationCount;
6194 result.usedBytes += stats.allocationBytes;
6195 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
6209 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
6213 waitSemaphoresForQueueSubmit.clear();
6214 if (sp->waitSemaphoreCount)
6215 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
6217 signalSemaphoresForQueueSubmit.clear();
6218 if (sp->signalSemaphoreCount)
6219 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
6221 waitSemaphoresForPresent.clear();
6222 if (sp->presentWaitSemaphoreCount)
6223 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
6253 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
6256 size_t dataSize = 0;
6257 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
6258 if (err != VK_SUCCESS) {
6259 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
6260 return QByteArray();
6263 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6264 data.resize(dataOffset + dataSize);
6265 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
6266 if (err != VK_SUCCESS) {
6267 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
6268 return QByteArray();
6272 header.rhiId = pipelineCacheRhiId();
6273 header.arch = quint32(
sizeof(
void*));
6274 header.driverVersion = physDevProperties.driverVersion;
6275 header.vendorId = physDevProperties.vendorID;
6276 header.deviceId = physDevProperties.deviceID;
6277 header.dataSize = quint32(dataSize);
6278 header.uuidSize = VK_UUID_SIZE;
6279 header.reserved = 0;
6280 memcpy(data.data(), &header, headerSize);
6281 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
6292 if (data.size() < qsizetype(headerSize)) {
6293 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
6297 memcpy(&header, data.constData(), headerSize);
6299 const quint32 rhiId = pipelineCacheRhiId();
6300 if (header.rhiId != rhiId) {
6301 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
6302 rhiId, header.rhiId);
6305 const quint32 arch = quint32(
sizeof(
void*));
6306 if (header.arch != arch) {
6307 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
6311 if (header.driverVersion != physDevProperties.driverVersion) {
6312 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
6313 physDevProperties.driverVersion, header.driverVersion);
6316 if (header.vendorId != physDevProperties.vendorID) {
6317 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
6318 physDevProperties.vendorID, header.vendorId);
6321 if (header.deviceId != physDevProperties.deviceID) {
6322 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
6323 physDevProperties.deviceID, header.deviceId);
6326 if (header.uuidSize != VK_UUID_SIZE) {
6327 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
6328 quint32(VK_UUID_SIZE), header.uuidSize);
6332 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
6333 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
6336 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
6337 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
6341 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6342 if (quint64(data.size()) < quint64(dataOffset) + header.dataSize) {
6343 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
6347 if (pipelineCache) {
6348 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
6349 pipelineCache = VK_NULL_HANDLE;
6352 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
6353 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
6354 int(header.dataSize));
6356 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
6360QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
6361 int sampleCount, QRhiRenderBuffer::Flags flags,
6362 QRhiTexture::Format backingFormatHint)
6364 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
6368 const QSize &pixelSize,
int depth,
int arraySize,
6369 int sampleCount, QRhiTexture::Flags flags)
6371 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
6375 QRhiSampler::Filter mipmapMode,
6376 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
6378 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
6383 return new QVkShadingRateMap(
this);
6387 QRhiTextureRenderTarget::Flags flags)
6394 return new QVkGraphicsPipeline(
this);
6399 return new QVkComputePipeline(
this);
6404 return new QVkShaderResourceBindings(
this);
6410 Q_ASSERT(psD->pipeline);
6416 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
6420 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
6421 cmd.args.bindPipeline.pipeline = psD->pipeline;
6424 cbD->currentGraphicsPipeline = ps;
6425 cbD->currentComputePipeline =
nullptr;
6432 psD->lastActiveFrameSlot = currentFrameSlot;
6436 int dynamicOffsetCount,
6437 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
6447 srb = gfxPsD->m_shaderResourceBindings;
6449 srb = compPsD->m_shaderResourceBindings;
6453 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
6454 bool rewriteDescSet =
false;
6455 bool addWriteBarrier =
false;
6456 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
6457 VkPipelineStageFlags writeBarrierDstStageMask = 0;
6461 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
6462 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
6465 case QRhiShaderResourceBinding::UniformBuffer:
6468 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
6469 sanityCheckResourceOwnership(bufD);
6471 if (bufD->m_type == QRhiBuffer::Dynamic)
6474 bufD->lastActiveFrameSlot = currentFrameSlot;
6475 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6477 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
6483 if (bufD
->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
6484 rewriteDescSet =
true;
6485 bd.ubuf.id = bufD->m_id;
6490 case QRhiShaderResourceBinding::SampledTexture:
6491 case QRhiShaderResourceBinding::Texture:
6492 case QRhiShaderResourceBinding::Sampler:
6494 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
6495 if (bd.stex.d.size() != data->count()) {
6496 bd.stex.d.resize(data->count());
6497 rewriteDescSet =
true;
6499 for (
int elem = 0; elem < data->count(); ++elem) {
6505 Q_ASSERT(texD || samplerD);
6506 sanityCheckResourceOwnership(texD);
6507 sanityCheckResourceOwnership(samplerD);
6509 texD->lastActiveFrameSlot = currentFrameSlot;
6515 samplerD->lastActiveFrameSlot = currentFrameSlot;
6516 const quint64 texId = texD ? texD->m_id : 0;
6518 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6519 const uint samplerGen = samplerD ? samplerD
->generation : 0;
6520 if (texGen != bd.stex.d[elem].texGeneration
6521 || texId != bd.stex.d[elem].texId
6522 || samplerGen != bd.stex.d[elem].samplerGeneration
6523 || samplerId != bd.stex.d[elem].samplerId)
6525 rewriteDescSet =
true;
6526 bd.stex.d[elem].texId = texId;
6527 bd.stex.d[elem].texGeneration = texGen;
6528 bd.stex.d[elem].samplerId = samplerId;
6529 bd.stex.d[elem].samplerGeneration = samplerGen;
6534 case QRhiShaderResourceBinding::ImageLoad:
6535 case QRhiShaderResourceBinding::ImageStore:
6536 case QRhiShaderResourceBinding::ImageLoadStore:
6539 sanityCheckResourceOwnership(texD);
6540 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6541 texD->lastActiveFrameSlot = currentFrameSlot;
6543 if (b->type == QRhiShaderResourceBinding::ImageLoad)
6545 else if (b->type == QRhiShaderResourceBinding::ImageStore)
6550 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6551 const auto prevAccess = passResTracker
.textures().find(texD);
6552 if (prevAccess != passResTracker
.textures().end()) {
6556 addWriteBarrier =
true;
6557 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6558 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6566 if (texD
->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6567 rewriteDescSet =
true;
6568 bd.simage.id = texD->m_id;
6573 case QRhiShaderResourceBinding::BufferLoad:
6574 case QRhiShaderResourceBinding::BufferStore:
6575 case QRhiShaderResourceBinding::BufferLoadStore:
6578 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6579 sanityCheckResourceOwnership(bufD);
6581 if (bufD->m_type == QRhiBuffer::Dynamic)
6584 bufD->lastActiveFrameSlot = currentFrameSlot;
6586 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6588 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6593 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6594 const auto prevAccess = passResTracker
.buffers().find(bufD);
6595 if (prevAccess != passResTracker
.buffers().end()) {
6599 addWriteBarrier =
true;
6600 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6601 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6604 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6608 if (bufD
->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6609 rewriteDescSet =
true;
6610 bd.sbuf.id = bufD->m_id;
6621 if (addWriteBarrier) {
6623 VkMemoryBarrier barrier = {};
6624 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6625 barrier.pNext =
nullptr;
6626 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6627 barrier.srcAccessMask = barrier.dstAccessMask;
6628 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6635 cmd.args.memoryBarrier.dependencyFlags = 0;
6636 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6637 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6638 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6639 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6645 updateShaderResourceBindings(srb);
6649 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6650 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6652 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6655 QVarLengthArray<uint32_t, 4> dynOfs;
6660 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6661 uint32_t offset = 0;
6662 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6663 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6664 if (bindingOffsetPair.first == bindingNumber) {
6665 offset = bindingOffsetPair.second;
6669 dynOfs.append(offset);
6673 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6674 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6675 gfxPsD ? gfxPsD->layout : compPsD->layout,
6676 0, 1, &srbD->descSets[currentFrameSlot],
6677 uint32_t(dynOfs.size()),
6678 dynOfs.size() ? dynOfs.constData() :
nullptr);
6682 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6683 : VK_PIPELINE_BIND_POINT_COMPUTE;
6684 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6685 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6686 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6687 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6688 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6692 cbD->currentGraphicsSrb = srb;
6693 cbD->currentComputeSrb =
nullptr;
6695 cbD->currentGraphicsSrb =
nullptr;
6696 cbD->currentComputeSrb = srb;
6699 cbD->currentDescSetSlot = currentFrameSlot;
6702 srbD->lastActiveFrameSlot = currentFrameSlot;
6706 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6707 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6713 bool needsBindVBuf =
false;
6714 for (
int i = 0; i < bindingCount; ++i) {
6715 const int inputSlot = startBinding + i;
6717 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6718 bufD->lastActiveFrameSlot = currentFrameSlot;
6719 if (bufD->m_type == QRhiBuffer::Dynamic)
6722 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6723 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6724 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6726 needsBindVBuf =
true;
6727 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6728 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6732 if (needsBindVBuf) {
6733 QVarLengthArray<VkBuffer, 4> bufs;
6734 QVarLengthArray<VkDeviceSize, 4> ofs;
6735 for (
int i = 0; i < bindingCount; ++i) {
6737 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6738 bufs.append(bufD->buffers[slot]);
6739 ofs.append(bindings[i].second);
6746 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6747 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6751 cmd.args.bindVertexBuffer.startBinding = startBinding;
6752 cmd.args.bindVertexBuffer.count = bufs.size();
6753 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6754 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6755 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6756 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6762 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6763 ibufD->lastActiveFrameSlot = currentFrameSlot;
6764 if (ibufD->m_type == QRhiBuffer::Dynamic)
6767 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6768 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6769 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6770 : VK_INDEX_TYPE_UINT32;
6772 if (cbD->currentIndexBuffer != vkindexbuf
6773 || cbD->currentIndexOffset != indexOffset
6774 || cbD->currentIndexFormat != type)
6776 cbD->currentIndexBuffer = vkindexbuf;
6777 cbD->currentIndexOffset = indexOffset;
6778 cbD->currentIndexFormat = type;
6781 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6785 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6786 cmd.args.bindIndexBuffer.ofs = indexOffset;
6787 cmd.args.bindIndexBuffer.type = type;
6801 const QSize outputSize = cbD->currentTarget->pixelSize();
6802 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6803 float x = 0, y = 0, w = 0, h = 0;
6805 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6808 w = outputSize.width();
6809 h = outputSize.height();
6812 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6816 VkRect2D *s = &cmd.args.setScissor.scissor;
6817 s->offset.x = int32_t(x);
6818 s->offset.y = int32_t(y);
6819 s->extent.width = uint32_t(w);
6820 s->extent.height = uint32_t(h);
6823 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6824 cbD->commands.unget();
6834 const QSize outputSize = cbD->currentTarget->pixelSize();
6838 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6842 VkViewport *vp = &cmd.args.setViewport.viewport;
6847 vp->minDepth = viewport.minDepth();
6848 vp->maxDepth = viewport.maxDepth();
6851 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6852 cbD->commands.unget();
6857 cbD->currentViewport = viewport;
6858 if (cbD->currentGraphicsPipeline
6859 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6869 Q_ASSERT(!cbD->currentGraphicsPipeline
6871 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6872 const QSize outputSize = cbD->currentTarget->pixelSize();
6876 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6880 VkRect2D *s = &cmd.args.setScissor.scissor;
6883 s->extent.width = uint32_t(w);
6884 s->extent.height = uint32_t(h);
6887 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6888 cbD->commands.unget();
6902 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6903 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6907 cmd.args.setBlendConstants.c[0] = c.redF();
6908 cmd.args.setBlendConstants.c[1] = c.greenF();
6909 cmd.args.setBlendConstants.c[2] = c.blueF();
6910 cmd.args.setBlendConstants.c[3] = c.alphaF();
6920 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6924 cmd.args.setStencilRef.ref = refValue;
6933 VkPipelineLayout layout = VK_NULL_HANDLE;
6934 VkShaderStageFlags stages = 0;
6937 layout = psD->layout;
6938 stages = psD->pushConstantStages;
6942 layout = psD->layout;
6943 stages = psD->pushConstantStages;
6946 if (!layout || !stages) {
6947 qWarning(
"No pipeline with a push constant block is active; setPushConstants ignored");
6952 df->vkCmdPushConstants(cbD->activeSecondaryCbStack.last(), layout, stages, offset, size, data);
6954 const int dataIndex = cbD->pools.pushConstantData.size();
6955 cbD->pools.pushConstantData.append(
static_cast<
const char *>(data), size);
6958 cmd.args.setPushConstants.layout = layout;
6959 cmd.args.setPushConstants.stages = stages;
6960 cmd.args.setPushConstants.offset = offset;
6961 cmd.args.setPushConstants.size = size;
6962 cmd.args.setPushConstants.dataIndex = dataIndex;
6968#ifdef VK_KHR_fragment_shading_rate
6969 if (!vkCmdSetFragmentShadingRateKHR)
6972 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6973 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6974 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6976 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6977 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6978 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6980 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6981 if (cbD->passUsesSecondaryCb) {
6982 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6984 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6985 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6986 cmd.args.setShadingRate.w = size.width;
6987 cmd.args.setShadingRate.h = size.height;
6989 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6990 cbD->hasShadingRateSet =
true;
6993 Q_UNUSED(coarsePixelSize);
6998 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
7004 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
7008 cmd.args.draw.vertexCount = vertexCount;
7009 cmd.args.draw.instanceCount = instanceCount;
7010 cmd.args.draw.firstVertex = firstVertex;
7011 cmd.args.draw.firstInstance = firstInstance;
7016 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
7022 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
7023 firstIndex, vertexOffset, firstInstance);
7027 cmd.args.drawIndexed.indexCount = indexCount;
7028 cmd.args.drawIndexed.instanceCount = instanceCount;
7029 cmd.args.drawIndexed.firstIndex = firstIndex;
7030 cmd.args.drawIndexed.vertexOffset = vertexOffset;
7031 cmd.args.drawIndexed.firstInstance = firstInstance;
7036 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
7043 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
7044 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
7046 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
7050 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
7053 if (caps.drawIndirectMulti) {
7054 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
7055 indirectBufVk, indirectBufferOffset,
7058 VkDeviceSize offset = indirectBufferOffset;
7059 for (quint32 i = 0; i < drawCount; ++i) {
7060 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
7061 indirectBufVk, offset,
7067 if (caps.drawIndirectMulti) {
7070 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
7071 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
7072 cmd.args.drawIndirect.drawCount = drawCount;
7073 cmd.args.drawIndirect.stride = stride;
7075 VkDeviceSize offset = indirectBufferOffset;
7076 for (quint32 i = 0; i < drawCount; ++i) {
7079 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
7080 cmd.args.drawIndirect.indirectBufferOffset = offset;
7081 cmd.args.drawIndirect.drawCount = 1;
7082 cmd.args.drawIndirect.stride = stride;
7090 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
7097 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
7098 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
7100 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
7104 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
7107 if (caps.drawIndirectMulti) {
7108 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
7109 indirectBufVk, indirectBufferOffset,
7112 VkDeviceSize offset = indirectBufferOffset;
7113 for (quint32 i = 0; i < drawCount; ++i) {
7114 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
7115 indirectBufVk, offset,
7121 if (caps.drawIndirectMulti) {
7124 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
7125 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
7126 cmd.args.drawIndexedIndirect.drawCount = drawCount;
7127 cmd.args.drawIndexedIndirect.stride = stride;
7129 VkDeviceSize offset = indirectBufferOffset;
7130 for (quint32 i = 0; i < drawCount; ++i) {
7133 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
7134 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
7135 cmd.args.drawIndexedIndirect.drawCount = 1;
7136 cmd.args.drawIndexedIndirect.stride = stride;
7145#ifdef VK_EXT_debug_utils
7146 if (!debugMarkers || !caps.debugUtils)
7149 VkDebugUtilsLabelEXT label = {};
7150 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
7152 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7153 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7154 label.pLabelName = name.constData();
7155 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
7157 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7158 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
7159 cmd.args.debugMarkerBegin.label = label;
7160 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
7161 cbD->pools.debugMarkerData.append(name);
7171#ifdef VK_EXT_debug_utils
7172 if (!debugMarkers || !caps.debugUtils)
7175 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7176 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7177 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
7179 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7180 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
7189#ifdef VK_EXT_debug_utils
7190 if (!debugMarkers || !caps.debugUtils)
7193 VkDebugUtilsLabelEXT label = {};
7194 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
7196 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7197 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7198 label.pLabelName = msg.constData();
7199 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
7201 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7202 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
7203 cmd.args.debugMarkerInsert.label = label;
7204 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
7205 cbD->pools.debugMarkerData.append(msg);
7215 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
7220 Q_ASSERT(cbD->currentTarget);
7223 switch (cbD->currentTarget->resourceType()) {
7224 case QRhiResource::SwapChainRenderTarget:
7227 case QRhiResource::TextureRenderTarget:
7259 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
7260 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
7264 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
7265 cbD->activeSecondaryCbStack.removeLast();
7266 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
7268 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
7270 cbD->activeSecondaryCbStack.append(extCb);
7282 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
7283 cbD->activeSecondaryCbStack.removeLast();
7284 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
7285 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
7299 if (!debugMarkers || name.isEmpty())
7302 QByteArray decoratedName = name;
7304 decoratedName +=
'/';
7305 decoratedName += QByteArray::number(slot);
7307 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
7312#ifdef VK_EXT_debug_utils
7313 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
7316 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
7317 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
7318 nameInfo.objectType = type;
7319 nameInfo.objectHandle = object;
7320 QByteArray decoratedName = name;
7322 decoratedName +=
'/';
7323 decoratedName += QByteArray::number(slot);
7325 nameInfo.pObjectName = decoratedName.constData();
7326 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
7338 if (usage.testFlag(QRhiBuffer::VertexBuffer))
7339 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
7340 if (usage.testFlag(QRhiBuffer::IndexBuffer))
7341 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
7342 if (usage.testFlag(QRhiBuffer::UniformBuffer))
7343 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
7344 if (usage.testFlag(QRhiBuffer::StorageBuffer))
7345 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
7346 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
7347 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
7348 return VkBufferUsageFlagBits(u);
7354 case QRhiSampler::Nearest:
7355 return VK_FILTER_NEAREST;
7356 case QRhiSampler::Linear:
7357 return VK_FILTER_LINEAR;
7359 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
7366 case QRhiSampler::None:
7367 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7368 case QRhiSampler::Nearest:
7369 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7370 case QRhiSampler::Linear:
7371 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
7373 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
7380 case QRhiSampler::Repeat:
7381 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
7382 case QRhiSampler::ClampToEdge:
7383 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
7384 case QRhiSampler::Mirror:
7385 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
7387 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
7394 case QRhiShaderStage::Vertex:
7395 return VK_SHADER_STAGE_VERTEX_BIT;
7396 case QRhiShaderStage::TessellationControl:
7397 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7398 case QRhiShaderStage::TessellationEvaluation:
7399 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7400 case QRhiShaderStage::Fragment:
7401 return VK_SHADER_STAGE_FRAGMENT_BIT;
7402 case QRhiShaderStage::Compute:
7403 return VK_SHADER_STAGE_COMPUTE_BIT;
7404 case QRhiShaderStage::Geometry:
7405 return VK_SHADER_STAGE_GEOMETRY_BIT;
7407 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
7414 case QRhiVertexInputAttribute::Float4:
7415 return VK_FORMAT_R32G32B32A32_SFLOAT;
7416 case QRhiVertexInputAttribute::Float3:
7417 return VK_FORMAT_R32G32B32_SFLOAT;
7418 case QRhiVertexInputAttribute::Float2:
7419 return VK_FORMAT_R32G32_SFLOAT;
7420 case QRhiVertexInputAttribute::Float:
7421 return VK_FORMAT_R32_SFLOAT;
7422 case QRhiVertexInputAttribute::UNormByte4:
7423 return VK_FORMAT_R8G8B8A8_UNORM;
7424 case QRhiVertexInputAttribute::UNormByte2:
7425 return VK_FORMAT_R8G8_UNORM;
7426 case QRhiVertexInputAttribute::UNormByte:
7427 return VK_FORMAT_R8_UNORM;
7428 case QRhiVertexInputAttribute::UInt4:
7429 return VK_FORMAT_R32G32B32A32_UINT;
7430 case QRhiVertexInputAttribute::UInt3:
7431 return VK_FORMAT_R32G32B32_UINT;
7432 case QRhiVertexInputAttribute::UInt2:
7433 return VK_FORMAT_R32G32_UINT;
7434 case QRhiVertexInputAttribute::UInt:
7435 return VK_FORMAT_R32_UINT;
7436 case QRhiVertexInputAttribute::SInt4:
7437 return VK_FORMAT_R32G32B32A32_SINT;
7438 case QRhiVertexInputAttribute::SInt3:
7439 return VK_FORMAT_R32G32B32_SINT;
7440 case QRhiVertexInputAttribute::SInt2:
7441 return VK_FORMAT_R32G32_SINT;
7442 case QRhiVertexInputAttribute::SInt:
7443 return VK_FORMAT_R32_SINT;
7444 case QRhiVertexInputAttribute::Half4:
7445 return VK_FORMAT_R16G16B16A16_SFLOAT;
7446 case QRhiVertexInputAttribute::Half3:
7447 return VK_FORMAT_R16G16B16_SFLOAT;
7448 case QRhiVertexInputAttribute::Half2:
7449 return VK_FORMAT_R16G16_SFLOAT;
7450 case QRhiVertexInputAttribute::Half:
7451 return VK_FORMAT_R16_SFLOAT;
7452 case QRhiVertexInputAttribute::UShort4:
7453 return VK_FORMAT_R16G16B16A16_UINT;
7454 case QRhiVertexInputAttribute::UShort3:
7455 return VK_FORMAT_R16G16B16_UINT;
7456 case QRhiVertexInputAttribute::UShort2:
7457 return VK_FORMAT_R16G16_UINT;
7458 case QRhiVertexInputAttribute::UShort:
7459 return VK_FORMAT_R16_UINT;
7460 case QRhiVertexInputAttribute::SShort4:
7461 return VK_FORMAT_R16G16B16A16_SINT;
7462 case QRhiVertexInputAttribute::SShort3:
7463 return VK_FORMAT_R16G16B16_SINT;
7464 case QRhiVertexInputAttribute::SShort2:
7465 return VK_FORMAT_R16G16_SINT;
7466 case QRhiVertexInputAttribute::SShort:
7467 return VK_FORMAT_R16_SINT;
7469 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
7476 case QRhiGraphicsPipeline::Triangles:
7477 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
7478 case QRhiGraphicsPipeline::TriangleStrip:
7479 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
7480 case QRhiGraphicsPipeline::TriangleFan:
7481 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
7482 case QRhiGraphicsPipeline::Lines:
7483 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
7484 case QRhiGraphicsPipeline::LineStrip:
7485 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7486 case QRhiGraphicsPipeline::Points:
7487 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
7488 case QRhiGraphicsPipeline::Patches:
7489 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7491 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
7498 case QRhiGraphicsPipeline::None:
7499 return VK_CULL_MODE_NONE;
7500 case QRhiGraphicsPipeline::Front:
7501 return VK_CULL_MODE_FRONT_BIT;
7502 case QRhiGraphicsPipeline::Back:
7503 return VK_CULL_MODE_BACK_BIT;
7505 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
7512 case QRhiGraphicsPipeline::CCW:
7513 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
7514 case QRhiGraphicsPipeline::CW:
7515 return VK_FRONT_FACE_CLOCKWISE;
7517 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
7524 if (c.testFlag(QRhiGraphicsPipeline::R))
7525 f |= VK_COLOR_COMPONENT_R_BIT;
7526 if (c.testFlag(QRhiGraphicsPipeline::G))
7527 f |= VK_COLOR_COMPONENT_G_BIT;
7528 if (c.testFlag(QRhiGraphicsPipeline::B))
7529 f |= VK_COLOR_COMPONENT_B_BIT;
7530 if (c.testFlag(QRhiGraphicsPipeline::A))
7531 f |= VK_COLOR_COMPONENT_A_BIT;
7532 return VkColorComponentFlags(f);
7538 case QRhiGraphicsPipeline::Zero:
7539 return VK_BLEND_FACTOR_ZERO;
7540 case QRhiGraphicsPipeline::One:
7541 return VK_BLEND_FACTOR_ONE;
7542 case QRhiGraphicsPipeline::SrcColor:
7543 return VK_BLEND_FACTOR_SRC_COLOR;
7544 case QRhiGraphicsPipeline::OneMinusSrcColor:
7545 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
7546 case QRhiGraphicsPipeline::DstColor:
7547 return VK_BLEND_FACTOR_DST_COLOR;
7548 case QRhiGraphicsPipeline::OneMinusDstColor:
7549 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
7550 case QRhiGraphicsPipeline::SrcAlpha:
7551 return VK_BLEND_FACTOR_SRC_ALPHA;
7552 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7553 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
7554 case QRhiGraphicsPipeline::DstAlpha:
7555 return VK_BLEND_FACTOR_DST_ALPHA;
7556 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7557 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7558 case QRhiGraphicsPipeline::ConstantColor:
7559 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7560 case QRhiGraphicsPipeline::OneMinusConstantColor:
7561 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7562 case QRhiGraphicsPipeline::ConstantAlpha:
7563 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7564 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7565 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7566 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7567 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7568 case QRhiGraphicsPipeline::Src1Color:
7569 return VK_BLEND_FACTOR_SRC1_COLOR;
7570 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7571 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7572 case QRhiGraphicsPipeline::Src1Alpha:
7573 return VK_BLEND_FACTOR_SRC1_ALPHA;
7574 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7575 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7577 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7584 case QRhiGraphicsPipeline::Add:
7585 return VK_BLEND_OP_ADD;
7586 case QRhiGraphicsPipeline::Subtract:
7587 return VK_BLEND_OP_SUBTRACT;
7588 case QRhiGraphicsPipeline::ReverseSubtract:
7589 return VK_BLEND_OP_REVERSE_SUBTRACT;
7590 case QRhiGraphicsPipeline::Min:
7591 return VK_BLEND_OP_MIN;
7592 case QRhiGraphicsPipeline::Max:
7593 return VK_BLEND_OP_MAX;
7595 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7602 case QRhiGraphicsPipeline::Never:
7603 return VK_COMPARE_OP_NEVER;
7604 case QRhiGraphicsPipeline::Less:
7605 return VK_COMPARE_OP_LESS;
7606 case QRhiGraphicsPipeline::Equal:
7607 return VK_COMPARE_OP_EQUAL;
7608 case QRhiGraphicsPipeline::LessOrEqual:
7609 return VK_COMPARE_OP_LESS_OR_EQUAL;
7610 case QRhiGraphicsPipeline::Greater:
7611 return VK_COMPARE_OP_GREATER;
7612 case QRhiGraphicsPipeline::NotEqual:
7613 return VK_COMPARE_OP_NOT_EQUAL;
7614 case QRhiGraphicsPipeline::GreaterOrEqual:
7615 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7616 case QRhiGraphicsPipeline::Always:
7617 return VK_COMPARE_OP_ALWAYS;
7619 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7626 case QRhiGraphicsPipeline::StencilZero:
7627 return VK_STENCIL_OP_ZERO;
7628 case QRhiGraphicsPipeline::Keep:
7629 return VK_STENCIL_OP_KEEP;
7630 case QRhiGraphicsPipeline::Replace:
7631 return VK_STENCIL_OP_REPLACE;
7632 case QRhiGraphicsPipeline::IncrementAndClamp:
7633 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7634 case QRhiGraphicsPipeline::DecrementAndClamp:
7635 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7636 case QRhiGraphicsPipeline::Invert:
7637 return VK_STENCIL_OP_INVERT;
7638 case QRhiGraphicsPipeline::IncrementAndWrap:
7639 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7640 case QRhiGraphicsPipeline::DecrementAndWrap:
7641 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7643 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7650 case QRhiGraphicsPipeline::Fill:
7651 return VK_POLYGON_MODE_FILL;
7652 case QRhiGraphicsPipeline::Line:
7653 return VK_POLYGON_MODE_LINE;
7655 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7661 dst->failOp = toVkStencilOp(src.failOp);
7662 dst->passOp = toVkStencilOp(src.passOp);
7663 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7664 dst->compareOp = toVkCompareOp(src.compareOp);
7670 case QRhiShaderResourceBinding::UniformBuffer:
7671 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7672 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7674 case QRhiShaderResourceBinding::SampledTexture:
7675 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7677 case QRhiShaderResourceBinding::Texture:
7678 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7680 case QRhiShaderResourceBinding::Sampler:
7681 return VK_DESCRIPTOR_TYPE_SAMPLER;
7683 case QRhiShaderResourceBinding::ImageLoad:
7684 case QRhiShaderResourceBinding::ImageStore:
7685 case QRhiShaderResourceBinding::ImageLoadStore:
7686 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7688 case QRhiShaderResourceBinding::BufferLoad:
7689 case QRhiShaderResourceBinding::BufferStore:
7690 case QRhiShaderResourceBinding::BufferLoadStore:
7691 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7694 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7701 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7702 s |= VK_SHADER_STAGE_VERTEX_BIT;
7703 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7704 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7705 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7706 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7707 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7708 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7709 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7710 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7711 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7712 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7713 return VkShaderStageFlags(s);
7719 case QRhiSampler::Never:
7720 return VK_COMPARE_OP_NEVER;
7721 case QRhiSampler::Less:
7722 return VK_COMPARE_OP_LESS;
7723 case QRhiSampler::Equal:
7724 return VK_COMPARE_OP_EQUAL;
7725 case QRhiSampler::LessOrEqual:
7726 return VK_COMPARE_OP_LESS_OR_EQUAL;
7727 case QRhiSampler::Greater:
7728 return VK_COMPARE_OP_GREATER;
7729 case QRhiSampler::NotEqual:
7730 return VK_COMPARE_OP_NOT_EQUAL;
7731 case QRhiSampler::GreaterOrEqual:
7732 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7733 case QRhiSampler::Always:
7734 return VK_COMPARE_OP_ALWAYS;
7736 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7744 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7764 e.buffer.buffers[i] = buffers[i];
7766 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7769 buffers[i] = VK_NULL_HANDLE;
7771 stagingBuffers[i] = VK_NULL_HANDLE;
7773 pendingDynamicUpdates[i].clear();
7781 rhiD->releaseQueue.append(e);
7782 rhiD->unregisterResource(
this);
7791 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7792 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7796 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7798 VkBufferCreateInfo bufferInfo = {};
7799 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7800 bufferInfo.size = nonZeroSize;
7801 bufferInfo.usage = toVkBufferUsage(m_usage);
7803 VmaAllocationCreateInfo allocInfo = {};
7805 if (m_type == Dynamic) {
7810 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7813 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7815 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7816 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7820 VkResult err = VK_SUCCESS;
7822 buffers[i] = VK_NULL_HANDLE;
7824 usageState[i].access = usageState[i].stage = 0;
7825 if (i == 0 || m_type == Dynamic) {
7826 VmaAllocation allocation;
7827 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7828 if (err != VK_SUCCESS)
7831 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7832 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7833 m_type == Dynamic ? i : -1);
7837 if (err != VK_SUCCESS) {
7838 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7839 rhiD->printExtraErrorInfo(err);
7845 rhiD->registerResource(
this);
7851 if (m_type == Dynamic) {
7857 b.objects[i] = &buffers[i];
7862 return { { &buffers[0] }, 1 };
7872 Q_ASSERT(m_type == Dynamic);
7874 Q_ASSERT(rhiD->inFrame);
7875 const int slot = rhiD->currentFrameSlot;
7877 VmaAllocation a = toVmaAllocation(allocations[slot]);
7878 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7879 if (err != VK_SUCCESS) {
7880 qWarning(
"Failed to map buffer: %d", err);
7883 return static_cast<
char *>(p);
7889 const int slot = rhiD->currentFrameSlot;
7890 VmaAllocation a = toVmaAllocation(allocations[slot]);
7891 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7892 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7896 int sampleCount, Flags flags,
7897 QRhiTexture::Format backingFormatHint)
7910 if (!memory && !backingTexture)
7917 e.renderBuffer.memory = memory;
7918 e.renderBuffer.image = image;
7919 e.renderBuffer.imageView = imageView;
7921 memory = VK_NULL_HANDLE;
7922 image = VK_NULL_HANDLE;
7923 imageView = VK_NULL_HANDLE;
7933 rhiD->releaseQueue.append(e);
7934 rhiD->unregisterResource(
this);
7940 if (memory || backingTexture)
7943 if (m_pixelSize.isEmpty())
7947 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7950 case QRhiRenderBuffer::Color:
7958 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7966 vkformat = backingTexture->vkformat;
7969 case QRhiRenderBuffer::DepthStencil:
7970 vkformat = rhiD->optimalDepthStencilFormat();
7971 if (!rhiD->createTransientImage(vkformat,
7973 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7974 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7983 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7992 rhiD->registerResource(
this);
7998 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7999 return m_backingFormatHint;
8001 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
8005 int arraySize,
int sampleCount, Flags flags)
8009 stagingBuffers[i] = VK_NULL_HANDLE;
8012 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
8013 perLevelImageViews[i] = VK_NULL_HANDLE;
8030 e.texture.image = owns ? image : VK_NULL_HANDLE;
8031 e.texture.imageView = imageView;
8035 e.texture.stagingBuffers[i] = stagingBuffers[i];
8038 stagingBuffers[i] = VK_NULL_HANDLE;
8042 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
8043 e.texture.extraImageViews[i] = perLevelImageViews[i];
8044 perLevelImageViews[i] = VK_NULL_HANDLE;
8047 image = VK_NULL_HANDLE;
8048 imageView = VK_NULL_HANDLE;
8053 rhiD->releaseQueue.append(e);
8054 rhiD->unregisterResource(
this);
8064 vkformat = toVkTextureFormat(m_format, m_flags);
8065 if (m_writeViewFormat.format != UnknownFormat)
8066 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
8068 viewFormat = vkformat;
8069 if (m_readViewFormat.format != UnknownFormat)
8070 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
8072 viewFormatForSampling = vkformat;
8074 VkFormatProperties props;
8075 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
8076 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
8077 if (!canSampleOptimal) {
8078 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
8082 const bool isCube = m_flags.testFlag(CubeMap);
8083 const bool isArray = m_flags.testFlag(TextureArray);
8084 const bool is3D = m_flags.testFlag(ThreeDimensional);
8085 const bool is1D = m_flags.testFlag(OneDimensional);
8086 const bool hasMipMaps = m_flags.testFlag(MipMapped);
8088 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
8089 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
8091 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
8092 const int maxLevels = QRhi::MAX_MIP_LEVELS;
8094 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain",
mipLevelCount, maxLevels);
8097 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
8098 if (samples > VK_SAMPLE_COUNT_1_BIT) {
8100 qWarning(
"Cubemap texture cannot be multisample");
8104 qWarning(
"3D texture cannot be multisample");
8108 qWarning(
"Multisample texture cannot have mipmaps");
8112 if (isCube && is3D) {
8113 qWarning(
"Texture cannot be both cube and 3D");
8116 if (isArray && is3D) {
8117 qWarning(
"Texture cannot be both array and 3D");
8120 if (isCube && is1D) {
8121 qWarning(
"Texture cannot be both cube and 1D");
8125 qWarning(
"Texture cannot be both 1D and 3D");
8128 if (m_depth > 1 && !is3D) {
8129 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
8132 if (m_arraySize > 0 && !isArray) {
8133 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
8136 if (m_arraySize < 1 && isArray) {
8137 qWarning(
"Texture is an array but array size is %d", m_arraySize);
8141 usageState.layout = VK_IMAGE_LAYOUT_UNDEFINED;
8142 usageState.access = 0;
8143 usageState.stage = 0;
8145 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
8149 *adjustedSize = size;
8158 const auto aspectMask = aspectMaskForTextureFormat(m_format);
8159 const bool isCube = m_flags.testFlag(CubeMap);
8160 const bool isArray = m_flags.testFlag(TextureArray);
8161 const bool is3D = m_flags.testFlag(ThreeDimensional);
8162 const bool is1D = m_flags.testFlag(OneDimensional);
8164 VkImageViewCreateInfo viewInfo = {};
8165 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8166 viewInfo.image = image;
8167 viewInfo.viewType = isCube
8168 ? VK_IMAGE_VIEW_TYPE_CUBE
8169 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8170 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8171 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8172 viewInfo.format = viewFormatForSampling;
8173 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8174 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8175 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8176 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8177 viewInfo.subresourceRange.aspectMask = aspectMask;
8180 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8182 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
8183 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
8184 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
8186 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8189 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
8190 if (err != VK_SUCCESS) {
8191 qWarning(
"Failed to create image view: %d", err);
8204 if (!prepareCreate(&size))
8208 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
8209 const bool isDepth = isDepthTextureFormat(m_format);
8210 const bool isCube = m_flags.testFlag(CubeMap);
8211 const bool isArray = m_flags.testFlag(TextureArray);
8212 const bool is3D = m_flags.testFlag(ThreeDimensional);
8213 const bool is1D = m_flags.testFlag(OneDimensional);
8215 VkImageCreateInfo imageInfo = {};
8216 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
8217 imageInfo.flags = 0;
8219 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
8220 if (viewFormat != vkformat || viewFormatForSampling != vkformat)
8221 imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
8223 if (is3D && isRenderTarget) {
8229 if (!rhiD->caps.texture3DSliceAs2D)
8230 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
8231#ifdef VK_VERSION_1_1
8232 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
8234 imageInfo.flags |= 0x00000020;
8238 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
8239 imageInfo.format = vkformat;
8240 imageInfo.extent.width = uint32_t(size.width());
8241 imageInfo.extent.height = uint32_t(size.height());
8242 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
8244 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8245 imageInfo.samples = samples;
8246 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
8249 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
8251 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
8252 if (isRenderTarget) {
8254 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
8256 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
8258 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
8259 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8260 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
8261 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8262 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
8263 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
8264#ifdef VK_KHR_fragment_shading_rate
8265 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
8266 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
8269 VmaAllocationCreateInfo allocInfo = {};
8270 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
8272 VmaAllocation allocation;
8273 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
8274 if (err != VK_SUCCESS) {
8275 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
8276 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
8277 int(imageInfo.format),
8278 imageInfo.mipLevels,
8279 imageInfo.arrayLayers,
8280 int(imageInfo.samples),
8282 rhiD->printExtraErrorInfo(err);
8286 rhiD->setAllocationName(allocation, m_objectName);
8291 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
8294 rhiD->registerResource(
this);
8300 VkImage img = VkImage(src.object);
8304 if (!prepareCreate())
8312 usageState.layout = VkImageLayout(src.layout);
8316 rhiD->registerResource(
this);
8322 return {quint64(image), usageState.layout};
8327 usageState.layout = VkImageLayout(layout);
8333 if (perLevelImageViews[level] != VK_NULL_HANDLE)
8334 return perLevelImageViews[level];
8336 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
8337 const bool isCube = m_flags.testFlag(CubeMap);
8338 const bool isArray = m_flags.testFlag(TextureArray);
8339 const bool is3D = m_flags.testFlag(ThreeDimensional);
8340 const bool is1D = m_flags.testFlag(OneDimensional);
8342 VkImageViewCreateInfo viewInfo = {};
8343 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8344 viewInfo.image = image;
8345 viewInfo.viewType = isCube
8346 ? VK_IMAGE_VIEW_TYPE_CUBE
8347 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8348 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8349 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8350 viewInfo.format = viewFormat;
8351 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8352 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8353 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8354 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8355 viewInfo.subresourceRange.aspectMask = aspectMask;
8356 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
8357 viewInfo.subresourceRange.levelCount = 1;
8358 viewInfo.subresourceRange.baseArrayLayer = 0;
8359 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8361 VkImageView v = VK_NULL_HANDLE;
8363 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
8364 if (err != VK_SUCCESS) {
8365 qWarning(
"Failed to create image view: %d", err);
8366 return VK_NULL_HANDLE;
8369 perLevelImageViews[level] = v;
8374 AddressMode u, AddressMode v, AddressMode w)
8393 e.sampler.sampler = sampler;
8394 sampler = VK_NULL_HANDLE;
8398 rhiD->releaseQueue.append(e);
8399 rhiD->unregisterResource(
this);
8408 VkSamplerCreateInfo samplerInfo = {};
8409 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
8410 samplerInfo.magFilter = toVkFilter(m_magFilter);
8411 samplerInfo.minFilter = toVkFilter(m_minFilter);
8412 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
8413 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
8414 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
8415 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
8416 samplerInfo.maxAnisotropy = 1.0f;
8417 samplerInfo.compareEnable = m_compareOp != Never;
8418 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
8419 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
8422 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
8423 if (err != VK_SUCCESS) {
8424 qWarning(
"Failed to create sampler: %d", err);
8430 rhiD->registerResource(
this);
8437 serializedFormatData.reserve(64);
8451 rp = VK_NULL_HANDLE;
8459 e.renderPass.rp = rp;
8461 rp = VK_NULL_HANDLE;
8465 rhiD->releaseQueue.append(e);
8466 rhiD->unregisterResource(
this);
8472 return a.format == b.format
8473 && a.samples == b.samples
8474 && a.loadOp == b.loadOp
8475 && a.storeOp == b.storeOp
8476 && a.stencilLoadOp == b.stencilLoadOp
8477 && a.stencilStoreOp == b.stencilStoreOp
8478 && a.initialLayout == b.initialLayout
8479 && a.finalLayout == b.finalLayout;
8492 if (attDescs.size() != o->attDescs.size())
8494 if (colorRefs.size() != o->colorRefs.size())
8496 if (resolveRefs.size() != o->resolveRefs.size())
8502 if (multiViewCount != o->multiViewCount)
8507 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8508 const uint32_t attIdx = colorRefs[i].attachment;
8509 if (attIdx != o->colorRefs[i].attachment)
8511 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8516 const uint32_t attIdx = dsRef.attachment;
8517 if (attIdx != o->dsRef.attachment)
8519 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8523 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8524 const uint32_t attIdx = resolveRefs[i].attachment;
8525 if (attIdx != o->resolveRefs[i].attachment)
8527 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8532 const uint32_t attIdx = dsResolveRef.attachment;
8533 if (attIdx != o->dsResolveRef.attachment)
8535 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8540 const uint32_t attIdx = shadingRateRef.attachment;
8541 if (attIdx != o->shadingRateRef.attachment)
8543 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8554 serializedFormatData.clear();
8555 auto p =
std::back_inserter(serializedFormatData);
8557 *p++ = attDescs.size();
8558 *p++ = colorRefs.size();
8559 *p++ = resolveRefs.size();
8563 *p++ = multiViewCount;
8565 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8566 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8567 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8568 *p++ = used ? a->format : 0;
8569 *p++ = used ? a->samples : 0;
8570 *p++ = used ? a->loadOp : 0;
8571 *p++ = used ? a->storeOp : 0;
8572 *p++ = used ? a->stencilLoadOp : 0;
8573 *p++ = used ? a->stencilStoreOp : 0;
8574 *p++ = used ? a->initialLayout : 0;
8575 *p++ = used ? a->finalLayout : 0;
8578 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8579 const uint32_t attIdx = colorRefs[i].attachment;
8581 serializeAttachmentData(attIdx);
8585 const uint32_t attIdx = dsRef.attachment;
8587 serializeAttachmentData(attIdx);
8590 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8591 const uint32_t attIdx = resolveRefs[i].attachment;
8593 serializeAttachmentData(attIdx);
8597 const uint32_t attIdx = dsResolveRef.attachment;
8599 serializeAttachmentData(attIdx);
8603 const uint32_t attIdx = shadingRateRef.attachment;
8605 serializeAttachmentData(attIdx);
8614 rpD->attDescs = attDescs;
8615 rpD->colorRefs = colorRefs;
8616 rpD->resolveRefs = resolveRefs;
8617 rpD->subpassDeps = subpassDeps;
8621 rpD->multiViewCount = multiViewCount;
8623 rpD->dsResolveRef = dsResolveRef;
8624 rpD->shadingRateRef = shadingRateRef;
8626 VkRenderPassCreateInfo rpInfo;
8627 VkSubpassDescription subpassDesc;
8628 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8632 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8637#ifdef VK_KHR_create_renderpass2
8638 if (rhiD->caps.renderPass2KHR) {
8640 VkRenderPassCreateInfo2KHR rpInfo2;
8641 RenderPass2SetupHelper rp2Helper(rhiD);
8642 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8646 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8647 if (err != VK_SUCCESS) {
8648 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8655 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8656 if (err != VK_SUCCESS) {
8657 qWarning(
"Failed to create renderpass: %d", err);
8664 rhiD->registerResource(rpD);
8670 return serializedFormatData;
8675 nativeHandlesStruct.renderPass = rp;
8676 return &nativeHandlesStruct;
8702 texture =
QRHI_RES(QVkTexture, src);
8734 return d.sampleCount;
8738 const QRhiTextureRenderTargetDescription &desc,
8743 rtv[att] = VK_NULL_HANDLE;
8744 resrtv[att] = VK_NULL_HANDLE;
8762 e.textureRenderTarget.fb = d.fb;
8763 d.fb = VK_NULL_HANDLE;
8766 e.textureRenderTarget.rtv[att] = rtv[att];
8767 e.textureRenderTarget.resrtv[att] = resrtv[att];
8768 rtv[att] = VK_NULL_HANDLE;
8769 resrtv[att] = VK_NULL_HANDLE;
8772 e.textureRenderTarget.dsv = dsv;
8773 dsv = VK_NULL_HANDLE;
8774 e.textureRenderTarget.resdsv = resdsv;
8775 resdsv = VK_NULL_HANDLE;
8777 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8778 shadingRateMapView = VK_NULL_HANDLE;
8782 rhiD->releaseQueue.append(e);
8783 rhiD->unregisterResource(
this);
8793 if (!rhiD->createOffscreenRenderPass(rp,
8794 m_desc.cbeginColorAttachments(),
8795 m_desc.cendColorAttachments(),
8796 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8797 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8798 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8799 m_desc.depthStencilBuffer(),
8800 m_desc.depthTexture(),
8801 m_desc.depthResolveTexture(),
8802 m_desc.depthLayer(),
8803 m_desc.shadingRateMap()))
8811 rhiD->registerResource(rp);
8820 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8821 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8822 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8825 QVarLengthArray<VkImageView, 8> views;
8826 d.multiViewCount = 0;
8828 d.colorAttCount = 0;
8830 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8831 d.colorAttCount += 1;
8834 Q_ASSERT(texD || rbD);
8836 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8837 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8838 const bool isMultiView = it->multiViewCount() >= 2;
8839 if (isMultiView && d.multiViewCount == 0)
8840 d.multiViewCount = it->multiViewCount();
8841 VkImageViewCreateInfo viewInfo = {};
8842 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8843 viewInfo.image = texD->image;
8844 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8845 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8846 : VK_IMAGE_VIEW_TYPE_2D);
8847 viewInfo.format = texD->viewFormat;
8848 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8849 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8850 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8851 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8852 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8853 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8854 viewInfo.subresourceRange.levelCount = 1;
8855 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8856 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8857 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8858 if (err != VK_SUCCESS) {
8859 qWarning(
"Failed to create render target image view: %d", err);
8862 views.append(rtv[attIndex]);
8863 if (attIndex == 0) {
8864 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8865 d.sampleCount = texD->samples;
8870 if (attIndex == 0) {
8871 d.pixelSize = rbD->pixelSize();
8872 d.sampleCount = rbD->samples;
8878 if (hasDepthStencil) {
8879 if (m_desc.depthTexture()) {
8882 VkImageViewCreateInfo viewInfo = {};
8883 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8884 viewInfo.image = depthTexD->image;
8885 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8886 viewInfo.format = depthTexD->viewFormat;
8887 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8888 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8889 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8890 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8891 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8892 viewInfo.subresourceRange.levelCount = 1;
8893 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8894 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8895 viewInfo.subresourceRange.layerCount = 1;
8898 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8899 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8900 if (err != VK_SUCCESS) {
8901 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8905 if (d.colorAttCount == 0) {
8906 d.pixelSize = depthTexD->pixelSize();
8907 d.sampleCount = depthTexD->samples;
8911 views.append(depthRbD->imageView);
8912 if (d.colorAttCount == 0) {
8913 d.pixelSize = depthRbD->pixelSize();
8914 d.sampleCount = depthRbD->samples;
8922 d.resolveAttCount = 0;
8924 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8925 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8926 if (it->resolveTexture()) {
8928 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8929 d.resolveAttCount += 1;
8931 VkImageViewCreateInfo viewInfo = {};
8932 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8933 viewInfo.image = resTexD->image;
8934 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8935 : VK_IMAGE_VIEW_TYPE_2D;
8936 viewInfo.format = resTexD->viewFormat;
8937 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8938 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8939 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8940 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8941 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8942 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8943 viewInfo.subresourceRange.levelCount = 1;
8944 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8945 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8946 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8947 if (err != VK_SUCCESS) {
8948 qWarning(
"Failed to create render target resolve image view: %d", err);
8951 views.append(resrtv[attIndex]);
8955 if (m_desc.depthResolveTexture()) {
8957 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8959 VkImageViewCreateInfo viewInfo = {};
8960 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8961 viewInfo.image = resTexD->image;
8962 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8963 : VK_IMAGE_VIEW_TYPE_2D;
8964 viewInfo.format = resTexD->viewFormat;
8965 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8966 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8967 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8968 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8969 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8970 viewInfo.subresourceRange.baseMipLevel = 0;
8971 viewInfo.subresourceRange.levelCount = 1;
8972 viewInfo.subresourceRange.baseArrayLayer = 0;
8973 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8974 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8975 if (err != VK_SUCCESS) {
8976 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8979 views.append(resdsv);
8980 d.dsResolveAttCount = 1;
8982 d.dsResolveAttCount = 0;
8985 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8987 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8989 VkImageViewCreateInfo viewInfo = {};
8990 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8991 viewInfo.image = texD->image;
8992 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8993 : VK_IMAGE_VIEW_TYPE_2D;
8994 viewInfo.format = texD->viewFormat;
8995 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8996 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8997 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8998 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8999 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
9000 viewInfo.subresourceRange.baseMipLevel = 0;
9001 viewInfo.subresourceRange.levelCount = 1;
9002 viewInfo.subresourceRange.baseArrayLayer = 0;
9003 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
9004 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
9005 if (err != VK_SUCCESS) {
9006 qWarning(
"Failed to create render target shading rate map view: %d", err);
9009 views.append(shadingRateMapView);
9010 d.shadingRateAttCount = 1;
9012 d.shadingRateAttCount = 0;
9015 if (!m_renderPassDesc)
9016 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9018 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9019 Q_ASSERT(d.rp && d.rp->rp);
9021 VkFramebufferCreateInfo fbInfo = {};
9022 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9023 fbInfo.renderPass = d.rp->rp;
9024 fbInfo.attachmentCount = uint32_t(views.count());
9025 fbInfo.pAttachments = views.constData();
9026 fbInfo.width = uint32_t(d.pixelSize.width());
9027 fbInfo.height = uint32_t(d.pixelSize.height());
9030 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
9031 if (err != VK_SUCCESS) {
9032 qWarning(
"Failed to create framebuffer: %d", err);
9036 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
9039 rhiD->registerResource(
this);
9045 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
9058 return d.sampleCount;
9076 sortedBindings.clear();
9077 sortedDynamicOffsetBindingNumbers.clear();
9083 e.shaderResourceBindings.poolIndex =
poolIndex;
9084 e.shaderResourceBindings.layout = layout;
9087 layout = VK_NULL_HANDLE;
9088 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9089 descSets[i] = VK_NULL_HANDLE;
9093 rhiD->releaseQueue.append(e);
9094 rhiD->unregisterResource(
this);
9104 if (!rhiD->sanityCheckShaderResourceBindings(
this))
9107 rhiD->updateLayoutDesc(
this);
9109 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9110 descSets[i] = VK_NULL_HANDLE;
9112 sortedBindings.clear();
9113 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
9114 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
9116 sortedDynamicOffsetBindingNumbers.clear();
9117 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9118 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9119 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
9120 if (b->u.ubuf.hasDynamicOffset)
9121 sortedDynamicOffsetBindingNumbers.append(b->binding);
9125 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
9126 vkbindings.reserve(sortedBindings.size());
9127 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9128 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9129 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
9130 vkbinding.binding = uint32_t(b->binding);
9131 vkbinding.descriptorType = toVkDescriptorType(b);
9132 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
9133 vkbinding.descriptorCount = b->stex.count();
9135 vkbinding.descriptorCount = 1;
9136 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
9139 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
9140 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
9141 layoutInfo.bindingCount = uint32_t(vkbindings.size());
9142 layoutInfo.pBindings = vkbindings.constData();
9144 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
9145 if (err != VK_SUCCESS) {
9146 qWarning(
"Failed to create descriptor set layout: %d", err);
9149 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
9151 VkDescriptorSetAllocateInfo allocInfo = {};
9152 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
9155 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9156 layouts[i] = layout;
9157 allocInfo.pSetLayouts = layouts;
9158 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
9162 boundResourceData[i].resize(sortedBindings.size());
9163 for (BoundResourceData &bd : boundResourceData[i])
9168 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
9172 rhiD->registerResource(
this);
9178 sortedBindings.clear();
9179 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
9180 if (!flags.testFlag(BindingsAreSorted))
9181 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
9183 sortedDynamicOffsetBindingNumbers.clear();
9184 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9185 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9186 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
9187 if (b->u.ubuf.hasDynamicOffset)
9188 sortedDynamicOffsetBindingNumbers.append(b->binding);
9202 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
9203 for (BoundResourceData &bd : boundResourceData[i])
9222 if (!pipeline && !layout)
9229 e.pipelineState.pipeline = pipeline;
9230 e.pipelineState.layout = layout;
9232 pipeline = VK_NULL_HANDLE;
9233 layout = VK_NULL_HANDLE;
9237 rhiD->releaseQueue.append(e);
9238 rhiD->unregisterResource(
this);
9244 if (pipeline || layout)
9248 rhiD->pipelineCreationStart();
9249 if (!rhiD->sanityCheckGraphicsPipeline(
this))
9252 if (!rhiD->ensurePipelineCache())
9255 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9256 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9257 pipelineLayoutInfo.setLayoutCount = 1;
9259 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9260 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9261 VkPushConstantRange pushConstantRange = {};
9262 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
9263 for (
const QShaderDescription::PushConstantBlock &block : shaderStage.shader().description().pushConstantBlocks()) {
9264 pushConstantRange.stageFlags |= toVkShaderStage(shaderStage.type());
9265 pushConstantRange.size = qMax(pushConstantRange.size, uint32_t((block.size + 3) & ~3));
9268 if (pushConstantRange.size) {
9269 pipelineLayoutInfo.pushConstantRangeCount = 1;
9270 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
9272 pushConstantStages = pushConstantRange.stageFlags;
9273 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9274 if (err != VK_SUCCESS) {
9275 qWarning(
"Failed to create pipeline layout: %d", err);
9278 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9279 rhiD->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9280 layout = VK_NULL_HANDLE;
9283 VkGraphicsPipelineCreateInfo pipelineInfo = {};
9284 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
9286 QVarLengthArray<VkShaderModule, 4> shaders;
9287 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
9288 for (VkShaderModule shader : shaders)
9289 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9291 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
9292 QVarLengthArray<QByteArray, 4> entryPointNames;
9293 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
9294 const QShader bakedShader = shaderStage.shader();
9295 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
9296 if (spirv.shader().isEmpty()) {
9297 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9300 VkShaderModule shader = rhiD->createShader(spirv.shader());
9302 shaders.append(shader);
9303 VkPipelineShaderStageCreateInfo shaderInfo = {};
9304 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9305 shaderInfo.stage = toVkShaderStage(shaderStage.type());
9306 shaderInfo.module = shader;
9307 entryPointNames.append(spirv.entryPoint());
9308 shaderInfo.pName =
nullptr;
9309 shaderStageCreateInfos.append(shaderInfo);
9314 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
9315 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
9317 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
9318 pipelineInfo.pStages = shaderStageCreateInfos.constData();
9320 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
9321#ifdef VK_EXT_vertex_attribute_divisor
9322 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
9324 int bindingIndex = 0;
9325 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
9326 it != itEnd; ++it, ++bindingIndex)
9328 VkVertexInputBindingDescription bindingInfo = {
9329 uint32_t(bindingIndex),
9331 it->classification() == QRhiVertexInputBinding::PerVertex
9332 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
9334 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
9335#ifdef VK_EXT_vertex_attribute_divisor
9336 if (rhiD->caps.vertexAttribDivisor) {
9337 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
9341 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
9342 "VK_EXT_vertex_attribute_divisor on the device and "
9343 "VK_KHR_get_physical_device_properties2 on the instance");
9346 vertexBindings.append(bindingInfo);
9348 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
9349 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
9352 VkVertexInputAttributeDescription attributeInfo = {
9353 uint32_t(it->location()),
9354 uint32_t(it->binding()),
9355 toVkAttributeFormat(it->format()),
9358 vertexAttributes.append(attributeInfo);
9360 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
9361 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
9362 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
9363 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
9364 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
9365 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
9366#ifdef VK_EXT_vertex_attribute_divisor
9367 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
9368 if (!nonOneStepRates.isEmpty()) {
9369 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
9370 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
9371 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
9372 vertexInputInfo.pNext = &divisorInfo;
9375 pipelineInfo.pVertexInputState = &vertexInputInfo;
9377 QVarLengthArray<VkDynamicState, 8> dynEnable;
9378 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
9379 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
9380 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
9381 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
9382 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
9383 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
9384#ifdef VK_KHR_fragment_shading_rate
9385 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
9386 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
9389 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
9390 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
9391 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
9392 dynamicInfo.pDynamicStates = dynEnable.constData();
9393 pipelineInfo.pDynamicState = &dynamicInfo;
9395 VkPipelineViewportStateCreateInfo viewportInfo = {};
9396 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
9397 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
9398 pipelineInfo.pViewportState = &viewportInfo;
9400 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
9401 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
9402 inputAsmInfo.topology = toVkTopology(m_topology);
9403 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
9404 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
9406 VkPipelineTessellationStateCreateInfo tessInfo = {};
9407#ifdef VK_VERSION_1_1
9408 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
9410 if (m_topology == Patches) {
9411 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
9412 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
9419#ifdef VK_VERSION_1_1
9420 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
9421 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
9422 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
9423 tessInfo.pNext = &originInfo;
9425 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
9428 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
9431 pipelineInfo.pTessellationState = &tessInfo;
9434 VkPipelineRasterizationStateCreateInfo rastInfo = {};
9435 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
9436 if (m_depthClamp && rhiD->caps.depthClamp)
9437 rastInfo.depthClampEnable = m_depthClamp;
9438 rastInfo.cullMode = toVkCullMode(m_cullMode);
9439 rastInfo.frontFace = toVkFrontFace(m_frontFace);
9440 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
9441 rastInfo.depthBiasEnable =
true;
9442 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
9443 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
9445 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
9446 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
9447 pipelineInfo.pRasterizationState = &rastInfo;
9449 VkPipelineMultisampleStateCreateInfo msInfo = {};
9450 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
9451 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
9452 pipelineInfo.pMultisampleState = &msInfo;
9454 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
9455 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
9456 dsInfo.depthTestEnable = m_depthTest;
9457 dsInfo.depthWriteEnable = m_depthWrite;
9458 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
9459 dsInfo.stencilTestEnable = m_stencilTest;
9460 if (m_stencilTest) {
9461 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
9462 dsInfo.front.compareMask = m_stencilReadMask;
9463 dsInfo.front.writeMask = m_stencilWriteMask;
9464 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
9465 dsInfo.back.compareMask = m_stencilReadMask;
9466 dsInfo.back.writeMask = m_stencilWriteMask;
9468 pipelineInfo.pDepthStencilState = &dsInfo;
9470 VkPipelineColorBlendStateCreateInfo blendInfo = {};
9471 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
9472 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
9473 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
9474 VkPipelineColorBlendAttachmentState blend = {};
9475 blend.blendEnable = b.enable;
9476 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
9477 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
9478 blend.colorBlendOp = toVkBlendOp(b.opColor);
9479 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
9480 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
9481 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
9482 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
9483 vktargetBlends.append(blend);
9485 if (vktargetBlends.isEmpty()) {
9486 VkPipelineColorBlendAttachmentState blend = {};
9487 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
9488 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
9489 vktargetBlends.append(blend);
9491 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
9492 blendInfo.pAttachments = vktargetBlends.constData();
9493 pipelineInfo.pColorBlendState = &blendInfo;
9495 pipelineInfo.layout = layout;
9497 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
9498 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
9500 err = rhiD->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9502 if (err != VK_SUCCESS) {
9503 qWarning(
"Failed to create graphics pipeline: %d", err);
9506 pipelineLayoutCleanup.dismiss();
9508 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9510 rhiD->pipelineCreationEnd();
9511 lastActiveFrameSlot = -1;
9513 rhiD->registerResource(
this);
9517QVkComputePipeline::QVkComputePipeline(QRhiImplementation *rhi)
9518 : QRhiComputePipeline(rhi)
9522QVkComputePipeline::~QVkComputePipeline()
9527void QVkComputePipeline::destroy()
9529 if (!pipeline && !layout)
9532 QRhiVulkan::DeferredReleaseEntry e;
9533 e.type = QRhiVulkan::DeferredReleaseEntry::Pipeline;
9534 e.lastActiveFrameSlot = lastActiveFrameSlot;
9536 e.pipelineState.pipeline = pipeline;
9537 e.pipelineState.layout = layout;
9539 pipeline = VK_NULL_HANDLE;
9540 layout = VK_NULL_HANDLE;
9544 rhiD->releaseQueue.append(e);
9545 rhiD->unregisterResource(
this);
9549bool QVkComputePipeline::create()
9551 if (pipeline || layout)
9555 rhiD->pipelineCreationStart();
9556 if (!rhiD->ensurePipelineCache())
9559 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9560 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9561 pipelineLayoutInfo.setLayoutCount = 1;
9562 QVkShaderResourceBindings *srbD =
QRHI_RES(QVkShaderResourceBindings, m_shaderResourceBindings);
9563 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9564 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9565 VkPushConstantRange pushConstantRange = {};
9566 for (
const QShaderDescription::PushConstantBlock &block : m_shaderStage.shader().description().pushConstantBlocks()) {
9567 pushConstantRange.stageFlags |= VK_SHADER_STAGE_COMPUTE_BIT;
9568 pushConstantRange.size = qMax(pushConstantRange.size, uint32_t((block.size + 3) & ~3));
9570 if (pushConstantRange.size) {
9571 pipelineLayoutInfo.pushConstantRangeCount = 1;
9572 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
9574 pushConstantStages = pushConstantRange.stageFlags;
9575 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9576 if (err != VK_SUCCESS) {
9577 qWarning(
"Failed to create pipeline layout: %d", err);
9580 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9581 rhiD->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9582 layout = VK_NULL_HANDLE;
9585 VkComputePipelineCreateInfo pipelineInfo = {};
9586 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9587 pipelineInfo.layout = layout;
9589 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9590 qWarning(
"Compute pipeline requires a compute shader stage");
9593 const QShader bakedShader = m_shaderStage.shader();
9594 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9595 if (spirv.shader().isEmpty()) {
9596 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9599 if (bakedShader.stage() != QShader::ComputeStage) {
9600 qWarning() << bakedShader <<
"is not a compute shader";
9603 VkShaderModule shader = rhiD->createShader(spirv.shader());
9606 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9607 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9609 VkPipelineShaderStageCreateInfo shaderInfo = {};
9610 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9611 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9612 shaderInfo.module = shader;
9613 const QByteArray entryPointName = spirv.entryPoint();
9614 shaderInfo.pName = entryPointName.constData();
9615 pipelineInfo.stage = shaderInfo;
9617 err = rhiD->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9618 if (err != VK_SUCCESS) {
9619 qWarning(
"Failed to create graphics pipeline: %d", err);
9622 pipelineLayoutCleanup.dismiss();
9624 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9626 rhiD->pipelineCreationEnd();
9627 lastActiveFrameSlot = -1;
9629 rhiD->registerResource(
this);
9633QVkCommandBuffer::QVkCommandBuffer(QRhiImplementation *rhi)
9634 : QRhiCommandBuffer(rhi)
9639QVkCommandBuffer::~QVkCommandBuffer()
9644void QVkCommandBuffer::destroy()
9649const QRhiNativeHandles *QVkCommandBuffer::nativeHandles()
9657 if (recordingPass == QVkCommandBuffer::NoPass) {
9658 nativeHandlesStruct.commandBuffer = cb;
9660 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9661 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9663 nativeHandlesStruct.commandBuffer = cb;
9666 return &nativeHandlesStruct;
9669QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi)
9670 : QRhiSwapChain(rhi),
9671 rtWrapper(rhi,
this),
9672 rtWrapperRight(rhi,
this),
9677QVkSwapChain::~QVkSwapChain()
9682void QVkSwapChain::destroy()
9684 if (sc == VK_NULL_HANDLE)
9689 rhiD->swapchains.remove(
this);
9690 rhiD->releaseSwapChainResources(
this);
9693 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) {
9694 QVkSwapChain::FrameResources &frame(frameRes[i]);
9695 frame.cmdBuf = VK_NULL_HANDLE;
9696 frame.timestampQueryIndex = -1;
9699 surface = lastConnectedSurface = VK_NULL_HANDLE;
9702 rhiD->unregisterResource(
this);
9705QRhiCommandBuffer *QVkSwapChain::currentFrameCommandBuffer()
9710QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget()
9715QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
9717 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9720QSize QVkSwapChain::surfacePixelSize()
9722 if (!ensureSurface())
9727 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9729 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9730 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9731 if (bufferSize.width == uint32_t(-1)) {
9732 Q_ASSERT(bufferSize.height == uint32_t(-1));
9733 return m_window->size() * m_window->devicePixelRatio();
9735 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9738static inline bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f,
const VkSurfaceFormatKHR &s)
9741 case QRhiSwapChain::HDRExtendedSrgbLinear:
9742 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9743 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9744 case QRhiSwapChain::HDR10:
9745 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9746 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9747 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9748 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9749 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9756bool QVkSwapChain::isFormatSupported(Format f)
9762 qWarning(
"Attempted to call isFormatSupported() without a window set");
9767 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9770 uint32_t formatCount = 0;
9771 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9772 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9774 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9775 for (uint32_t i = 0; i < formatCount; ++i) {
9776 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9784QRhiSwapChainHdrInfo QVkSwapChain::hdrInfo()
9786 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
9788 QRHI_RES_RHI(QRhiVulkan);
9790 if (m_window && rhiD->adapterLuidValid)
9791 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9796QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor()
9800 if (!ensureSurface())
9804 QVkRenderPassDescriptor *rp =
new QVkRenderPassDescriptor(m_rhi);
9805 if (!rhiD->createDefaultRenderPass(rp,
9806 m_depthStencil !=
nullptr,
9816 rp->updateSerializedFormat();
9817 rhiD->registerResource(rp);
9821static inline bool isSrgbFormat(VkFormat format)
9824 case VK_FORMAT_R8_SRGB:
9825 case VK_FORMAT_R8G8_SRGB:
9826 case VK_FORMAT_R8G8B8_SRGB:
9827 case VK_FORMAT_B8G8R8_SRGB:
9828 case VK_FORMAT_R8G8B8A8_SRGB:
9829 case VK_FORMAT_B8G8R8A8_SRGB:
9830 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9837bool QVkSwapChain::ensureSurface()
9845 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9847 qWarning(
"Failed to get surface for window");
9850 if (surface == surf)
9856 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9857 qWarning(
"Presenting not supported on this window");
9861 quint32 formatCount = 0;
9862 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9863 QList<VkSurfaceFormatKHR> formats(formatCount);
9864 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9868 colorFormat = formats.constFirst().format;
9869 colorSpace = formats.constFirst().colorSpace;
9872 const bool srgbRequested = m_flags.testFlag(sRGB);
9873 bool foundBestFormat =
false;
9874 if (m_format == SDR) {
9875 for (
int i = 0; i <
int(formatCount); ++i) {
9877 if (srgbRequested) {
9878 ok = defaultSrgbColorFormat == formats[i].format;
9880 ok = defaultColorFormat == formats[i].format;
9883 foundBestFormat =
true;
9884 colorFormat = formats[i].format;
9885 colorSpace = formats[i].colorSpace;
9892 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9893 for (
int i = 0; i <
int(formatCount); ++i) {
9895 if (m_format != SDR) {
9896 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9897 }
else if (srgbRequested) {
9898 ok = isSrgbFormat(formats[i].format);
9901 colorFormat = formats[i].format;
9902 colorSpace = formats[i].colorSpace;
9909 if (m_format != SDR) {
9910 VkSurfaceFormatKHR format{};
9911 format.format = colorFormat;
9912 format.colorSpace = colorSpace;
9913 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9914 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9918 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9919 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9924#if QT_CONFIG(wayland)
9929 const bool hasPassThrough =
9930 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9931 return fmt.format == colorFormat
9932 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9934 if (hasPassThrough) {
9935 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9939 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9941 quint32 presModeCount = 0;
9942 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9943 supportedPresentationModes.resize(presModeCount);
9944 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9945 supportedPresentationModes.data());
9950bool QVkSwapChain::createOrResize()
9953 const bool needsRegistration = !window || window != m_window;
9960 if (window && window != m_window)
9964 m_currentPixelSize = surfacePixelSize();
9965 pixelSize = m_currentPixelSize;
9967 if (!rhiD->recreateSwapChain(
this)) {
9968 qWarning(
"Failed to create new swapchain");
9972 if (needsRegistration || !rhiD->swapchains.contains(
this))
9973 rhiD->swapchains.insert(
this);
9975 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9976 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9977 m_depthStencil->sampleCount(), m_sampleCount);
9979 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9980 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9981 m_depthStencil->setPixelSize(pixelSize);
9982 if (!m_depthStencil->create())
9983 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9984 pixelSize.width(), pixelSize.height());
9986 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9987 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9988 pixelSize.width(), pixelSize.height());
9992 if (!m_renderPassDesc)
9993 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9995 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9996 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9997 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9999 rtWrapper.d.pixelSize = pixelSize;
10000 rtWrapper.d.dpr =
float(window->devicePixelRatio());
10001 rtWrapper.d.sampleCount = samples;
10002 rtWrapper.d.colorAttCount = 1;
10003 if (m_depthStencil) {
10004 rtWrapper.d.dsAttCount = 1;
10005 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
10007 rtWrapper.d.dsAttCount = 0;
10010 rtWrapper.d.dsResolveAttCount = 0;
10011 if (samples > VK_SAMPLE_COUNT_1_BIT)
10012 rtWrapper.d.resolveAttCount = 1;
10014 rtWrapper.d.resolveAttCount = 0;
10016 if (shadingRateMapView)
10017 rtWrapper.d.shadingRateAttCount = 1;
10019 rtWrapper.d.shadingRateAttCount = 0;
10021 for (
int i = 0; i < bufferCount; ++i) {
10022 QVkSwapChain::ImageResources &image(imageRes[i]);
10024 QVarLengthArray<VkImageView, 4> views;
10025 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
10027 views.append(ds->imageView);
10028 if (samples > VK_SAMPLE_COUNT_1_BIT)
10029 views.append(image.imageView);
10030 if (shadingRateMapView)
10031 views.append(shadingRateMapView);
10033 VkFramebufferCreateInfo fbInfo = {};
10034 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
10035 fbInfo.renderPass = rtWrapper.d.rp->rp;
10036 fbInfo.attachmentCount = uint32_t(views.count());
10037 fbInfo.pAttachments = views.constData();
10038 fbInfo.width = uint32_t(pixelSize.width());
10039 fbInfo.height = uint32_t(pixelSize.height());
10042 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
10043 if (err != VK_SUCCESS) {
10044 qWarning(
"Failed to create framebuffer: %d", err);
10050 rtWrapperRight.setRenderPassDescriptor(
10052 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
10053 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
10055 rtWrapperRight.d.pixelSize = pixelSize;
10056 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
10057 rtWrapperRight.d.sampleCount = samples;
10058 rtWrapperRight.d.colorAttCount = 1;
10059 if (m_depthStencil) {
10060 rtWrapperRight.d.dsAttCount = 1;
10061 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
10063 rtWrapperRight.d.dsAttCount = 0;
10066 rtWrapperRight.d.dsResolveAttCount = 0;
10067 if (samples > VK_SAMPLE_COUNT_1_BIT)
10068 rtWrapperRight.d.resolveAttCount = 1;
10070 rtWrapperRight.d.resolveAttCount = 0;
10072 for (
int i = 0; i < bufferCount; ++i) {
10073 QVkSwapChain::ImageResources &image(imageRes[i + bufferCount]);
10075 QVarLengthArray<VkImageView, 4> views;
10076 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
10078 views.append(ds->imageView);
10079 if (samples > VK_SAMPLE_COUNT_1_BIT)
10080 views.append(image.imageView);
10081 if (shadingRateMapView)
10082 views.append(shadingRateMapView);
10084 VkFramebufferCreateInfo fbInfo = {};
10085 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
10086 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
10087 fbInfo.attachmentCount = uint32_t(views.count());
10088 fbInfo.pAttachments = views.constData();
10089 fbInfo.width = uint32_t(pixelSize.width());
10090 fbInfo.height = uint32_t(pixelSize.height());
10093 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
10094 if (err != VK_SUCCESS) {
10095 qWarning(
"Failed to create framebuffer: %d", err);
10103 if (needsRegistration)
10104 rhiD->registerResource(
this);
const char * constData() const
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 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)
VkSampleCountFlagBits mask
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 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)