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>
58
59
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
89
90
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
199
200
201
202
203
206
207
208
209
212
213
214
215
216
220
221
222
223
224
225
226
227
228
229
232
233
234
235
238
239
240
241
242
245
246
247
248
251
252
253
254
257
258
259
260
261
262
263
264
265
266
269
270
271
272
273
276
277
278
279
280
283
284
285
286
287
291
292
293
294
295
296
297
298
299
300
301
302
303
304
307
308
309
310
314
315
316
317
318
319
320
321
324
325
326
327
331
332
333
334
335
336
337
340
341
342
343
344
345
348
349
350
351
352
353
356
357
358
359
360
361
364
365
366
367
368
369
372
373
374
375
376
377
380
381
382
383
384
385
390struct QVkPhysicalDevicePortabilitySubsetFeatures
392 VkStructureType sType;
394 VkBool32 constantAlphaColorBlendFactors;
396 VkBool32 imageViewFormatReinterpretation;
397 VkBool32 imageViewFormatSwizzle;
398 VkBool32 imageView2DOn3DImage;
399 VkBool32 multisampleArrayImage;
400 VkBool32 mutableComparisonSamplers;
401 VkBool32 pointPolygons;
402 VkBool32 samplerMipLodBias;
403 VkBool32 separateStencilMaskRef;
404 VkBool32 shaderSampleRateInterpolationFunctions;
405 VkBool32 tessellationIsolines;
406 VkBool32 tessellationPointMode;
407 VkBool32 triangleFans;
408 VkBool32 vertexAttributeAccessBeyondStride;
411static const VkStructureType QVK_STRUCTURE_TYPE_PDPSF = VkStructureType(1000163000);
415inline Int aligned(Int v, Int byteAlign)
417 return (v + byteAlign - 1) & ~(byteAlign - 1);
422static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
424 return globalVulkanInstance->getInstanceProcAddr(pName);
427static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
429 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
434 return reinterpret_cast<VmaAllocation>(a);
439 return reinterpret_cast<VmaAllocator>(a);
443
444
445
446
447
448
449QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
452 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"),
454 QByteArrayLiteral(
"VK_EXT_swapchain_colorspace")
459
460
461
462
463QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
466 QByteArrayLiteral(
"VK_KHR_swapchain"),
467 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
468 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
469 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
470 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
483 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
484 inst = QVulkanDefaultInstance::instance();
488 requestedDeviceExtensions = params->deviceExtensions;
491 physDev = importParams->physDev;
492 dev = importParams->dev;
493 if (dev && physDev) {
495 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
496 gfxQueueIdx = importParams->gfxQueueIdx;
497 gfxQueueFlags = importParams->gfxQueueFlags;
499 if (importParams->vmemAllocator) {
508 QVulkanInstance::DebugMessageTypeFlags type,
509 const void *callbackData)
513#ifdef VK_EXT_debug_utils
514 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
518 if (strstr(d->pMessage,
"Mapping an image with layout")
519 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
530 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
533 Q_UNUSED(callbackData);
541 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
542 return QRhiDriverInfo::UnknownDevice;
543 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
544 return QRhiDriverInfo::IntegratedDevice;
545 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
546 return QRhiDriverInfo::DiscreteDevice;
547 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
548 return QRhiDriverInfo::VirtualDevice;
549 case VK_PHYSICAL_DEVICE_TYPE_CPU:
550 return QRhiDriverInfo::CpuDevice;
552 return QRhiDriverInfo::UnknownDevice;
556static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
558 info->deviceName = QByteArray(physDevProperties.deviceName);
559 info->deviceId = physDevProperties.deviceID;
560 info->vendorId = physDevProperties.vendorID;
561 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
567 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
569 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
575 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
581 if (!inst->isValid()) {
582 qWarning(
"Vulkan instance is not valid");
587 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
589 globalVulkanInstance = inst;
590 f = inst->functions();
591 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
592 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
593 const QByteArrayList extensions = inst->extensions();
594 for (
const char *ext : extensions)
595 qCDebug(QRHI_LOG_INFO,
" %s", ext);
599 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
601 QList<VkQueueFamilyProperties> queueFamilyProps;
602 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
603 uint32_t queueCount = 0;
604 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
605 queueFamilyProps.resize(
int(queueCount));
606 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
611 uint32_t physDevCount = 0;
612 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
614 qWarning(
"No physical devices");
617 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
618 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
619 if (err != VK_SUCCESS || !physDevCount) {
620 qWarning(
"Failed to enumerate physical devices: %d", err);
624 int physDevIndex = -1;
625 int requestedPhysDevIndex = -1;
626 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
627 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
629 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
630 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
631 for (
int i = 0; i <
int(physDevCount); ++i) {
632 if (physDevs[i] == requestedPhysDev) {
633 requestedPhysDevIndex = i;
639 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
640 for (
int i = 0; i <
int(physDevCount); ++i) {
641 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
642 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
643 requestedPhysDevIndex = i;
649 for (
int i = 0; i <
int(physDevCount); ++i) {
650 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
651 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
653 physDevProperties.deviceName,
654 VK_VERSION_MAJOR(physDevProperties.driverVersion),
655 VK_VERSION_MINOR(physDevProperties.driverVersion),
656 VK_VERSION_PATCH(physDevProperties.driverVersion),
657 VK_VERSION_MAJOR(physDevProperties.apiVersion),
658 VK_VERSION_MINOR(physDevProperties.apiVersion),
659 VK_VERSION_PATCH(physDevProperties.apiVersion),
660 physDevProperties.vendorID,
661 physDevProperties.deviceID,
662 physDevProperties.deviceType);
663 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
665 qCDebug(QRHI_LOG_INFO,
" using this physical device");
669 if (physDevIndex < 0) {
670 qWarning(
"No matching physical device");
673 physDev = physDevs[physDevIndex];
674 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
676 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
677 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
678 physDevProperties.deviceName,
679 VK_VERSION_MAJOR(physDevProperties.driverVersion),
680 VK_VERSION_MINOR(physDevProperties.driverVersion),
681 VK_VERSION_PATCH(physDevProperties.driverVersion),
682 VK_VERSION_MAJOR(physDevProperties.apiVersion),
683 VK_VERSION_MINOR(physDevProperties.apiVersion),
684 VK_VERSION_PATCH(physDevProperties.apiVersion),
685 physDevProperties.vendorID,
686 physDevProperties.deviceID,
687 physDevProperties.deviceType);
690 caps.apiVersion = inst->apiVersion();
696 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
697 VK_VERSION_MINOR(physDevProperties.apiVersion));
698 if (physDevApiVersion < caps.apiVersion) {
699 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
700 <<
"whereas the chosen physical device has" << physDevApiVersion
701 <<
"- restricting to the latter";
702 caps.apiVersion = physDevApiVersion;
707 QVulkanInfoVector<QVulkanExtension> devExts;
708 uint32_t devExtCount = 0;
709 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
711 QList<VkExtensionProperties> extProps(devExtCount);
712 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
713 for (
const VkExtensionProperties &p : std::as_const(extProps))
714 devExts.append({ p.extensionName, p.specVersion });
716 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
718 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
720 bool featuresQueried =
false;
722 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
723 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
726#ifdef VK_KHR_fragment_shading_rate
727 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
728 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
729 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
730 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
732#ifdef VK_EXT_device_fault
733 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
734 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
735 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
736 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
739 QVkPhysicalDevicePortabilitySubsetFeatures portabilitySubsetFeatures = {};
740 portabilitySubsetFeatures.sType = QVK_STRUCTURE_TYPE_PDPSF;
741 if (hasPhysDevProp2 && devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset")))
742 addToChain(&physDevFeaturesChainable, &portabilitySubsetFeatures);
747 if (!featuresQueried) {
749 if (caps.apiVersion >= QVersionNumber(1, 2)) {
750 physDevFeatures11IfApi12OrNewer = {};
751 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
752 physDevFeatures12 = {};
753 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
755 physDevFeatures13 = {};
756 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
758 physDevFeatures14 = {};
759 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
762 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
763 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
765 if (caps.apiVersion >= QVersionNumber(1, 3))
766 physDevFeatures12.pNext = &physDevFeatures13;
768 if (caps.apiVersion >= QVersionNumber(1, 4))
769 physDevFeatures13.pNext = &physDevFeatures14;
772 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
773 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
774 featuresQueried =
true;
781 if (!featuresQueried) {
789 if (caps.apiVersion == QVersionNumber(1, 1)) {
791 multiviewFeaturesIfApi11 = {};
792 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
793 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
796 shaderDrawParametersFeaturesIfApi11 = {};
797 shaderDrawParametersFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
798 addToChain(&physDevFeaturesChainable, &shaderDrawParametersFeaturesIfApi11);
800 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
801 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
802 featuresQueried =
true;
807 if (!featuresQueried) {
810 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
811 featuresQueried =
true;
819 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
820 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
821 queryQueueFamilyProps();
822 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
823 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
824 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
825 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
826 if (!gfxQueueFamilyIdxOpt.has_value()
827 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
828 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
830 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
831 gfxQueueFamilyIdxOpt = i;
832 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
833 computelessGfxQueueCandidateIdxOpt = i;
836 if (gfxQueueFamilyIdxOpt.has_value()) {
837 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
839 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
840 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
842 qWarning(
"No graphics (or no graphics+present) queue family found");
847 VkDeviceQueueCreateInfo queueInfo = {};
848 const float prio[] = { 0 };
849 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
850 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
851 queueInfo.queueCount = 1;
852 queueInfo.pQueuePriorities = prio;
854 QList<
const char *> requestedDevExts;
855 requestedDevExts.append(
"VK_KHR_swapchain");
857 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
858 if (hasPhysDevProp2) {
859 requestedDevExts.append(
"VK_KHR_portability_subset");
861 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
862 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
867#ifdef VK_EXT_vertex_attribute_divisor
868 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
869 if (hasPhysDevProp2) {
870 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
871 caps.vertexAttribDivisor =
true;
876#ifdef VK_KHR_create_renderpass2
877 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
881 bool canEnable =
true;
882 if (caps.apiVersion < QVersionNumber(1, 1)) {
883 canEnable = hasPhysDevProp2
884 && devExts.contains(QByteArrayLiteral(
"VK_KHR_multiview"))
885 && devExts.contains(QByteArrayLiteral(
"VK_KHR_maintenance2"));
887 requestedDevExts.append(
"VK_KHR_multiview");
888 requestedDevExts.append(
"VK_KHR_maintenance2");
892 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
893 caps.renderPass2KHR =
true;
898#ifdef VK_KHR_depth_stencil_resolve
900 const bool hasRenderPass2Dep = caps.renderPass2KHR || caps.apiVersion >= QVersionNumber(1, 2);
901 if (hasRenderPass2Dep && devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
902 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
903 caps.depthStencilResolveKHR =
true;
908#ifdef VK_KHR_fragment_shading_rate
910 const bool hasRenderPass2Dep = caps.renderPass2KHR || caps.apiVersion >= QVersionNumber(1, 2);
911 if (hasRenderPass2Dep && devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
912 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
916#ifdef VK_EXT_device_fault
917 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
918 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
919 caps.deviceFault =
true;
923 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
924 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
925 if (devExts.contains(ext)) {
926 requestedDevExts.append(ext.constData());
928 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
934 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
935 for (
const QByteArray &ext : envExtList) {
936 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
937 if (devExts.contains(ext)) {
938 requestedDevExts.append(ext.constData());
940 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
946 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
947 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
948 for (
const char *ext : std::as_const(requestedDevExts))
949 qCDebug(QRHI_LOG_INFO,
" %s", ext);
952 VkDeviceCreateInfo devInfo = {};
953 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
954 devInfo.queueCreateInfoCount = 1;
955 devInfo.pQueueCreateInfos = &queueInfo;
957 devInfo.enabledLayerCount = 0;
958 devInfo.ppEnabledLayerNames =
nullptr;
959 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
960 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
976 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
979 physDevFeatures13.robustImageAccess = VK_FALSE;
983 if (caps.apiVersion >= QVersionNumber(1, 1)) {
990 devInfo.pNext = &physDevFeaturesChainable;
994 physDevFeatures.robustBufferAccess = VK_FALSE;
995 devInfo.pEnabledFeatures = &physDevFeatures;
998 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
999 if (err != VK_SUCCESS) {
1000 qWarning(
"Failed to create device: %d", err);
1004 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
1009 caps.deviceFault =
true;
1010 caps.vertexAttribDivisor =
true;
1011 caps.renderPass2KHR =
true;
1012 caps.depthStencilResolveKHR =
true;
1015 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
1016 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
1017 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
1018 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
1019 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
1020 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
1022 df = inst->deviceFunctions(dev);
1024 VkCommandPoolCreateInfo poolInfo = {};
1025 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1026 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
1028 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
1029 if (err != VK_SUCCESS) {
1030 qWarning(
"Failed to create command pool: %d", err);
1035 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
1036 gfxQueueFamilyIdx, gfxQueueIdx);
1039 if (gfxQueueFlags && caps.apiVersion >= QVersionNumber(1, 1)) {
1040 VkDeviceQueueInfo2 queueInfo = {};
1041 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
1042 queueInfo.flags = gfxQueueFlags;
1043 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
1044 queueInfo.queueIndex = gfxQueueIdx;
1045 df->vkGetDeviceQueue2(dev, &queueInfo, &gfxQueue);
1048 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
1050 if (queueFamilyProps.isEmpty())
1051 queryQueueFamilyProps();
1053 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
1054 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
1056 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
1059 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
1061 caps.depthClamp = physDevFeatures.depthClamp;
1063 caps.wideLines = physDevFeatures.wideLines;
1065 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
1067 caps.tessellation = physDevFeatures.tessellationShader;
1068 caps.geometryShader = physDevFeatures.geometryShader;
1070 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
1072 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
1074#ifdef VK_VERSION_1_2
1075 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1076 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1077 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
1080 caps.drawIndirectCount = physDevFeatures12.drawIndirectCount && caps.drawIndirectMulti;
1084#ifdef VK_VERSION_1_1
1085 if (caps.apiVersion == QVersionNumber(1, 1)) {
1086 caps.multiView = multiviewFeaturesIfApi11.multiview;
1087 caps.shaderDrawParameters = shaderDrawParametersFeaturesIfApi11.shaderDrawParameters;
1091#ifdef VK_KHR_fragment_shading_rate
1092 fragmentShadingRates.clear();
1093 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1094 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1095 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1096 if (caps.imageBasedShadingRate) {
1097 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1098 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1099 VkPhysicalDeviceProperties2 props2 = {};
1100 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1101 props2.pNext = &shadingRateProps;
1102 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1103 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1106 if (caps.perDrawShadingRate) {
1107 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1108 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1109 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1110 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1112 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1113 fragmentShadingRates.resize(count);
1114 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1116 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1118 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1120 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1121 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1130#ifdef VK_KHR_create_renderpass2
1131 if (caps.renderPass2KHR) {
1132 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1133 if (!vkCreateRenderPass2KHR)
1134 caps.renderPass2KHR =
false;
1138#ifdef VK_VERSION_1_2
1139 if (caps.drawIndirectCount) {
1140 vkCmdDrawIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndirectCount>(
1141 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndirectCount"));
1142 vkCmdDrawIndexedIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirectCount>(
1143 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndexedIndirectCount"));
1144 if (!vkCmdDrawIndirectCount || !vkCmdDrawIndexedIndirectCount) {
1145 qWarning(
"Failed to resolve vkCmdDrawIndirectCount/vkCmdDrawIndexedIndirectCount; disabling DrawIndirectCount feature.");
1146 caps.drawIndirectCount =
false;
1153 adapterLuidValid =
false;
1155#ifdef VK_VERSION_1_2
1156 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1157 VkPhysicalDeviceVulkan11Properties v11props = {};
1158 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1159 VkPhysicalDeviceProperties2 props2 = {};
1160 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1161 props2.pNext = &v11props;
1162 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1163 if (v11props.deviceLUIDValid) {
1164 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1165 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1166 adapterLuidValid =
true;
1167 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1168 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1169 adapterLuid.LowPart, adapterLuid.HighPart);
1176 VmaVulkanFunctions funcs = {};
1177 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1178 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1180 VmaAllocatorCreateInfo allocatorInfo = {};
1183 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1184 allocatorInfo.physicalDevice = physDev;
1185 allocatorInfo.device = dev;
1186 allocatorInfo.pVulkanFunctions = &funcs;
1187 allocatorInfo.instance = inst->vkInstance();
1195#ifdef VK_VERSION_1_4
1196 if (caps.apiVersion >= QVersionNumber(1, 4))
1197 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1200#ifdef VK_VERSION_1_3
1201 if (caps.apiVersion >= QVersionNumber(1, 3))
1202 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1205#ifdef VK_VERSION_1_2
1206 if (caps.apiVersion >= QVersionNumber(1, 2))
1207 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1210#ifdef VK_VERSION_1_1
1211 if (caps.apiVersion >= QVersionNumber(1, 1))
1212 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1215#ifdef VK_VERSION_1_0
1216 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1219 VmaAllocator vmaallocator;
1220 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1221 if (err != VK_SUCCESS) {
1222 qWarning(
"Failed to create allocator: %d", err);
1228 inst->installDebugOutputFilter(qvk_debug_filter);
1230 VkDescriptorPool pool;
1231 VkResult err = createDescriptorPool(&pool);
1232 if (err == VK_SUCCESS)
1233 descriptorPools.append(pool);
1235 qWarning(
"Failed to create initial descriptor pool: %d", err);
1237 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1238 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1239 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1241 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1242 if (err != VK_SUCCESS) {
1243 qWarning(
"Failed to create timestamp query pool: %d", err);
1246 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1247 timestampQueryPoolMap.fill(
false);
1249#ifdef VK_EXT_debug_utils
1250 if (caps.debugUtils) {
1251 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1252 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1253 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1254 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1258#ifdef VK_EXT_device_fault
1259 if (caps.deviceFault) {
1260 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1266 nativeHandlesStruct.physDev = physDev;
1267 nativeHandlesStruct.dev = dev;
1268 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1269 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1270 nativeHandlesStruct.gfxQueueFlags = gfxQueueFlags;
1271 nativeHandlesStruct.gfxQueue = gfxQueue;
1272 nativeHandlesStruct.vmemAllocator = allocator;
1273 nativeHandlesStruct.inst = inst;
1284 df->vkQueueWaitIdle(gfxQueue);
1291 dxgiHdrInfo =
nullptr;
1295 if (ofr.cmdFence[i]) {
1296 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1297 ofr.cmdFence[i] = VK_NULL_HANDLE;
1299 ofr.cmdFenceWaitable[i] =
false;
1302 if (pipelineCache) {
1303 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1304 pipelineCache = VK_NULL_HANDLE;
1307 for (
const DescriptorPoolData &pool : descriptorPools)
1308 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1310 descriptorPools.clear();
1312 if (timestampQueryPool) {
1313 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1314 timestampQueryPool = VK_NULL_HANDLE;
1318 vmaDestroyAllocator(toVmaAllocator(allocator));
1324 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1325 cmdPool[i] = VK_NULL_HANDLE;
1327 freeSecondaryCbs[i].clear();
1328 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1331 if (!importedDevice && dev) {
1332 df->vkDestroyDevice(dev,
nullptr);
1333 inst->resetDeviceFunctions(dev);
1334 dev = VK_NULL_HANDLE;
1344QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1346 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1347 if (nativeHandles) {
1348 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1349 requestedPhysDev = h->physDev;
1352 QRhi::AdapterList list;
1353 QVulkanFunctions *f = inst->functions();
1354 uint32_t physDevCount = 0;
1355 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1359 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1360 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1361 if (err != VK_SUCCESS || !physDevCount)
1364 VkPhysicalDeviceProperties physDevProperties = {};
1365 for (uint32_t i = 0; i < physDevCount; ++i) {
1366 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1369 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1370 QVulkanAdapter *a =
new QVulkanAdapter;
1371 a->physDev = physDevs[i];
1372 fillDriverInfo(&a->adapterInfo, physDevProperties);
1386 VkDescriptorPoolSize descPoolSizes[] = {
1387 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1388 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1389 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1390 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1391 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1392 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1393 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1395 VkDescriptorPoolCreateInfo descPoolInfo = {};
1396 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1400 descPoolInfo.flags = 0;
1402 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1403 descPoolInfo.pPoolSizes = descPoolSizes;
1404 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1409 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1410 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1411 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1412 if (r == VK_SUCCESS)
1413 descriptorPools[poolIndex].refCount += 1;
1417 int lastPoolIdx = descriptorPools.size() - 1;
1418 for (
int i = lastPoolIdx; i >= 0; --i) {
1419 if (descriptorPools[i].refCount == 0) {
1420 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1421 descriptorPools[i].allocedDescSets = 0;
1423 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1424 VkResult err = tryAllocate(i);
1425 if (err == VK_SUCCESS) {
1426 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1427 *resultPoolIndex = i;
1433 VkDescriptorPool newPool;
1434 VkResult poolErr = createDescriptorPool(&newPool);
1435 if (poolErr == VK_SUCCESS) {
1436 descriptorPools.append(newPool);
1437 lastPoolIdx = descriptorPools.size() - 1;
1438 VkResult err = tryAllocate(lastPoolIdx);
1439 if (err != VK_SUCCESS) {
1440 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1443 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1444 *resultPoolIndex = lastPoolIdx;
1447 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1454 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1456 case QRhiTexture::RGBA8:
1457 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1458 case QRhiTexture::BGRA8:
1459 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1460 case QRhiTexture::R8:
1461 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1462 case QRhiTexture::RG8:
1463 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1464 case QRhiTexture::R16:
1465 return VK_FORMAT_R16_UNORM;
1466 case QRhiTexture::RG16:
1467 return VK_FORMAT_R16G16_UNORM;
1468 case QRhiTexture::RED_OR_ALPHA8:
1469 return VK_FORMAT_R8_UNORM;
1471 case QRhiTexture::RGBA16F:
1472 return VK_FORMAT_R16G16B16A16_SFLOAT;
1473 case QRhiTexture::RGBA32F:
1474 return VK_FORMAT_R32G32B32A32_SFLOAT;
1475 case QRhiTexture::R16F:
1476 return VK_FORMAT_R16_SFLOAT;
1477 case QRhiTexture::R32F:
1478 return VK_FORMAT_R32_SFLOAT;
1480 case QRhiTexture::RGB10A2:
1482 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1484 case QRhiTexture::R8SI:
1485 return VK_FORMAT_R8_SINT;
1486 case QRhiTexture::R32SI:
1487 return VK_FORMAT_R32_SINT;
1488 case QRhiTexture::RG32SI:
1489 return VK_FORMAT_R32G32_SINT;
1490 case QRhiTexture::RGBA32SI:
1491 return VK_FORMAT_R32G32B32A32_SINT;
1493 case QRhiTexture::R8UI:
1494 return VK_FORMAT_R8_UINT;
1495 case QRhiTexture::R32UI:
1496 return VK_FORMAT_R32_UINT;
1497 case QRhiTexture::RG32UI:
1498 return VK_FORMAT_R32G32_UINT;
1499 case QRhiTexture::RGBA32UI:
1500 return VK_FORMAT_R32G32B32A32_UINT;
1502 case QRhiTexture::D16:
1503 return VK_FORMAT_D16_UNORM;
1504 case QRhiTexture::D24:
1505 return VK_FORMAT_X8_D24_UNORM_PACK32;
1506 case QRhiTexture::D24S8:
1507 return VK_FORMAT_D24_UNORM_S8_UINT;
1508 case QRhiTexture::D32F:
1509 return VK_FORMAT_D32_SFLOAT;
1510 case QRhiTexture::D32FS8:
1511 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1513 case QRhiTexture::BC1:
1514 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1515 case QRhiTexture::BC2:
1516 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1517 case QRhiTexture::BC3:
1518 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1519 case QRhiTexture::BC4:
1520 return VK_FORMAT_BC4_UNORM_BLOCK;
1521 case QRhiTexture::BC5:
1522 return VK_FORMAT_BC5_UNORM_BLOCK;
1523 case QRhiTexture::BC6H:
1524 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1525 case QRhiTexture::BC7:
1526 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1528 case QRhiTexture::ETC2_RGB8:
1529 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1530 case QRhiTexture::ETC2_RGB8A1:
1531 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1532 case QRhiTexture::ETC2_RGBA8:
1533 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1535 case QRhiTexture::ASTC_4x4:
1536 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1537 case QRhiTexture::ASTC_5x4:
1538 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1539 case QRhiTexture::ASTC_5x5:
1540 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1541 case QRhiTexture::ASTC_6x5:
1542 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1543 case QRhiTexture::ASTC_6x6:
1544 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1545 case QRhiTexture::ASTC_8x5:
1546 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1547 case QRhiTexture::ASTC_8x6:
1548 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1549 case QRhiTexture::ASTC_8x8:
1550 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1551 case QRhiTexture::ASTC_10x5:
1552 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1553 case QRhiTexture::ASTC_10x6:
1554 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1555 case QRhiTexture::ASTC_10x8:
1556 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1557 case QRhiTexture::ASTC_10x10:
1558 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1559 case QRhiTexture::ASTC_12x10:
1560 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1561 case QRhiTexture::ASTC_12x12:
1562 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1565 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1572 case VK_FORMAT_R8G8B8A8_UNORM:
1573 return QRhiTexture::RGBA8;
1574 case VK_FORMAT_R8G8B8A8_SRGB:
1576 (*flags) |= QRhiTexture::sRGB;
1577 return QRhiTexture::RGBA8;
1578 case VK_FORMAT_B8G8R8A8_UNORM:
1579 return QRhiTexture::BGRA8;
1580 case VK_FORMAT_B8G8R8A8_SRGB:
1582 (*flags) |= QRhiTexture::sRGB;
1583 return QRhiTexture::BGRA8;
1584 case VK_FORMAT_R16G16B16A16_SFLOAT:
1585 return QRhiTexture::RGBA16F;
1586 case VK_FORMAT_R32G32B32A32_SFLOAT:
1587 return QRhiTexture::RGBA32F;
1588 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1589 return QRhiTexture::RGB10A2;
1591 qWarning(
"VkFormat %d cannot be read back", format);
1594 return QRhiTexture::UnknownFormat;
1600 case QRhiTexture::Format::D16:
1601 case QRhiTexture::Format::D24:
1602 case QRhiTexture::Format::D24S8:
1603 case QRhiTexture::Format::D32F:
1604 case QRhiTexture::Format::D32FS8:
1615 case QRhiTexture::Format::D24S8:
1616 case QRhiTexture::Format::D32FS8:
1626 if (isDepthTextureFormat(format)) {
1627 if (isStencilTextureFormat(format))
1628 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1630 return VK_IMAGE_ASPECT_DEPTH_BIT;
1632 return VK_IMAGE_ASPECT_COLOR_BIT;
1643 VkPhysicalDeviceMemoryProperties physDevMemProps;
1644 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1646 VkMemoryRequirements memReq;
1647 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1648 uint32_t memTypeIndex = uint32_t(-1);
1650 if (memReq.memoryTypeBits) {
1652 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1653 bool foundDevLocal =
false;
1654 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1655 if (memReq.memoryTypeBits & (1 << i)) {
1656 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1657 if (!foundDevLocal) {
1658 foundDevLocal =
true;
1661 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1670 return memTypeIndex;
1674 const QSize &pixelSize,
1675 VkImageUsageFlags usage,
1676 VkImageAspectFlags aspectMask,
1677 VkSampleCountFlagBits samples,
1678 VkDeviceMemory *mem,
1683 VkMemoryRequirements memReq;
1686 *mem = VK_NULL_HANDLE;
1687 for (
int i = 0; i < count; ++i) {
1688 images[i] = VK_NULL_HANDLE;
1689 views[i] = VK_NULL_HANDLE;
1692 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1693 for (
int i = 0; i < count; ++i) {
1695 df->vkDestroyImageView(dev, views[i],
nullptr);
1696 views[i] = VK_NULL_HANDLE;
1699 df->vkDestroyImage(dev, images[i],
nullptr);
1700 images[i] = VK_NULL_HANDLE;
1704 df->vkFreeMemory(dev, *mem,
nullptr);
1705 *mem = VK_NULL_HANDLE;
1709 for (
int i = 0; i < count; ++i) {
1710 VkImageCreateInfo imgInfo = {};
1711 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1712 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1713 imgInfo.format = format;
1714 imgInfo.extent.width = uint32_t(pixelSize.width());
1715 imgInfo.extent.height = uint32_t(pixelSize.height());
1716 imgInfo.extent.depth = 1;
1717 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1718 imgInfo.samples = samples;
1719 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1720 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1721 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1723 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1724 if (err != VK_SUCCESS) {
1725 qWarning(
"Failed to create image: %d", err);
1732 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1735 VkMemoryAllocateInfo memInfo = {};
1736 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1737 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1739 uint32_t startIndex = 0;
1741 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1742 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1743 qWarning(
"No suitable memory type found");
1746 startIndex = memInfo.memoryTypeIndex + 1;
1747 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1748 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1749 qWarning(
"Failed to allocate image memory: %d", err);
1752 }
while (err != VK_SUCCESS);
1754 VkDeviceSize ofs = 0;
1755 for (
int i = 0; i < count; ++i) {
1756 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1757 if (err != VK_SUCCESS) {
1758 qWarning(
"Failed to bind image memory: %d", err);
1761 ofs += aligned(memReq.size, memReq.alignment);
1763 VkImageViewCreateInfo imgViewInfo = {};
1764 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1765 imgViewInfo.image = images[i];
1766 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1767 imgViewInfo.format = format;
1768 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1769 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1770 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1771 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1772 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1773 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1775 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1776 if (err != VK_SUCCESS) {
1777 qWarning(
"Failed to create image view: %d", err);
1788 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1789 return optimalDsFormat;
1791 const VkFormat dsFormatCandidates[] = {
1792 VK_FORMAT_D24_UNORM_S8_UINT,
1793 VK_FORMAT_D32_SFLOAT_S8_UINT,
1794 VK_FORMAT_D16_UNORM_S8_UINT
1796 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1797 int dsFormatIdx = 0;
1798 while (dsFormatIdx < dsFormatCandidateCount) {
1799 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1800 VkFormatProperties fmtProp;
1801 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1802 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1806 if (dsFormatIdx == dsFormatCandidateCount)
1807 qWarning(
"Failed to find an optimal depth-stencil format");
1809 return optimalDsFormat;
1814 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1816 if (multiViewCount < 2)
1818 if (!multiViewCap) {
1819 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1822#ifdef VK_VERSION_1_1
1823 uint32_t allViewsMask = 0;
1824 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1825 allViewsMask |= (1 << i);
1826 multiViewMask = allViewsMask;
1827 multiViewCorrelationMask = allViewsMask;
1828 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1829 multiViewInfo.subpassCount = 1;
1830 multiViewInfo.pViewMasks = &multiViewMask;
1831 multiViewInfo.correlationMaskCount = 1;
1832 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1833 rpInfo->pNext = &multiViewInfo;
1838#ifdef VK_VERSION_1_1
1845#ifdef VK_KHR_create_renderpass2
1849struct RenderPass2SetupHelper
1851 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1853 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1857 if (multiViewCount >= 2) {
1858 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1859 viewMask |= (1 << i);
1862 attDescs2.resize(rpInfo->attachmentCount);
1863 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1864 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1865 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1867 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1868 att2.flags = att.flags;
1869 att2.format = att.format;
1870 att2.samples = att.samples;
1871 att2.loadOp = att.loadOp;
1872 att2.storeOp = att.storeOp;
1873 att2.stencilLoadOp = att.stencilLoadOp;
1874 att2.stencilStoreOp = att.stencilStoreOp;
1875 att2.initialLayout = att.initialLayout;
1876 att2.finalLayout = att.finalLayout;
1881 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1882 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1883 subpass2.flags = subpassDesc.flags;
1884 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1885 if (multiViewCount >= 2)
1886 subpass2.viewMask = viewMask;
1889 qsizetype startIndex = attRefs2.count();
1890 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1891 attRefs2.append({});
1892 VkAttachmentReference2KHR &attref2(attRefs2.last());
1893 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1894 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1895 attref2.attachment = attref.attachment;
1896 attref2.layout = attref.layout;
1897 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1899 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1900 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1903 if (subpassDesc.pResolveAttachments) {
1904 startIndex = attRefs2.count();
1905 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1906 attRefs2.append({});
1907 VkAttachmentReference2KHR &attref2(attRefs2.last());
1908 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1909 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1910 attref2.attachment = attref.attachment;
1911 attref2.layout = attref.layout;
1912 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1914 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1918 if (subpassDesc.pDepthStencilAttachment) {
1919 startIndex = attRefs2.count();
1920 attRefs2.append({});
1921 VkAttachmentReference2KHR &attref2(attRefs2.last());
1922 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1923 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1924 attref2.attachment = attref.attachment;
1925 attref2.layout = attref.layout;
1926 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1927 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1931#ifdef VK_KHR_depth_stencil_resolve
1933 if (rpD->hasDepthStencilResolve) {
1934 startIndex = attRefs2.count();
1935 attRefs2.append({});
1936 VkAttachmentReference2KHR &attref2(attRefs2.last());
1937 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1938 attref2.attachment = rpD->dsResolveRef.attachment;
1939 attref2.layout = rpD->dsResolveRef.layout;
1940 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1941 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1942 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1943 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1944 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1945 addToChain(&subpass2, &dsResolveDesc);
1949#ifdef VK_KHR_fragment_shading_rate
1950 shadingRateAttInfo = {};
1951 if (rpD->hasShadingRateMap) {
1952 startIndex = attRefs2.count();
1953 attRefs2.append({});
1954 VkAttachmentReference2KHR &attref2(attRefs2.last());
1955 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1956 attref2.attachment = rpD->shadingRateRef.attachment;
1957 attref2.layout = rpD->shadingRateRef.layout;
1958 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1959 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1960 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1961 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1962 addToChain(&subpass2, &shadingRateAttInfo);
1968 subpassDeps2.clear();
1969 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1970 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1971 subpassDeps2.append({});
1972 VkSubpassDependency2 &dep2(subpassDeps2.last());
1973 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1974 dep2.srcSubpass = dep.srcSubpass;
1975 dep2.dstSubpass = dep.dstSubpass;
1976 dep2.srcStageMask = dep.srcStageMask;
1977 dep2.dstStageMask = dep.dstStageMask;
1978 dep2.srcAccessMask = dep.srcAccessMask;
1979 dep2.dstAccessMask = dep.dstAccessMask;
1980 dep2.dependencyFlags = dep.dependencyFlags;
1983 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1984 rpInfo2->pNext =
nullptr;
1985 rpInfo2->flags = rpInfo->flags;
1986 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1987 rpInfo2->pAttachments = attDescs2.constData();
1988 rpInfo2->subpassCount = 1;
1989 rpInfo2->pSubpasses = &subpass2;
1990 rpInfo2->dependencyCount = subpassDeps2.count();
1991 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1992 if (multiViewCount >= 2) {
1993 rpInfo2->correlatedViewMaskCount = 1;
1994 rpInfo2->pCorrelatedViewMasks = &viewMask;
2000 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
2001 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
2002 VkSubpassDescription2KHR subpass2;
2003 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
2004#ifdef VK_KHR_depth_stencil_resolve
2005 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
2007#ifdef VK_KHR_fragment_shading_rate
2008 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
2015 VkSubpassDescription *subpassDesc,
2018 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
2019 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
2020 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
2021 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
2022 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
2023 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
2025 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
2026 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
2027 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
2028 rpInfo->pAttachments = rpD->attDescs.constData();
2029 rpInfo->subpassCount = 1;
2030 rpInfo->pSubpasses = subpassDesc;
2031 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
2032 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
2036 bool hasDepthStencil,
2037 VkSampleCountFlagBits samples,
2038 VkFormat colorFormat,
2039 QRhiShadingRateMap *shadingRateMap)
2043 VkAttachmentDescription attDesc = {};
2044 attDesc.format = colorFormat;
2045 attDesc.samples = samples;
2046 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2047 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2048 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2049 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2050 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2051 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2052 rpD->attDescs.append(attDesc);
2054 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2059 rpD->multiViewCount = 0;
2061 if (hasDepthStencil) {
2065 attDesc.format = optimalDepthStencilFormat();
2066 attDesc.samples = samples;
2067 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2068 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2069 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2070 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2071 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2072 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2073 rpD->attDescs.append(attDesc);
2075 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2080 if (samples > VK_SAMPLE_COUNT_1_BIT) {
2082 attDesc.format = colorFormat;
2083 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2084 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2085 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2086 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2087 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2088 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2089 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2090 rpD->attDescs.append(attDesc);
2092 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2095 rpD->dsResolveRef = {};
2097 rpD->shadingRateRef = {};
2098#ifdef VK_KHR_fragment_shading_rate
2099 if (shadingRateMap) {
2101 attDesc.format = VK_FORMAT_R8_UINT;
2102 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2103 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2104 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2105 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2106 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2107 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2108 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2109 rpD->attDescs.append(attDesc);
2111 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2116 VkSubpassDependency subpassDep = {};
2117 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2118 subpassDep.dstSubpass = 0;
2119 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2120 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2121 subpassDep.srcAccessMask = 0;
2122 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2123 rpD->subpassDeps.append(subpassDep);
2124 if (hasDepthStencil) {
2125 memset(&subpassDep, 0,
sizeof(subpassDep));
2126 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2127 subpassDep.dstSubpass = 0;
2128 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2129 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2130 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2131 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2132 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2133 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2134 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2135 rpD->subpassDeps.append(subpassDep);
2138 VkRenderPassCreateInfo rpInfo;
2139 VkSubpassDescription subpassDesc;
2140 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2142#ifdef VK_KHR_create_renderpass2
2143 if (caps.renderPass2KHR) {
2145 VkRenderPassCreateInfo2KHR rpInfo2;
2146 RenderPass2SetupHelper rp2Helper(
this);
2147 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2149 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2150 if (err != VK_SUCCESS) {
2151 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2158 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2159 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2160 if (err != VK_SUCCESS) {
2161 qWarning(
"Failed to create renderpass: %d", err);
2170 const QRhiColorAttachment *colorAttachmentsBegin,
2171 const QRhiColorAttachment *colorAttachmentsEnd,
2175 QRhiRenderBuffer *depthStencilBuffer,
2176 QRhiTexture *depthTexture,
2177 QRhiTexture *depthResolveTexture,
2179 QRhiShadingRateMap *shadingRateMap)
2183 int multiViewCount = 0;
2184 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2187 Q_ASSERT(texD || rbD);
2188 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2189 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2191 VkAttachmentDescription attDesc = {};
2192 attDesc.format = vkformat;
2193 attDesc.samples = samples;
2194 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2195 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2196 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2197 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2199 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2200 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2201 rpD->attDescs.append(attDesc);
2203 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2204 rpD->colorRefs.append(ref);
2206 if (it->multiViewCount() >= 2) {
2207 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2208 qWarning(
"Inconsistent multiViewCount in color attachment set");
2210 multiViewCount = it->multiViewCount();
2211 }
else if (multiViewCount > 0) {
2212 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2215 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2216 rpD->multiViewCount = uint32_t(multiViewCount);
2220 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2221 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2222 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2223 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2224 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2225 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2226 VkAttachmentDescription attDesc = {};
2227 attDesc.format = dsFormat;
2228 attDesc.samples = samples;
2229 attDesc.loadOp = loadOp;
2230 attDesc.storeOp = storeOp;
2231 attDesc.stencilLoadOp = loadOp;
2232 attDesc.stencilStoreOp = storeOp;
2233 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2234 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2235 rpD->attDescs.append(attDesc);
2236 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2237 multiViewCount = depthTexture->arraySize();
2238 rpD->multiViewCount = multiViewCount;
2240 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2245 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2246 if (it->resolveTexture()) {
2248 const VkFormat dstFormat = rtexD->vkformat;
2249 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2250 qWarning(
"Resolving into a multisample texture is not supported");
2254 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2255 if (srcFormat != dstFormat) {
2259 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2260 int(srcFormat),
int(dstFormat));
2263 VkAttachmentDescription attDesc = {};
2264 attDesc.format = rtexD->viewFormat;
2265 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2266 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2267 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2268 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2269 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2270 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2271 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2272 rpD->attDescs.append(attDesc);
2274 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2275 rpD->resolveRefs.append(ref);
2277 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2278 rpD->resolveRefs.append(ref);
2281 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2286 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2287 qWarning(
"Resolving into a multisample depth texture is not supported");
2288 const VkFormat dstFormat = rtexD->vkformat;
2292 Q_ASSERT(texD || rbD);
2293 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2294 if (srcFormat != dstFormat) {
2295 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2296 int(srcFormat),
int(dstFormat));
2299 VkAttachmentDescription attDesc = {};
2300 attDesc.format = rtexD->viewFormat;
2301 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2302 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2303 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2304 attDesc.stencilLoadOp = attDesc.loadOp;
2305 attDesc.stencilStoreOp = attDesc.storeOp;
2306 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2307 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2308 rpD->attDescs.append(attDesc);
2309 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2311 rpD->dsResolveRef = {};
2315 rpD->shadingRateRef = {};
2316#ifdef VK_KHR_fragment_shading_rate
2317 if (shadingRateMap) {
2318 VkAttachmentDescription attDesc = {};
2319 attDesc.format = VK_FORMAT_R8_UINT;
2320 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2321 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2322 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2323 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2324 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2325 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2326 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2327 rpD->attDescs.append(attDesc);
2328 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2333 VkSubpassDependency selfDependency = {};
2334 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2335 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2336 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2337 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2338 selfDependency.srcSubpass = 0;
2339 selfDependency.dstSubpass = 0;
2340 selfDependency.srcStageMask = stageMask;
2341 selfDependency.dstStageMask = stageMask;
2342 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2343 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2344 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2345#ifdef VK_VERSION_1_1
2346 if (rpD->multiViewCount >= 2)
2347 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2349 selfDependency.dependencyFlags = depFlags;
2350 rpD->subpassDeps.append(selfDependency);
2357 VkRenderPassCreateInfo rpInfo;
2358 VkSubpassDescription subpassDesc;
2359 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2362 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2365#ifdef VK_KHR_create_renderpass2
2366 if (caps.renderPass2KHR) {
2368 VkRenderPassCreateInfo2KHR rpInfo2;
2369 RenderPass2SetupHelper rp2Helper(
this);
2370 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2373 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2374 if (err != VK_SUCCESS) {
2375 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2382 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2383 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2386 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2387 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2388 if (err != VK_SUCCESS) {
2389 qWarning(
"Failed to create renderpass: %d", err);
2400 if (swapChainD->pixelSize.isEmpty()) {
2401 qWarning(
"Surface size is 0, cannot create swapchain");
2406 df->vkQueueWaitIdle(gfxQueue);
2408 if (!vkCreateSwapchainKHR) {
2409 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2410 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2411 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2412 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2413 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2414 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2415 qWarning(
"Swapchain functions not available");
2420 VkSurfaceCapabilitiesKHR surfaceCaps;
2421 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2422 quint32 reqBufferCount;
2423 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2424 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2426 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2428 VkSurfaceTransformFlagBitsKHR preTransform =
2429 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2430 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2431 : surfaceCaps.currentTransform;
2457 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2458 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2459 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2460 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2462 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2463 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2464 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2465 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2466 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2467 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2468 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2469 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2470 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2471 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2474 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2475 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2476 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2477 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2479 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2480 && surfaceCaps.maxImageArrayLayers > 1;
2483 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2484 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2488 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2489 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2490 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2491 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2499 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2501 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2502 reuseExisting ?
"recycled" :
"new",
2503 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2505 VkSwapchainCreateInfoKHR swapChainInfo = {};
2506 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2507 swapChainInfo.surface = swapChainD->surface;
2508 swapChainInfo.minImageCount = reqBufferCount;
2509 swapChainInfo.imageFormat = swapChainD->colorFormat;
2510 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2511 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2512 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2513 swapChainInfo.imageUsage = usage;
2514 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2515 swapChainInfo.preTransform = preTransform;
2516 swapChainInfo.compositeAlpha = compositeAlpha;
2517 swapChainInfo.presentMode = presentMode;
2518 swapChainInfo.clipped =
true;
2519 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2521 VkSwapchainKHR newSwapChain;
2522 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2523 if (err != VK_SUCCESS) {
2524 qWarning(
"Failed to create swapchain: %d", err);
2527 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2532 swapChainD->sc = newSwapChain;
2533 swapChainD->lastConnectedSurface = swapChainD->surface;
2535 quint32 actualSwapChainBufferCount = 0;
2536 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2537 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2538 qWarning(
"Failed to get swapchain images: %d", err);
2542 if (actualSwapChainBufferCount != reqBufferCount)
2543 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2546 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2547 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2548 if (err != VK_SUCCESS) {
2549 qWarning(
"Failed to get swapchain images: %d", err);
2553 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2554 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2555 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2556 if (!createTransientImage(swapChainD->colorFormat,
2557 swapChainD->pixelSize,
2558 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2559 VK_IMAGE_ASPECT_COLOR_BIT,
2560 swapChainD->samples,
2561 &swapChainD->msaaImageMem,
2564 swapChainD->bufferCount))
2566 qWarning(
"Failed to create transient image for MSAA color buffer");
2571 VkFenceCreateInfo fenceInfo = {};
2572 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2573 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2576 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2580 image.image = swapChainImages[i];
2581 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2582 image.msaaImage = msaaImages[i];
2583 image.msaaImageView = msaaViews[i];
2586 VkImageViewCreateInfo imgViewInfo = {};
2587 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2588 imgViewInfo.image = swapChainImages[i];
2589 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2590 imgViewInfo.format = swapChainD->colorFormat;
2591 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2592 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2593 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2594 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2595 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2596 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2597 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2598 if (err != VK_SUCCESS) {
2599 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2605 VkSemaphoreCreateInfo semInfo = {};
2606 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2607 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2612 image.image = swapChainImages[i];
2613 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2614 image.msaaImage = msaaImages[i];
2615 image.msaaImageView = msaaViews[i];
2618 VkImageViewCreateInfo imgViewInfo = {};
2619 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2620 imgViewInfo.image = swapChainImages[i];
2621 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2622 imgViewInfo.format = swapChainD->colorFormat;
2623 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2624 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2625 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2626 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2627 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2628 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2629 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2630 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2631 if (err != VK_SUCCESS) {
2632 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2636 VkSemaphoreCreateInfo semInfo = {};
2637 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2638 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2644 swapChainD->currentImageIndex = 0;
2646 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2648 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2649 VkImageViewCreateInfo viewInfo = {};
2650 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2651 viewInfo.image = texD->image;
2652 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2653 viewInfo.format = texD->viewFormat;
2654 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2655 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2656 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2657 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2658 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2659 viewInfo.subresourceRange.baseMipLevel = 0;
2660 viewInfo.subresourceRange.levelCount = 1;
2661 viewInfo.subresourceRange.baseArrayLayer = 0;
2662 viewInfo.subresourceRange.layerCount = 1;
2663 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2664 if (err != VK_SUCCESS) {
2665 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2670 VkSemaphoreCreateInfo semInfo = {};
2671 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2679 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2681 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2682 if (err != VK_SUCCESS) {
2683 qWarning(
"Failed to create command buffer fence: %d", err);
2696 if (swapChainD->sc == VK_NULL_HANDLE)
2700 df->vkQueueWaitIdle(gfxQueue);
2704 if (frame.cmdFence) {
2706 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2707 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2708 frame.cmdFence = VK_NULL_HANDLE;
2711 if (frame.imageSem) {
2712 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2713 frame.imageSem = VK_NULL_HANDLE;
2720 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2721 image.fb = VK_NULL_HANDLE;
2723 if (image.imageView) {
2724 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2725 image.imageView = VK_NULL_HANDLE;
2727 if (image.msaaImageView) {
2728 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2729 image.msaaImageView = VK_NULL_HANDLE;
2731 if (image.msaaImage) {
2732 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2733 image.msaaImage = VK_NULL_HANDLE;
2735 if (image.drawSem) {
2736 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2737 image.drawSem = VK_NULL_HANDLE;
2741 if (swapChainD->msaaImageMem) {
2742 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2743 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2746 if (swapChainD->shadingRateMapView) {
2747 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2748 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2751 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2752 swapChainD->sc = VK_NULL_HANDLE;
2759 VkCommandPoolResetFlags flags = 0;
2764 if (releaseCachedResourcesCalledBeforeFrameStart)
2765 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2768 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2774 for (quint64 i = 0; i < timestampValidBits; i += 8)
2775 mask |= 0xFFULL << i;
2776 const quint64 ts0 = timestamp[0] & mask;
2777 const quint64 ts1 = timestamp[1] & mask;
2778 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2779 if (!qFuzzyIsNull(nsecsPerTick)) {
2780 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2781 const double elapsedSec = elapsedMs / 1000.0;
2792 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2795 inst->handle()->beginFrame(swapChainD->window);
2796 auto instEndFrameOnErrorGuard = qScopeGuard([
this, swapChainD] {
2797 inst->handle()->endFrame(swapChainD->window);
2808 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2809 if (waitResult != QRhi::FrameOpSuccess)
2814 uint32_t imageIndex = 0;
2815 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2816 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2818 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2819 swapChainD->currentImageIndex = imageIndex;
2822 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2823 return QRhi::FrameOpSwapChainOutOfDate;
2825 if (err == VK_ERROR_DEVICE_LOST) {
2826 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2827 printExtraErrorInfo(err);
2829 return QRhi::FrameOpDeviceLost;
2831 qWarning(
"Failed to acquire next swapchain image: %d", err);
2832 return QRhi::FrameOpError;
2838 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2844 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2845 if (cbres != QRhi::FrameOpSuccess)
2848 swapChainD->cbWrapper.cb = frame.cmdBuf;
2851 swapChainD->rtWrapper.d.fb = image.fb;
2855 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2856 swapChainD->rtWrapperRight.d.fb = image.fb;
2863 quint64 timestamp[2] = { 0, 0 };
2864 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2865 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2866 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2867 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2869 if (err == VK_SUCCESS) {
2871 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2873 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2875 qWarning(
"Failed to query timestamp: %d", err);
2880 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2881 int timestampQueryIdx = -1;
2882 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2883 if (!timestampQueryPoolMap.testBit(i)) {
2884 timestampQueryPoolMap.setBit(i);
2885 timestampQueryIdx = i * 2;
2889 if (timestampQueryIdx >= 0) {
2890 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2892 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2893 timestampQueryPool, uint32_t(timestampQueryIdx));
2898 instEndFrameOnErrorGuard.dismiss();
2899 return QRhi::FrameOpSuccess;
2907 auto cleanup = qScopeGuard([
this, swapChainD] {
2908 inst->handle()->endFrame(swapChainD->window);
2913 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2918 VkImageMemoryBarrier presTrans = {};
2919 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2920 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2921 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2922 presTrans.image = image.image;
2923 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2924 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2928 presTrans.srcAccessMask = 0;
2929 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2930 df->vkCmdPipelineBarrier(frame.cmdBuf,
2931 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2932 0, 0,
nullptr, 0,
nullptr,
2936 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2937 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2938 df->vkCmdPipelineBarrier(frame.cmdBuf,
2939 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2940 0, 0,
nullptr, 0,
nullptr,
2948 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2954 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2955 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2957 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2958 needsPresent ? &image.drawSem :
nullptr);
2959 if (submitres != QRhi::FrameOpSuccess)
2967 VkPresentInfoKHR presInfo = {};
2968 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2969 presInfo.swapchainCount = 1;
2970 presInfo.pSwapchains = &swapChainD->sc;
2971 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2972 waitSemaphoresForPresent.append(image.drawSem);
2973 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2974 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2978 inst->presentAboutToBeQueued(swapChainD->window);
2980 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2981 waitSemaphoresForPresent.clear();
2982 if (err != VK_SUCCESS) {
2983 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2984 return QRhi::FrameOpSwapChainOutOfDate;
2985 }
else if (err != VK_SUBOPTIMAL_KHR) {
2986 if (err == VK_ERROR_DEVICE_LOST) {
2987 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2988 printExtraErrorInfo(err);
2990 return QRhi::FrameOpDeviceLost;
2992 qWarning(
"Failed to present: %d", err);
2993 return QRhi::FrameOpError;
2999 inst->presentQueued(swapChainD->window);
3004 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3009 return QRhi::FrameOpSuccess;
3023 QRHI_RES(QVkCommandBuffer, cb)->resetState();
3033 VkCommandBufferAllocateInfo cmdBufInfo = {};
3034 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3035 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3036 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
3037 cmdBufInfo.commandBufferCount = 1;
3039 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
3040 if (err != VK_SUCCESS) {
3041 if (err == VK_ERROR_DEVICE_LOST) {
3042 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
3043 printExtraErrorInfo(err);
3045 return QRhi::FrameOpDeviceLost;
3047 qWarning(
"Failed to allocate frame command buffer: %d", err);
3048 return QRhi::FrameOpError;
3052 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3053 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3055 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
3056 if (err != VK_SUCCESS) {
3057 if (err == VK_ERROR_DEVICE_LOST) {
3058 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
3059 printExtraErrorInfo(err);
3061 return QRhi::FrameOpDeviceLost;
3063 qWarning(
"Failed to begin frame command buffer: %d", err);
3064 return QRhi::FrameOpError;
3067 return QRhi::FrameOpSuccess;
3071 VkSemaphore *waitSem, VkSemaphore *signalSem)
3073 VkResult err =
df->vkEndCommandBuffer(cb);
3074 if (err != VK_SUCCESS) {
3075 if (err == VK_ERROR_DEVICE_LOST) {
3076 qWarning(
"Device loss detected in vkEndCommandBuffer()");
3077 printExtraErrorInfo(err);
3079 return QRhi::FrameOpDeviceLost;
3081 qWarning(
"Failed to end frame command buffer: %d", err);
3082 return QRhi::FrameOpError;
3085 VkSubmitInfo submitInfo = {};
3086 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
3087 submitInfo.commandBufferCount = 1;
3088 submitInfo.pCommandBuffers = &cb;
3091 waitSemaphoresForQueueSubmit.append(*waitSem);
3093 signalSemaphoresForQueueSubmit.append(*signalSem);
3095 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
3096 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
3097 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
3098 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3099 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
3101 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3102 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3103 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3106 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3108 waitSemaphoresForQueueSubmit.clear();
3109 signalSemaphoresForQueueSubmit.clear();
3111 if (err != VK_SUCCESS) {
3112 if (err == VK_ERROR_DEVICE_LOST) {
3113 qWarning(
"Device loss detected in vkQueueSubmit()");
3114 printExtraErrorInfo(err);
3116 return QRhi::FrameOpDeviceLost;
3118 qWarning(
"Failed to submit to graphics queue: %d", err);
3119 return QRhi::FrameOpError;
3122 return QRhi::FrameOpSuccess;
3127 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3128 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3129 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3130 if (frame.cmdFenceWaitable) {
3131 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3133 if (err != VK_SUCCESS) {
3134 if (err == VK_ERROR_DEVICE_LOST) {
3135 qWarning(
"Device loss detected in vkWaitForFences()");
3136 printExtraErrorInfo(err);
3138 return QRhi::FrameOpDeviceLost;
3140 qWarning(
"Failed to wait for fence: %d", err);
3141 return QRhi::FrameOpError;
3144 df->vkResetFences(dev, 1, &frame.cmdFence);
3145 frame.cmdFenceWaitable =
false;
3149 if (ofr.cmdFenceWaitable[frameSlot]) {
3150 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3151 if (err != VK_SUCCESS) {
3152 if (err == VK_ERROR_DEVICE_LOST) {
3153 qWarning(
"Device loss detected in vkWaitForFences()");
3154 printExtraErrorInfo(err);
3156 return QRhi::FrameOpDeviceLost;
3158 qWarning(
"Failed to wait for offscreen fence: %d", err);
3159 return QRhi::FrameOpError;
3161 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3162 ofr.cmdFenceWaitable[frameSlot] =
false;
3165 return QRhi::FrameOpSuccess;
3170 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3171 if (waitResult != QRhi::FrameOpSuccess)
3177 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3178 if (cbres != QRhi::FrameOpSuccess)
3184 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3185 quint64 timestamp[2] = { 0, 0 };
3186 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3187 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3188 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3189 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3190 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3191 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3192 if (err == VK_SUCCESS) {
3194 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3198 qWarning(
"Failed to query timestamp: %d", err);
3202 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3203 int timestampQueryIdx = -1;
3204 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3205 if (!timestampQueryPoolMap.testBit(i)) {
3206 timestampQueryPoolMap.setBit(i);
3207 timestampQueryIdx = i * 2;
3211 if (timestampQueryIdx >= 0) {
3212 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3214 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3215 timestampQueryPool, uint32_t(timestampQueryIdx));
3216 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3221 return QRhi::FrameOpSuccess;
3227 Q_ASSERT(ofr.active);
3233 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3237 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3238 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3239 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3242 if (!ofr.cmdFence[currentFrameSlot]) {
3243 VkFenceCreateInfo fenceInfo = {};
3244 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3245 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3246 if (err != VK_SUCCESS) {
3247 qWarning(
"Failed to create command buffer fence: %d", err);
3248 return QRhi::FrameOpError;
3252 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3253 if (submitres != QRhi::FrameOpSuccess)
3256 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3259 if (readbacksPending) {
3260 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3261 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3262 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3269 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3271 return QRhi::FrameOpSuccess;
3293 swapChainFrameRes = &swapChainD->frameRes[swapChainD->bufferCount > 1 ? currentFrameSlot : 0];
3295 swapChainD->cbWrapper.resetCommands();
3296 cb = swapChainD->cbWrapper.cb;
3299 ? &swapChainFrameRes->imageSem
3301 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE, waitSem,
nullptr);
3302 if (submitres != QRhi::FrameOpSuccess)
3308 df->vkQueueWaitIdle(gfxQueue);
3315 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3317 startPrimaryCommandBuffer(&swapChainFrameRes->cmdBuf);
3318 swapChainD->cbWrapper.cb = swapChainFrameRes->cmdBuf;
3325 return QRhi::FrameOpSuccess;
3332 u
.access =
int(bufUsage.access);
3333 u
.stage =
int(bufUsage.stage);
3341 u
.access =
int(texUsage.access);
3342 u
.stage =
int(texUsage.stage);
3348 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3351 rtD->lastActiveFrameSlot = currentFrameSlot;
3352 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3354 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3362 texD->lastActiveFrameSlot = currentFrameSlot;
3367 rbD->lastActiveFrameSlot = currentFrameSlot;
3373 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3376 if (rtD->m_desc.depthStencilBuffer()) {
3378 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3385 rbD->lastActiveFrameSlot = currentFrameSlot;
3387 if (rtD->m_desc.depthTexture()) {
3392 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3394 if (rtD->m_desc.depthResolveTexture()) {
3399 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3401 if (rtD->m_desc.shadingRateMap()) {
3406 texD->lastActiveFrameSlot = currentFrameSlot;
3420 VkCommandBuffer secondaryCb;
3422 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3423 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3424 freeSecondaryCbs[currentFrameSlot].removeLast();
3426 VkCommandBufferAllocateInfo cmdBufInfo = {};
3427 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3428 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3429 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3430 cmdBufInfo.commandBufferCount = 1;
3432 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3433 if (err != VK_SUCCESS) {
3434 qWarning(
"Failed to create secondary command buffer: %d", err);
3435 return VK_NULL_HANDLE;
3439 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3440 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3441 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3442 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3443 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3444 cmdBufInheritInfo.subpass = 0;
3446 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3447 cmdBufInheritInfo.framebuffer = rtD->fb;
3449 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3451 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3452 if (err != VK_SUCCESS) {
3453 qWarning(
"Failed to begin secondary command buffer: %d", err);
3454 return VK_NULL_HANDLE;
3462 VkResult err =
df->vkEndCommandBuffer(cb);
3463 if (err != VK_SUCCESS)
3464 qWarning(
"Failed to end secondary command buffer: %d", err);
3468 cmd.args.executeSecondary.cb = cb;
3472 e.lastActiveFrameSlot = currentFrameSlot;
3473 e.secondaryCommandBuffer.cb = cb;
3474 releaseQueue.append(e);
3478 QRhiRenderTarget *rt,
3479 const QColor &colorClearValue,
3480 const QRhiDepthStencilClearValue &depthStencilClearValue,
3481 QRhiResourceUpdateBatch *resourceUpdates,
3482 QRhiCommandBuffer::BeginPassFlags flags)
3487 if (resourceUpdates)
3497 switch (rt->resourceType()) {
3498 case QRhiResource::SwapChainRenderTarget:
3500 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3510 texD->lastActiveFrameSlot = currentFrameSlot;
3513 case QRhiResource::TextureRenderTarget:
3527 cbD->currentTarget = rt;
3532 VkRenderPassBeginInfo rpBeginInfo = {};
3533 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3534 rpBeginInfo.renderPass = rtD
->rp->rp;
3535 rpBeginInfo.framebuffer = rtD->fb;
3536 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3537 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3539 const bool rpHasAnyClearOp =
std::any_of(rtD
->rp->attDescs.cbegin(), rtD
->rp->attDescs.cend(),
3540 [](
const VkAttachmentDescription &attDesc) {
3541 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3542 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3545 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3546 if (rpHasAnyClearOp) {
3548 VkClearValue cv = {};
3549 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3550 colorClearValue.alphaF() } };
3554 VkClearValue cv = {};
3555 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3559 VkClearValue cv = {};
3560 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3561 colorClearValue.alphaF() } };
3565 VkClearValue cv = {};
3566 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3570 VkClearValue cv = {};
3571 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3575 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3576 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3580 cmd.args.beginRenderPass.desc = rpBeginInfo;
3581 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3583 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3586 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3591 rateCmd.args.setShadingRate.w = 1;
3592 rateCmd.args.setShadingRate.h = 1;
3604 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3605 cbD->activeSecondaryCbStack.removeLast();
3606 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3613 cbD->currentTarget =
nullptr;
3615 if (resourceUpdates)
3620 QRhiResourceUpdateBatch *resourceUpdates,
3621 QRhiCommandBuffer::BeginPassFlags flags)
3626 if (resourceUpdates)
3634 cbD->computePassState.reset();
3637 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3648 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3649 cbD->activeSecondaryCbStack.removeLast();
3650 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3655 if (resourceUpdates)
3662 Q_ASSERT(psD->pipeline);
3668 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3672 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3673 cmd.args.bindPipeline.pipeline = psD->pipeline;
3676 cbD->currentGraphicsPipeline =
nullptr;
3677 cbD->currentComputePipeline = ps;
3681 psD->lastActiveFrameSlot = currentFrameSlot;
3686 QRhiShaderResourceBinding::Type bindingType,
3687 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3689 VkAccessFlags access = 0;
3690 if (bindingType == loadTypeVal) {
3691 access = VK_ACCESS_SHADER_READ_BIT;
3693 access = VK_ACCESS_SHADER_WRITE_BIT;
3694 if (bindingType == loadStoreTypeVal)
3695 access |= VK_ACCESS_SHADER_READ_BIT;
3697 auto it = writtenResources->find(resource);
3698 if (it != writtenResources->end())
3699 it->second.accessFlags |= access;
3700 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3701 writtenResources->insert(resource, { access,
true });
3706 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3707 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3708 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3709 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3710 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3711 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3717 QVarLengthArray<VkImageMemoryBarrier, 8> *imageBarriers,
3718 QVarLengthArray<VkBufferMemoryBarrier, 8> *bufferBarriers)
3720 if (!cbD->currentComputeSrb)
3726 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3727 accessAndIsNewFlag = { 0,
false };
3730 for (
auto &binding : srbD->m_bindings) {
3731 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3733 case QRhiShaderResourceBinding::ImageLoad:
3734 case QRhiShaderResourceBinding::ImageStore:
3735 case QRhiShaderResourceBinding::ImageLoadStore:
3736 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3739 QRhiShaderResourceBinding::ImageLoad,
3740 QRhiShaderResourceBinding::ImageStore,
3741 QRhiShaderResourceBinding::ImageLoadStore);
3743 case QRhiShaderResourceBinding::BufferLoad:
3744 case QRhiShaderResourceBinding::BufferStore:
3745 case QRhiShaderResourceBinding::BufferLoadStore:
3746 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3749 QRhiShaderResourceBinding::BufferLoad,
3750 QRhiShaderResourceBinding::BufferStore,
3751 QRhiShaderResourceBinding::BufferLoadStore);
3758 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3759 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3760 const bool isNewInThisDispatch = it->second.isNew;
3761 if (accessInThisDispatch && !isNewInThisDispatch) {
3762 if (it.key()->resourceType() == QRhiResource::Texture) {
3764 VkImageMemoryBarrier barrier = {};
3765 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3766 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3768 barrier.subresourceRange.baseMipLevel = 0;
3769 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3770 barrier.subresourceRange.baseArrayLayer = 0;
3771 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3772 barrier.oldLayout = texD->usageState.layout;
3773 barrier.newLayout = texD->usageState.layout;
3774 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3775 barrier.dstAccessMask = accessInThisDispatch;
3776 barrier.image = texD->image;
3777 imageBarriers->append(barrier);
3780 VkBufferMemoryBarrier barrier = {};
3781 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3782 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3783 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3784 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3785 barrier.dstAccessMask = accessInThisDispatch;
3786 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3787 barrier.size = VK_WHOLE_SIZE;
3788 bufferBarriers->append(barrier);
3794 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3795 it = cbD->computePassState.writtenResources.erase(it);
3806 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3807 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3808 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
3811 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3812 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3813 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3815 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3816 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3818 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3820 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3823 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3824 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3825 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3826 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3827 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3828 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3829 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3830 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3834 cmd.args.dispatch.x = x;
3835 cmd.args.dispatch.y = y;
3836 cmd.args.dispatch.z = z;
3841 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3842 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3843 quint32 maxDrawCount, quint32 stride)
3845 if (!caps.drawIndirectCount) {
3846 qWarning(
"drawIndirectCount called but the DrawIndirectCount feature is not supported");
3855 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3856 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3858 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3862 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3865 countBufD->lastActiveFrameSlot = currentFrameSlot;
3866 if (countBufD->m_type == QRhiBuffer::Dynamic)
3868 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3872 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3875#ifdef VK_VERSION_1_2
3876 vkCmdDrawIndirectCount(cbD->activeSecondaryCbStack.last(),
3877 indirectBufVk, indirectBufferOffset,
3878 countBufVk, countBufferOffset,
3879 maxDrawCount, stride);
3884 cmd.args.drawIndirectCount.indirectBuffer = indirectBufVk;
3885 cmd.args.drawIndirectCount.indirectBufferOffset = indirectBufferOffset;
3886 cmd.args.drawIndirectCount.countBuffer = countBufVk;
3887 cmd.args.drawIndirectCount.countBufferOffset = countBufferOffset;
3888 cmd.args.drawIndirectCount.maxDrawCount = maxDrawCount;
3889 cmd.args.drawIndirectCount.stride = stride;
3894 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3895 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3896 quint32 maxDrawCount, quint32 stride)
3898 if (!caps.drawIndirectCount) {
3899 qWarning(
"drawIndexedIndirectCount called but the DrawIndirectCount feature is not supported");
3908 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3909 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3911 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3915 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3918 countBufD->lastActiveFrameSlot = currentFrameSlot;
3919 if (countBufD->m_type == QRhiBuffer::Dynamic)
3921 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3925 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3928#ifdef VK_VERSION_1_2
3929 vkCmdDrawIndexedIndirectCount(cbD->activeSecondaryCbStack.last(),
3930 indirectBufVk, indirectBufferOffset,
3931 countBufVk, countBufferOffset,
3932 maxDrawCount, stride);
3937 cmd.args.drawIndexedIndirectCount.indirectBuffer = indirectBufVk;
3938 cmd.args.drawIndexedIndirectCount.indirectBufferOffset = indirectBufferOffset;
3939 cmd.args.drawIndexedIndirectCount.countBuffer = countBufVk;
3940 cmd.args.drawIndexedIndirectCount.countBufferOffset = countBufferOffset;
3941 cmd.args.drawIndexedIndirectCount.maxDrawCount = maxDrawCount;
3942 cmd.args.drawIndexedIndirectCount.stride = stride;
3947 quint32 indirectBufferOffset)
3954 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3955 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3957 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3958 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3963 VkAccessFlags indirectSrcAccess = 0;
3964 VkPipelineStageFlags indirectSrcStage = 0;
3969 if (cbD->computePassState.writtenResources.contains(indirectBufD)) {
3970 indirectSrcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
3971 indirectSrcStage |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3979 const auto trackedIt = passResTracker
.buffers().find(indirectBufD);
3980 if (trackedIt != passResTracker
.buffers().cend()
3983 indirectSrcAccess |= VkAccessFlags(trackedIt->second.stateAtPassBegin.access);
3984 indirectSrcStage |= VkPipelineStageFlags(trackedIt->second.stateAtPassBegin.stage);
3987 u.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
3988 u.stage |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
3995 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3996 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3997 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
3999 VkBufferMemoryBarrier indirectBarrier = {};
4000 const bool needsIndirectBarrier = indirectSrcStage != 0 && accessIsWrite(indirectSrcAccess);
4001 if (needsIndirectBarrier) {
4002 indirectBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4003 indirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4004 indirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4005 indirectBarrier.srcAccessMask = indirectSrcAccess;
4006 indirectBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
4007 indirectBarrier.buffer = indirectBufVk;
4008 indirectBarrier.size = VK_WHOLE_SIZE;
4012 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
4013 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
4014 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
4016 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
4017 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
4019 if (needsIndirectBarrier) {
4020 df->vkCmdPipelineBarrier(secondaryCb, indirectSrcStage, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
4022 1, &indirectBarrier,
4025 df->vkCmdDispatchIndirect(secondaryCb, indirectBufVk, VkDeviceSize(indirectBufferOffset));
4027 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
4030 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4031 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4032 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
4033 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
4034 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
4035 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
4036 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
4037 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
4039 if (needsIndirectBarrier) {
4042 cmd.args.bufferBarrier.srcStageMask = indirectSrcStage;
4043 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
4044 cmd.args.bufferBarrier.count = 1;
4045 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4046 cbD->pools.bufferBarrier.append(indirectBarrier);
4050 cmd.args.dispatchIndirect.indirectBuffer = indirectBufVk;
4051 cmd.args.dispatchIndirect.indirectBufferOffset = VkDeviceSize(indirectBufferOffset);
4057 VkShaderModuleCreateInfo shaderInfo = {};
4058 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
4059 shaderInfo.codeSize = size_t(spirv.size());
4060 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
4061 VkShaderModule shaderModule;
4062 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
4063 if (err != VK_SUCCESS) {
4064 qWarning(
"Failed to create shader module: %d", err);
4065 return VK_NULL_HANDLE;
4067 return shaderModule;
4075 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
4076 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
4077 pipelineCacheInfo.initialDataSize = initialDataSize;
4078 pipelineCacheInfo.pInitialData = initialData;
4079 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
4080 if (err != VK_SUCCESS) {
4081 qWarning(
"Failed to create pipeline cache: %d", err);
4091 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
4092 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
4093 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
4094 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
4095 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
4097 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
4098 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
4101 VkWriteDescriptorSet writeInfo = {};
4102 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
4103 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
4104 writeInfo.dstBinding = uint32_t(b->binding);
4105 writeInfo.descriptorCount = 1;
4107 int bufferInfoIndex = -1;
4108 int imageInfoIndex = -1;
4111 case QRhiShaderResourceBinding::UniformBuffer:
4113 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
4114 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
4115 QRhiBuffer *buf = b->u.ubuf.buf;
4117 bd.ubuf.id = bufD->m_id;
4119 VkDescriptorBufferInfo bufInfo = {};
4120 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4121 bufInfo.offset = b->u.ubuf.offset;
4122 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
4124 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
4125 bufferInfoIndex = bufferInfos.size();
4126 bufferInfos.append(bufInfo);
4129 case QRhiShaderResourceBinding::SampledTexture:
4131 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
4132 writeInfo.descriptorCount = data->count();
4133 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
4134 ArrayOfImageDesc imageInfo(data->count());
4135 bd.stex.d.resize(data->count());
4136 for (
int elem = 0; elem < data->count(); ++elem) {
4139 bd.stex.d[elem].texId = texD->m_id;
4141 bd.stex.d[elem].samplerId = samplerD->m_id;
4142 bd.stex.d[elem].samplerGeneration = samplerD
->generation;
4143 imageInfo[elem].sampler = samplerD->sampler;
4144 imageInfo[elem].imageView = texD->imageView;
4145 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4147 imageInfoIndex = imageInfos.size();
4148 imageInfos.append(imageInfo);
4151 case QRhiShaderResourceBinding::Texture:
4153 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
4154 writeInfo.descriptorCount = data->count();
4155 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
4156 ArrayOfImageDesc imageInfo(data->count());
4157 bd.stex.d.resize(data->count());
4158 for (
int elem = 0; elem < data->count(); ++elem) {
4160 bd.stex.d[elem].texId = texD->m_id;
4162 bd.stex.d[elem].samplerId = 0;
4163 bd.stex.d[elem].samplerGeneration = 0;
4164 imageInfo[elem].sampler = VK_NULL_HANDLE;
4165 imageInfo[elem].imageView = texD->imageView;
4166 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4168 imageInfoIndex = imageInfos.size();
4169 imageInfos.append(imageInfo);
4172 case QRhiShaderResourceBinding::Sampler:
4175 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
4176 bd.stex.d.resize(1);
4177 bd.stex.d[0].texId = 0;
4178 bd.stex.d[0].texGeneration = 0;
4179 bd.stex.d[0].samplerId = samplerD->m_id;
4181 ArrayOfImageDesc imageInfo(1);
4182 imageInfo[0].sampler = samplerD->sampler;
4183 imageInfo[0].imageView = VK_NULL_HANDLE;
4184 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4185 imageInfoIndex = imageInfos.size();
4186 imageInfos.append(imageInfo);
4189 case QRhiShaderResourceBinding::ImageLoad:
4190 case QRhiShaderResourceBinding::ImageStore:
4191 case QRhiShaderResourceBinding::ImageLoadStore:
4194 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
4196 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
4197 bd.simage.id = texD->m_id;
4199 ArrayOfImageDesc imageInfo(1);
4200 imageInfo[0].sampler = VK_NULL_HANDLE;
4201 imageInfo[0].imageView = view;
4202 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4203 imageInfoIndex = imageInfos.size();
4204 imageInfos.append(imageInfo);
4208 case QRhiShaderResourceBinding::BufferLoad:
4209 case QRhiShaderResourceBinding::BufferStore:
4210 case QRhiShaderResourceBinding::BufferLoadStore:
4213 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
4214 bd.sbuf.id = bufD->m_id;
4216 VkDescriptorBufferInfo bufInfo = {};
4217 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4218 bufInfo.offset = b->u.sbuf.offset;
4219 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
4220 bufferInfoIndex = bufferInfos.size();
4221 bufferInfos.append(bufInfo);
4228 writeInfos.append(writeInfo);
4229 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
4232 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
4233 const int bufferInfoIndex = infoIndices[i].first;
4234 const int imageInfoIndex = infoIndices[i].second;
4235 if (bufferInfoIndex >= 0)
4236 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
4237 else if (imageInfoIndex >= 0)
4238 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
4241 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
4245 VkAccessFlags access, VkPipelineStageFlags stage)
4248 Q_ASSERT(access && stage);
4256 if (s.access == access && s.stage == stage) {
4259 if (!accessIsWrite(access))
4263 VkBufferMemoryBarrier bufMemBarrier = {};
4264 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4265 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4266 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4267 bufMemBarrier.srcAccessMask = s.access;
4268 bufMemBarrier.dstAccessMask = access;
4269 bufMemBarrier.buffer = bufD->buffers[slot];
4270 bufMemBarrier.size = VK_WHOLE_SIZE;
4274 cmd.args.bufferBarrier.srcStageMask = s.stage;
4275 cmd.args.bufferBarrier.dstStageMask = stage;
4276 cmd.args.bufferBarrier.count = 1;
4277 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4278 cbD->pools.bufferBarrier.append(bufMemBarrier);
4285 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
4288 Q_ASSERT(layout && access && stage);
4290 if (s.access == access && s.stage == stage && s.layout == layout) {
4291 if (!accessIsWrite(access))
4295 VkImageMemoryBarrier barrier = {};
4296 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4297 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
4298 barrier.subresourceRange.baseMipLevel = 0;
4299 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4300 barrier.subresourceRange.baseArrayLayer = 0;
4301 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4302 barrier.oldLayout = s.layout;
4303 barrier.newLayout = layout;
4304 barrier.srcAccessMask = s.access;
4305 barrier.dstAccessMask = access;
4306 barrier.image = texD->image;
4308 VkPipelineStageFlags srcStage = s.stage;
4311 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4315 cmd.args.imageBarrier.srcStageMask = srcStage;
4316 cmd.args.imageBarrier.dstStageMask = stage;
4317 cmd.args.imageBarrier.count = 1;
4318 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4319 cbD->pools.imageBarrier.append(barrier);
4330 VkImageMemoryBarrier barrier = {};
4331 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4332 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4333 barrier.subresourceRange.baseMipLevel = 0;
4334 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4335 barrier.subresourceRange.baseArrayLayer = 0;
4336 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4337 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4338 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4339 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4340 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4341 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4342 barrier.image = rbD->image;
4344 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4345 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4349 cmd.args.imageBarrier.srcStageMask = stages;
4350 cmd.args.imageBarrier.dstStageMask = stages;
4351 cmd.args.imageBarrier.count = 1;
4352 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4353 cbD->pools.imageBarrier.append(barrier);
4357 VkImageLayout oldLayout, VkImageLayout newLayout,
4358 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4359 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4360 int startLayer,
int layerCount,
4361 int startLevel,
int levelCount)
4364 VkImageMemoryBarrier barrier = {};
4365 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4366 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4367 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4368 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4369 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4370 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4371 barrier.oldLayout = oldLayout;
4372 barrier.newLayout = newLayout;
4373 barrier.srcAccessMask = srcAccess;
4374 barrier.dstAccessMask = dstAccess;
4375 barrier.image = image;
4379 cmd.args.imageBarrier.srcStageMask = srcStage;
4380 cmd.args.imageBarrier.dstStageMask = dstStage;
4381 cmd.args.imageBarrier.count = 1;
4382 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4383 cbD->pools.imageBarrier.append(barrier);
4388 VkDeviceSize size = 0;
4389 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4390 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4391 if (imageSizeBytes > 0)
4392 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4397 const QRhiTextureSubresourceUploadDescription &subresDesc,
4398 size_t *curOfs,
void *mp,
4399 BufferImageCopyList *copyInfos)
4401 qsizetype copySizeBytes = 0;
4402 qsizetype imageSizeBytes = 0;
4403 const void *src =
nullptr;
4404 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4405 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4407 VkBufferImageCopy copyInfo = {};
4408 copyInfo.bufferOffset = *curOfs;
4409 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4410 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4411 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4412 copyInfo.imageSubresource.layerCount = 1;
4413 copyInfo.imageExtent.depth = 1;
4415 copyInfo.imageOffset.z = uint32_t(layer);
4417 copyInfo.imageOffset.y = uint32_t(layer);
4419 const QByteArray rawData = subresDesc.data();
4420 const QPoint dp = subresDesc.destinationTopLeft();
4421 QImage image = subresDesc.image();
4422 if (!image.isNull()) {
4423 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4424 QSize size = image.size();
4425 src = image.constBits();
4428 int bpc = qMax(1, image.depth() / 8);
4430 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4431 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4432 const int sx = subresDesc.sourceTopLeft().x();
4433 const int sy = subresDesc.sourceTopLeft().y();
4434 if (!subresDesc.sourceSize().isEmpty())
4435 size = subresDesc.sourceSize();
4436 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4437 if (size.width() == image.width()) {
4440 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4441 copySizeBytes = size.height() * image.bytesPerLine();
4443 image = image.copy(sx, sy, size.width(), size.height());
4444 src = image.constBits();
4447 copySizeBytes = image.sizeInBytes();
4448 bpc = qMax(1, image.depth() / 8);
4449 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4452 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4454 copyInfo.imageOffset.x = dp.x();
4455 copyInfo.imageOffset.y = dp.y();
4456 copyInfo.imageExtent.width = uint32_t(size.width());
4457 copyInfo.imageExtent.height = uint32_t(size.height());
4458 copyInfos->append(copyInfo);
4459 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4460 copySizeBytes = imageSizeBytes = rawData.size();
4461 src = rawData.constData();
4462 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4463 const int subresw = size.width();
4464 const int subresh = size.height();
4465 if (!subresDesc.sourceSize().isEmpty())
4466 size = subresDesc.sourceSize();
4467 const int w = size.width();
4468 const int h = size.height();
4470 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4472 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4473 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4476 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4477 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4478 copyInfos->append(copyInfo);
4479 }
else if (!rawData.isEmpty()) {
4480 copySizeBytes = imageSizeBytes = rawData.size();
4481 src = rawData.constData();
4482 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4483 if (!subresDesc.sourceSize().isEmpty())
4484 size = subresDesc.sourceSize();
4485 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4487 quint32 bytesPerPixel = 0;
4488 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4489 if (subresDesc.dataStride() && bytesPerPixel)
4490 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4492 size = clampedSubResourceUploadSizeForSourceData(size, subresDesc.dataStride(),
4493 bytesPerPixel, rawData.size());
4495 if (!size.isEmpty()) {
4496 copyInfo.imageOffset.x = dp.x();
4497 copyInfo.imageOffset.y = dp.y();
4498 copyInfo.imageExtent.width = uint32_t(size.width());
4499 copyInfo.imageExtent.height = uint32_t(size.height());
4500 copyInfos->append(copyInfo);
4503 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4507 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4508 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4514 if (err == VK_ERROR_DEVICE_LOST)
4515 printDeviceLossErrorInfo();
4516 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4517 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4522#ifdef VK_EXT_device_fault
4523 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4526 VkDeviceFaultCountsEXT faultCounts{};
4527 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4528 faultCounts.pNext =
nullptr;
4530 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4531 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4532 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4535 faultCounts.vendorBinarySize = 0;
4537 const auto numAddressInfos = faultCounts.addressInfoCount;
4538 const auto addressInfos
4539 = q20::make_unique_for_overwrite<VkDeviceFaultAddressInfoEXT[]>(numAddressInfos);
4541 const auto numVendorInfos = faultCounts.vendorInfoCount;
4542 const auto vendorInfos
4543 = q20::make_unique_for_overwrite<VkDeviceFaultVendorInfoEXT[]>(numVendorInfos);
4545 VkDeviceFaultInfoEXT info{};
4546 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4547 info.pNext =
nullptr;
4548 info.pAddressInfos = numAddressInfos ? addressInfos.get() :
nullptr;
4549 info.pVendorInfos = numVendorInfos ? vendorInfos.get() :
nullptr;
4550 info.pVendorBinaryData =
nullptr;
4552 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4553 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4554 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4558 const char *desc = info.description[0] ? info.description :
"n/a";
4559 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4560 faultCounts.addressInfoCount,
4561 faultCounts.vendorInfoCount,
4562 (
unsigned long long)faultCounts.vendorBinarySize,
4565 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4566 const auto &a = addressInfos[i];
4567 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4569 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4570 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4571 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4572 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4573 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4574 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4575 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4576 default:
return "UNKNOWN";
4579 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4581 addressTypeString(a.addressType),
4582 (
unsigned long long)a.reportedAddress,
4583 (
unsigned long long)a.addressPrecision);
4586 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4587 const auto &v = vendorInfos[i];
4588 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4590 (
unsigned long long)v.vendorFaultCode,
4591 (
unsigned long long)v.vendorFaultData,
4605 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4607 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4608 bufD->pendingDynamicUpdates[i].clear();
4609 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4613 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4614 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4616 if (!bufD->stagingBuffers[currentFrameSlot]) {
4617 VkBufferCreateInfo bufferInfo = {};
4618 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4621 bufferInfo.size = bufD->m_size;
4622 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4624 VmaAllocationCreateInfo allocInfo = {};
4625 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4627 VmaAllocation allocation;
4628 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4629 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4630 if (err == VK_SUCCESS) {
4631 bufD->stagingAllocations[currentFrameSlot] = allocation;
4632 setAllocationName(allocation, bufD->name());
4634 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4635 printExtraErrorInfo(err);
4640 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4641 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4642 u.offset, u
.data.size());
4643 if (err != VK_SUCCESS) {
4644 qWarning(
"Failed to copy memory to buffer: %d", err);
4648 trackedBufferBarrier(cbD, bufD, 0,
4649 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4651 VkBufferCopy copyInfo = {};
4652 copyInfo.srcOffset = u.offset;
4653 copyInfo.dstOffset = u.offset;
4654 copyInfo.size = u
.data.size();
4658 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4659 cmd.args.copyBuffer.dst = bufD->buffers[0];
4660 cmd.args.copyBuffer.desc = copyInfo;
4669 bufD->lastActiveFrameSlot = currentFrameSlot;
4671 if (bufD->m_type == QRhiBuffer::Immutable) {
4674 e.lastActiveFrameSlot = currentFrameSlot;
4675 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4676 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4677 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4678 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4679 releaseQueue.append(e);
4683 if (bufD->m_type == QRhiBuffer::Dynamic) {
4685 u.result->data.resizeForOverwrite(u.readSize);
4686 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4687 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4688 u.offset, u.result->data.data(), u.readSize);
4689 if (err != VK_SUCCESS) {
4690 qWarning(
"Failed to copy memory from buffer: %d", err);
4691 u.result->data.clear();
4693 if (u.result->completed)
4694 u.result->completed();
4703 readback.activeFrameSlot = currentFrameSlot;
4704 readback.result = u.result;
4705 readback.byteSize = u.readSize;
4707 VkBufferCreateInfo bufferInfo = {};
4708 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4709 bufferInfo.size = readback.byteSize;
4710 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4712 VmaAllocationCreateInfo allocInfo = {};
4713 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4715 VmaAllocation allocation;
4716 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4717 if (err == VK_SUCCESS) {
4719 setAllocationName(allocation, bufD->name());
4721 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4722 printExtraErrorInfo(err);
4726 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4728 VkBufferCopy copyInfo = {};
4729 copyInfo.srcOffset = u.offset;
4730 copyInfo.size = u.readSize;
4734 cmd.args.copyBuffer.src = bufD->buffers[0];
4735 cmd.args.copyBuffer.dst = readback.stagingBuf;
4736 cmd.args.copyBuffer.desc = copyInfo;
4738 bufD->lastActiveFrameSlot = currentFrameSlot;
4740 activeBufferReadbacks.append(readback);
4745 Q_ASSERT(dstD->m_type != QRhiBuffer::Dynamic && srcD->m_type != QRhiBuffer::Dynamic);
4747 trackedBufferBarrier(cbD, srcD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4748 trackedBufferBarrier(cbD, dstD, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4750 VkBufferCopy copyInfo = {};
4751 copyInfo.srcOffset = u.srcOffset;
4752 copyInfo.dstOffset = u.offset;
4753 copyInfo.size = u.readSize;
4757 cmd.args.copyBuffer.src = srcD->buffers[0];
4758 cmd.args.copyBuffer.dst = dstD->buffers[0];
4759 cmd.args.copyBuffer.desc = copyInfo;
4761 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4764 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4766 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4770 cmd.args.fillBuffer.dst = bufD->buffers[0];
4771 cmd.args.fillBuffer.offset = u.offset;
4772 cmd.args.fillBuffer.size = u.readSize;
4773 cmd.args.fillBuffer.data = u.fillValue32();
4775 bufD->lastActiveFrameSlot = currentFrameSlot;
4784 VkDeviceSize stagingSize = 0;
4785 for (
const auto &subres : u.subresDesc)
4786 stagingSize += subresUploadByteSize(subres.desc);
4788 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4789 VkBufferCreateInfo bufferInfo = {};
4790 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4791 bufferInfo.size = stagingSize;
4792 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4794 VmaAllocationCreateInfo allocInfo = {};
4795 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4797 VmaAllocation allocation;
4798 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4799 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4800 if (err != VK_SUCCESS) {
4801 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4802 printExtraErrorInfo(err);
4805 utexD->stagingAllocations[currentFrameSlot] = allocation;
4806 setAllocationName(allocation, utexD->name());
4808 BufferImageCopyList copyInfos;
4811 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4812 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4813 if (err != VK_SUCCESS) {
4814 qWarning(
"Failed to map image data: %d", err);
4815 vmaDestroyBuffer(toVmaAllocator(allocator), utexD->stagingBuffers[currentFrameSlot], a);
4816 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4817 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4821 for (
const auto &subres : u.subresDesc)
4822 prepareUploadSubres(utexD, subres.layer, subres.level, subres.desc, &curOfs, mp, ©Infos);
4823 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4824 vmaUnmapMemory(toVmaAllocator(allocator), a);
4826 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4827 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4829 if (!copyInfos.isEmpty()) {
4832 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4833 cmd.args.copyBufferToImage.dst = utexD->image;
4834 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4835 cmd.args.copyBufferToImage.count = copyInfos.size();
4836 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4837 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4843 e.lastActiveFrameSlot = currentFrameSlot;
4844 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4845 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4846 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4847 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4848 releaseQueue.append(e);
4853 utexD->lastActiveFrameSlot = currentFrameSlot;
4857 qWarning(
"Texture copy with matching source and destination is not supported");
4862 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4863 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4865 VkImageCopy region = {};
4866 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4867 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4868 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4869 region.srcSubresource.layerCount = 1;
4871 region.srcOffset.x = u.desc.sourceTopLeft().x();
4872 region.srcOffset.y = u.desc.sourceTopLeft().y();
4874 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4876 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4877 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4878 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4879 region.dstSubresource.layerCount = 1;
4881 region.dstOffset.x = u.desc.destinationTopLeft().x();
4882 region.dstOffset.y = u.desc.destinationTopLeft().y();
4884 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4886 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4887 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4888 region.extent.width = uint32_t(copySize.width());
4889 region.extent.height = uint32_t(copySize.height());
4890 region.extent.depth = 1;
4892 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4893 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4894 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4895 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4899 cmd.args.copyImage.src = srcD->image;
4900 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4901 cmd.args.copyImage.dst = dstD->image;
4902 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4903 cmd.args.copyImage.desc = region;
4905 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4908 readback.activeFrameSlot = currentFrameSlot;
4909 readback.desc = u.rb;
4910 readback.result = u.result;
4916 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4917 qWarning(
"Multisample texture cannot be read back");
4920 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4921 if (u.rb.rect().isValid())
4922 readback.rect = u.rb.rect();
4924 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4925 readback.format = texD->m_format;
4926 texD->lastActiveFrameSlot = currentFrameSlot;
4931 qWarning(
"Swapchain does not support readback");
4934 if (u.rb.rect().isValid())
4935 readback.rect = u.rb.rect();
4937 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4938 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4939 if (readback.format == QRhiTexture::UnknownFormat)
4945 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4948 VkBufferCreateInfo bufferInfo = {};
4949 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4950 bufferInfo.size = readback.byteSize;
4951 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4953 VmaAllocationCreateInfo allocInfo = {};
4954 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4956 VmaAllocation allocation;
4957 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4958 if (err == VK_SUCCESS) {
4960 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4962 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4963 printExtraErrorInfo(err);
4968 VkBufferImageCopy copyDesc = {};
4969 copyDesc.bufferOffset = 0;
4970 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4971 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4972 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4973 copyDesc.imageSubresource.layerCount = 1;
4974 copyDesc.imageOffset.x = readback.rect.x();
4975 copyDesc.imageOffset.y = readback.rect.y();
4977 copyDesc.imageOffset.z = u.rb.layer();
4978 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4979 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4980 copyDesc.imageExtent.depth = 1;
4983 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4984 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4987 cmd.args.copyImageToBuffer.src = texD->image;
4988 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4989 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4990 cmd.args.copyImageToBuffer.desc = copyDesc;
4994 VkImage image = imageRes.image;
4997 qWarning(
"Attempted to read back undefined swapchain image content, "
4998 "results are undefined. (do a render pass first)");
5000 subresourceBarrier(cbD, image,
5001 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5002 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
5003 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5011 cmd.args.copyImageToBuffer.src = image;
5012 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5013 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
5014 cmd.args.copyImageToBuffer.desc = copyDesc;
5017 activeTextureReadbacks.append(readback);
5020 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
5021 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
5022 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
5023 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
5025 VkImageLayout origLayout = utexD->usageState.layout;
5026 VkAccessFlags origAccess = utexD->usageState.access;
5027 VkPipelineStageFlags origStage = utexD->usageState.stage;
5029 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5031 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
5032 int w = utexD->m_pixelSize.width();
5033 int h = utexD->m_pixelSize.height();
5034 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
5037 subresourceBarrier(cbD, utexD->image,
5038 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5039 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
5040 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
5044 subresourceBarrier(cbD, utexD->image,
5045 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5046 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
5047 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
5052 subresourceBarrier(cbD, utexD->image,
5053 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5054 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
5055 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
5059 VkImageBlit region = {};
5060 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5061 region.srcSubresource.mipLevel = uint32_t(level) - 1;
5062 region.srcSubresource.baseArrayLayer = uint32_t(layer);
5063 region.srcSubresource.layerCount = 1;
5065 region.srcOffsets[1].x = qMax(1, w);
5066 region.srcOffsets[1].y = qMax(1, h);
5067 region.srcOffsets[1].z = qMax(1, depth);
5069 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5070 region.dstSubresource.mipLevel = uint32_t(level);
5071 region.dstSubresource.baseArrayLayer = uint32_t(layer);
5072 region.dstSubresource.layerCount = 1;
5074 region.dstOffsets[1].x = qMax(1, w >> 1);
5075 region.dstOffsets[1].y = qMax(1, h >> 1);
5076 region.dstOffsets[1].z = qMax(1, depth >> 1);
5080 cmd.args.blitImage.src = utexD->image;
5081 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5082 cmd.args.blitImage.dst = utexD->image;
5083 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5084 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
5085 cmd.args.blitImage.desc = region;
5093 subresourceBarrier(cbD, utexD->image,
5094 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
5095 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
5096 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5098 0,
int(utexD->mipLevelCount) - 1);
5099 subresourceBarrier(cbD, utexD->image,
5100 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
5101 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
5102 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5104 int(utexD->mipLevelCount) - 1, 1);
5107 utexD->lastActiveFrameSlot = currentFrameSlot;
5116 if (bufD->pendingDynamicUpdates[slot].isEmpty())
5119 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
5121 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
5125 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
5126 if (err != VK_SUCCESS) {
5127 qWarning(
"Failed to map buffer: %d", err);
5130 quint32 changeBegin = UINT32_MAX;
5131 quint32 changeEnd = 0;
5132 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
5133 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
5134 if (u.offset < changeBegin)
5135 changeBegin = u.offset;
5136 if (u.offset + u.data.size() > changeEnd)
5137 changeEnd = u.offset + u.data.size();
5139 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
5140 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
5141 vmaUnmapMemory(toVmaAllocator(allocator), a);
5143 bufD->pendingDynamicUpdates[slot].clear();
5149 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
5150 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
5156 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
5157 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
5158 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
5163 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
5164 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
5166 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
5167 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
5168 if (e.texture.extraImageViews[i])
5169 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
5175 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
5180 qsizetype keepBegin = releaseQueue.size();
5181 for (qsizetype i = keepBegin - 1; i >= 0; --i) {
5183 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
5186 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
5187 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
5190 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
5191 if (e.shaderResourceBindings.poolIndex >= 0) {
5192 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
5193 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
5200 qrhivk_releaseRenderBuffer(e, dev,
df);
5206 qrhivk_releaseSampler(e, dev,
df);
5209 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
5211 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
5212 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
5214 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
5215 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
5216 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
5219 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
5222 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
5224 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
5225 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
5231 }
else if (--keepBegin != i) {
5232 releaseQueue[keepBegin] = std::move(releaseQueue[i]);
5236 releaseQueue.remove(0, keepBegin);
5241 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5243 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
5245 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5246 readback.result->format = readback.format;
5247 readback.result->pixelSize = readback.rect.size();
5248 readback.result->data.resizeForOverwrite(readback.byteSize);
5249 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5250 toVmaAllocation(readback.stagingAlloc),
5251 0, readback.result->data.data(), readback.byteSize);
5252 if (err != VK_SUCCESS) {
5253 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
5254 readback.result->data.clear();
5257 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5259 if (readback.result->completed)
5260 completedCallbacks.append(readback.result->completed);
5262 activeTextureReadbacks.remove(i);
5266 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
5268 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5269 readback.result->data.resizeForOverwrite(readback.byteSize);
5270 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5271 toVmaAllocation(readback.stagingAlloc),
5272 0, readback.result->data.data(), readback.byteSize);
5273 if (err != VK_SUCCESS) {
5274 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
5275 readback.result->data.clear();
5278 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5280 if (readback.result->completed)
5281 completedCallbacks.append(readback.result->completed);
5283 activeBufferReadbacks.remove(i);
5287 for (
const auto &f : completedCallbacks)
5294} qvk_sampleCounts[] = {
5296 { VK_SAMPLE_COUNT_1_BIT, 1 },
5297 { VK_SAMPLE_COUNT_2_BIT, 2 },
5298 { VK_SAMPLE_COUNT_4_BIT, 4 },
5299 { VK_SAMPLE_COUNT_8_BIT, 8 },
5300 { VK_SAMPLE_COUNT_16_BIT, 16 },
5301 { VK_SAMPLE_COUNT_32_BIT, 32 },
5302 { VK_SAMPLE_COUNT_64_BIT, 64 }
5307 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
5308 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
5309 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
5310 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
5313 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5314 if ((color & qvk_sampleCount.mask)
5315 && (depth & qvk_sampleCount.mask)
5316 && (stencil & qvk_sampleCount.mask))
5318 result.append(qvk_sampleCount.count);
5327 const int s = effectiveSampleCount(sampleCount);
5329 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5330 if (qvk_sampleCount.count == s)
5331 return qvk_sampleCount.mask;
5334 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
5339 QList<QSize> result;
5340#ifdef VK_KHR_fragment_shading_rate
5341 sampleCount = qMax(1, sampleCount);
5342 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
5343 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5344 if (qvk_sampleCount.count == sampleCount) {
5345 mask = qvk_sampleCount.mask;
5349 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
5350 if (s.sampleCounts & mask)
5351 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
5354 Q_UNUSED(sampleCount);
5355 result.append(QSize(1, 1));
5362 cbD->passResTrackers.emplace_back();
5367 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5374 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5378 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5379 1, &cmd.args.copyBuffer.desc);
5382 df->vkCmdFillBuffer(cbD->cb, cmd.args.fillBuffer.dst, cmd.args.fillBuffer.offset,
5383 cmd.args.fillBuffer.size, cmd.args.fillBuffer.data);
5386 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5387 cmd.args.copyBufferToImage.dstLayout,
5388 uint32_t(cmd.args.copyBufferToImage.count),
5389 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5392 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5393 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5394 1, &cmd.args.copyImage.desc);
5397 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5398 cmd.args.copyImageToBuffer.dst,
5399 1, &cmd.args.copyImageToBuffer.desc);
5402 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5403 0, 0,
nullptr, 0,
nullptr,
5404 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5407 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5409 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5413 const auto &barrier = cmd.args.imageAndBufferBarrier;
5414 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5415 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5416 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5417 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5418 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5420 barrier.bufferCount, bufferBarrierData,
5421 barrier.imageCount, imageBarrierData);
5424 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5425 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5426 1, &cmd.args.blitImage.desc,
5427 cmd.args.blitImage.filter);
5430 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5431 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5432 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5433 : VK_SUBPASS_CONTENTS_INLINE);
5436 VkMemoryBarrier barrier = {};
5437 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5438 barrier.pNext =
nullptr;
5439 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5440 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5441 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5447 df->vkCmdEndRenderPass(cbD->cb);
5450 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5454 const uint32_t *offsets =
nullptr;
5455 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5456 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5457 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5458 cmd.args.bindDescriptorSet.pipelineLayout,
5459 0, 1, &cmd.args.bindDescriptorSet.descSet,
5460 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5465 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5466 uint32_t(cmd.args.bindVertexBuffer.count),
5467 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5468 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5471 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5472 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5475 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5478 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5481 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5484 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5487 df->vkCmdPushConstants(cbD->cb,
5488 cmd.args.setPushConstants.layout,
5489 cmd.args.setPushConstants.stages,
5490 cmd.args.setPushConstants.offset,
5491 cmd.args.setPushConstants.size,
5492 cbD->pools.pushConstantData.constData() + cmd.args.setPushConstants.dataIndex);
5495 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5496 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5499 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5500 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5501 cmd.args.drawIndexed.firstInstance);
5504 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5505 cmd.args.drawIndirect.indirectBufferOffset,
5506 cmd.args.drawIndirect.drawCount,
5507 cmd.args.drawIndirect.stride);
5510 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5511 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5512 cmd.args.drawIndexedIndirect.drawCount,
5513 cmd.args.drawIndexedIndirect.stride);
5515#ifdef VK_VERSION_1_2
5516 case QVkCommandBuffer::Command::DrawIndirectCount:
5517 vkCmdDrawIndirectCount(cbD->cb,
5518 cmd.args.drawIndirectCount.indirectBuffer,
5519 cmd.args.drawIndirectCount.indirectBufferOffset,
5520 cmd.args.drawIndirectCount.countBuffer,
5521 cmd.args.drawIndirectCount.countBufferOffset,
5522 cmd.args.drawIndirectCount.maxDrawCount,
5523 cmd.args.drawIndirectCount.stride);
5525 case QVkCommandBuffer::Command::DrawIndexedIndirectCount:
5526 vkCmdDrawIndexedIndirectCount(cbD->cb,
5527 cmd.args.drawIndexedIndirectCount.indirectBuffer,
5528 cmd.args.drawIndexedIndirectCount.indirectBufferOffset,
5529 cmd.args.drawIndexedIndirectCount.countBuffer,
5530 cmd.args.drawIndexedIndirectCount.countBufferOffset,
5531 cmd.args.drawIndexedIndirectCount.maxDrawCount,
5532 cmd.args.drawIndexedIndirectCount.stride);
5536#ifdef VK_EXT_debug_utils
5537 cmd.args.debugMarkerBegin.label.pLabelName =
5538 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5539 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5543#ifdef VK_EXT_debug_utils
5544 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5548#ifdef VK_EXT_debug_utils
5549 cmd.args.debugMarkerInsert.label.pLabelName =
5550 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5551 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5558 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5561 df->vkCmdDispatchIndirect(cbD->cb,
5562 cmd.args.dispatchIndirect.indirectBuffer,
5563 cmd.args.dispatchIndirect.indirectBufferOffset);
5566 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5570#ifdef VK_KHR_fragment_shading_rate
5571 VkFragmentShadingRateCombinerOpKHR op[2] = {
5572 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5573 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5575 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5576 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5589 case QRhiPassResourceTracker::BufIndirectDraw:
5590 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5591 case QRhiPassResourceTracker::BufVertexInput:
5592 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5593 case QRhiPassResourceTracker::BufIndexRead:
5594 return VK_ACCESS_INDEX_READ_BIT;
5595 case QRhiPassResourceTracker::BufUniformRead:
5596 return VK_ACCESS_UNIFORM_READ_BIT;
5597 case QRhiPassResourceTracker::BufStorageLoad:
5598 return VK_ACCESS_SHADER_READ_BIT;
5599 case QRhiPassResourceTracker::BufStorageStore:
5600 return VK_ACCESS_SHADER_WRITE_BIT;
5601 case QRhiPassResourceTracker::BufStorageLoadStore:
5602 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5613 case QRhiPassResourceTracker::BufIndirectDrawStage:
5614 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5615 case QRhiPassResourceTracker::BufVertexInputStage:
5616 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5617 case QRhiPassResourceTracker::BufVertexStage:
5618 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5619 case QRhiPassResourceTracker::BufTCStage:
5620 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5621 case QRhiPassResourceTracker::BufTEStage:
5622 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5623 case QRhiPassResourceTracker::BufFragmentStage:
5624 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5625 case QRhiPassResourceTracker::BufComputeStage:
5626 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5627 case QRhiPassResourceTracker::BufGeometryStage:
5628 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5639 u.access = VkAccessFlags(usage
.access);
5640 u.stage = VkPipelineStageFlags(usage
.stage);
5647 case QRhiPassResourceTracker::TexSample:
5648 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5649 case QRhiPassResourceTracker::TexColorOutput:
5650 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5651 case QRhiPassResourceTracker::TexDepthOutput:
5652 case QRhiPassResourceTracker::TexDepthResolveOutput:
5653 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5654 case QRhiPassResourceTracker::TexStorageLoad:
5655 case QRhiPassResourceTracker::TexStorageStore:
5656 case QRhiPassResourceTracker::TexStorageLoadStore:
5657 return VK_IMAGE_LAYOUT_GENERAL;
5658 case QRhiPassResourceTracker::TexShadingRate:
5659#ifdef VK_KHR_fragment_shading_rate
5660 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5662 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5668 return VK_IMAGE_LAYOUT_GENERAL;
5674 case QRhiPassResourceTracker::TexSample:
5675 return VK_ACCESS_SHADER_READ_BIT;
5676 case QRhiPassResourceTracker::TexColorOutput:
5677 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5678 case QRhiPassResourceTracker::TexDepthOutput:
5679 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5680 case QRhiPassResourceTracker::TexDepthResolveOutput:
5683 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5684 case QRhiPassResourceTracker::TexStorageLoad:
5685 return VK_ACCESS_SHADER_READ_BIT;
5686 case QRhiPassResourceTracker::TexStorageStore:
5687 return VK_ACCESS_SHADER_WRITE_BIT;
5688 case QRhiPassResourceTracker::TexStorageLoadStore:
5689 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5702 case QRhiPassResourceTracker::TexVertexStage:
5703 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5704 case QRhiPassResourceTracker::TexTCStage:
5705 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5706 case QRhiPassResourceTracker::TexTEStage:
5707 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5708 case QRhiPassResourceTracker::TexFragmentStage:
5709 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5710 case QRhiPassResourceTracker::TexColorOutputStage:
5711 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5712 case QRhiPassResourceTracker::TexDepthOutputStage:
5713 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5714 case QRhiPassResourceTracker::TexComputeStage:
5715 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5716 case QRhiPassResourceTracker::TexGeometryStage:
5717 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5728 u.layout = VkImageLayout(usage
.layout);
5729 u.access = VkAccessFlags(usage
.access);
5730 u.stage = VkPipelineStageFlags(usage
.stage);
5741 const VkAccessFlags newAccess = toVkAccess(access);
5742 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5743 if (u.access == newAccess && u.stage == newStage) {
5744 if (!accessIsWrite(newAccess))
5748 u.access = newAccess;
5758 const VkAccessFlags newAccess = toVkAccess(access);
5759 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5760 const VkImageLayout newLayout = toVkLayout(access);
5761 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5762 if (!accessIsWrite(newAccess))
5766 u.layout = newLayout;
5767 u.access = newAccess;
5776 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5777 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5778 VkAccessFlags access = toVkAccess(trackedB.access);
5779 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5780 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5783 if (s.access == access && s.stage == stage) {
5784 if (!accessIsWrite(access))
5787 VkBufferMemoryBarrier bufMemBarrier = {};
5788 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5789 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5790 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5791 bufMemBarrier.srcAccessMask = s.access;
5792 bufMemBarrier.dstAccessMask = access;
5793 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5794 bufMemBarrier.size = VK_WHOLE_SIZE;
5795 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5801 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5802 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5803 VkImageLayout layout = toVkLayout(trackedT.access);
5804 VkAccessFlags access = toVkAccess(trackedT.access);
5805 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5806 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5807 if (s.access == access && s.stage == stage && s.layout == layout) {
5808 if (!accessIsWrite(access))
5811 VkImageMemoryBarrier barrier = {};
5812 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5813 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5814 barrier.subresourceRange.baseMipLevel = 0;
5815 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5816 barrier.subresourceRange.baseArrayLayer = 0;
5817 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5818 barrier.oldLayout = s.layout;
5819 barrier.newLayout = layout;
5820 barrier.srcAccessMask = s.access;
5821 barrier.dstAccessMask = access;
5822 barrier.image = texD->image;
5823 VkPipelineStageFlags srcStage = s.stage;
5826 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5827 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5836 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5837 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5838 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5840 qWarning(
"Physical device surface queries not available");
5844 return new QVkSwapChain(
this);
5847QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5849 return new QVkBuffer(
this, type, usage, size);
5854 return int(ubufAlign);
5877 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
5878 0.0f, -1.0f, 0.0f, 0.0f,
5879 0.0f, 0.0f, 0.5f, 0.5f,
5880 0.0f, 0.0f, 0.0f, 1.0f);
5889 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5890 if (!physDevFeatures.textureCompressionBC)
5894 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5895 if (!physDevFeatures.textureCompressionETC2)
5899 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5900 if (!physDevFeatures.textureCompressionASTC_LDR)
5904 VkFormat vkformat = toVkTextureFormat(format, flags);
5905 VkFormatProperties props;
5906 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5907 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5913 case QRhi::MultisampleTexture:
5915 case QRhi::MultisampleRenderBuffer:
5917 case QRhi::DebugMarkers:
5918 return caps.debugUtils;
5919 case QRhi::Timestamps:
5920 return timestampValidBits != 0;
5921 case QRhi::Instancing:
5923 case QRhi::CustomInstanceStepRate:
5924 return caps.vertexAttribDivisor;
5925 case QRhi::PrimitiveRestart:
5927 case QRhi::NonDynamicUniformBuffers:
5929 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5931 case QRhi::NPOTTextureRepeat:
5933 case QRhi::RedOrAlpha8IsRed:
5935 case QRhi::ElementIndexUint:
5938 return caps.compute;
5939 case QRhi::WideLines:
5940 return caps.wideLines;
5941 case QRhi::VertexShaderPointSize:
5943 case QRhi::BaseVertex:
5945 case QRhi::BaseInstance:
5947 case QRhi::TriangleFanTopology:
5949 case QRhi::ReadBackNonUniformBuffer:
5951 case QRhi::ReadBackNonBaseMipLevel:
5953 case QRhi::TexelFetch:
5955 case QRhi::RenderToNonBaseMipLevel:
5957 case QRhi::IntAttributes:
5959 case QRhi::ScreenSpaceDerivatives:
5961 case QRhi::ReadBackAnyTextureFormat:
5963 case QRhi::PipelineCacheDataLoadSave:
5965 case QRhi::ImageDataStride:
5967 case QRhi::RenderBufferImport:
5969 case QRhi::ThreeDimensionalTextures:
5971 case QRhi::RenderTo3DTextureSlice:
5972 return caps.texture3DSliceAs2D;
5973 case QRhi::TextureArrays:
5975 case QRhi::Tessellation:
5976 return caps.tessellation;
5977 case QRhi::GeometryShader:
5978 return caps.geometryShader;
5979 case QRhi::TextureArrayRange:
5981 case QRhi::NonFillPolygonMode:
5982 return caps.nonFillPolygonMode;
5983 case QRhi::OneDimensionalTextures:
5985 case QRhi::OneDimensionalTextureMipmaps:
5987 case QRhi::HalfAttributes:
5989 case QRhi::RenderToOneDimensionalTexture:
5991 case QRhi::ThreeDimensionalTextureMipmaps:
5993 case QRhi::MultiView:
5994 return caps.multiView;
5995 case QRhi::TextureViewFormat:
5997 case QRhi::ResolveDepthStencil:
5998 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5999 case QRhi::VariableRateShading:
6000 return caps.renderPass2KHR && caps.perDrawShadingRate;
6001 case QRhi::VariableRateShadingMap:
6002 case QRhi::VariableRateShadingMapWithTexture:
6003 return caps.renderPass2KHR && caps.imageBasedShadingRate;
6004 case QRhi::PerRenderTargetBlending:
6005 case QRhi::SampleVariables:
6007 case QRhi::InstanceIndexIncludesBaseInstance:
6009 case QRhi::DepthClamp:
6010 return caps.depthClamp;
6011 case QRhi::DrawIndirect:
6013 case QRhi::DrawIndirectMulti:
6014 return caps.drawIndirectMulti;
6015 case QRhi::ShaderDrawParameters:
6016 return caps.shaderDrawParameters;
6017 case QRhi::DispatchIndirect:
6019 case QRhi::PushConstants:
6021 case QRhi::DrawIndirectCount:
6022 return caps.drawIndirectCount;
6023 case QRhi::BufferToBufferCopy:
6025 case QRhi::StaticBuffersOnGpuTimeline:
6028 Q_UNREACHABLE_RETURN(
false);
6035 case QRhi::TextureSizeMin:
6037 case QRhi::TextureSizeMax:
6038 return int(physDevProperties.limits.maxImageDimension2D);
6039 case QRhi::MaxColorAttachments:
6040 return int(physDevProperties.limits.maxColorAttachments);
6041 case QRhi::FramesInFlight:
6043 case QRhi::MaxAsyncReadbackFrames:
6045 case QRhi::MaxThreadGroupsPerDimension:
6046 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
6047 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
6048 physDevProperties.limits.maxComputeWorkGroupCount[2])));
6049 case QRhi::MaxThreadsPerThreadGroup:
6050 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
6051 case QRhi::MaxThreadGroupX:
6052 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
6053 case QRhi::MaxThreadGroupY:
6054 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
6055 case QRhi::MaxThreadGroupZ:
6056 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
6057 case QRhi::TextureArraySizeMax:
6058 return int(physDevProperties.limits.maxImageArrayLayers);
6059 case QRhi::MaxUniformBufferRange:
6060 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
6061 case QRhi::MaxVertexInputs:
6062 return physDevProperties.limits.maxVertexInputAttributes;
6063 case QRhi::MaxVertexOutputs:
6064 return physDevProperties.limits.maxVertexOutputComponents / 4;
6065 case QRhi::MaxPushConstantsSize:
6066 return int(physDevProperties.limits.maxPushConstantsSize);
6067 case QRhi::MaxVertexStorageBuffers:
6068 case QRhi::MaxFragmentStorageBuffers:
6069 return int(physDevProperties.limits.maxPerStageDescriptorStorageBuffers);
6070 case QRhi::ShadingRateImageTileSize:
6071 return caps.imageBasedShadingRateTileSize;
6073 Q_UNREACHABLE_RETURN(0);
6079 return &nativeHandlesStruct;
6084 return driverInfoStruct;
6090 result.totalPipelineCreationTime = totalPipelineCreationTime();
6092 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
6093 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
6095 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
6096 for (uint32_t i = 0; i < count; ++i) {
6097 const VmaStatistics &stats(budgets[i].statistics);
6098 result.blockCount += stats.blockCount;
6099 result.allocCount += stats.allocationCount;
6100 result.usedBytes += stats.allocationBytes;
6101 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
6115 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
6119 waitSemaphoresForQueueSubmit.clear();
6120 if (sp->waitSemaphoreCount)
6121 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
6123 signalSemaphoresForQueueSubmit.clear();
6124 if (sp->signalSemaphoreCount)
6125 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
6127 waitSemaphoresForPresent.clear();
6128 if (sp->presentWaitSemaphoreCount)
6129 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
6159 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
6162 size_t dataSize = 0;
6163 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
6164 if (err != VK_SUCCESS) {
6165 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
6166 return QByteArray();
6169 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6170 data.resize(dataOffset + dataSize);
6171 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
6172 if (err != VK_SUCCESS) {
6173 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
6174 return QByteArray();
6178 header.rhiId = pipelineCacheRhiId();
6179 header.arch = quint32(
sizeof(
void*));
6180 header.driverVersion = physDevProperties.driverVersion;
6181 header.vendorId = physDevProperties.vendorID;
6182 header.deviceId = physDevProperties.deviceID;
6183 header.dataSize = quint32(dataSize);
6184 header.uuidSize = VK_UUID_SIZE;
6185 header.reserved = 0;
6186 memcpy(data.data(), &header, headerSize);
6187 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
6198 if (data.size() < qsizetype(headerSize)) {
6199 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
6203 memcpy(&header, data.constData(), headerSize);
6205 const quint32 rhiId = pipelineCacheRhiId();
6206 if (header.rhiId != rhiId) {
6207 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
6208 rhiId, header.rhiId);
6211 const quint32 arch = quint32(
sizeof(
void*));
6212 if (header.arch != arch) {
6213 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
6217 if (header.driverVersion != physDevProperties.driverVersion) {
6218 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
6219 physDevProperties.driverVersion, header.driverVersion);
6222 if (header.vendorId != physDevProperties.vendorID) {
6223 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
6224 physDevProperties.vendorID, header.vendorId);
6227 if (header.deviceId != physDevProperties.deviceID) {
6228 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
6229 physDevProperties.deviceID, header.deviceId);
6232 if (header.uuidSize != VK_UUID_SIZE) {
6233 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
6234 quint32(VK_UUID_SIZE), header.uuidSize);
6238 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
6239 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
6242 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
6243 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
6247 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6248 if (quint64(data.size()) < quint64(dataOffset) + header.dataSize) {
6249 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
6253 if (pipelineCache) {
6254 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
6255 pipelineCache = VK_NULL_HANDLE;
6258 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
6259 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
6260 int(header.dataSize));
6262 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
6266QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
6267 int sampleCount, QRhiRenderBuffer::Flags flags,
6268 QRhiTexture::Format backingFormatHint)
6270 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
6274 const QSize &pixelSize,
int depth,
int arraySize,
6275 int sampleCount, QRhiTexture::Flags flags)
6277 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
6281 QRhiSampler::Filter mipmapMode,
6282 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
6284 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
6289 return new QVkShadingRateMap(
this);
6293 QRhiTextureRenderTarget::Flags flags)
6300 return new QVkGraphicsPipeline(
this);
6305 return new QVkComputePipeline(
this);
6310 return new QVkShaderResourceBindings(
this);
6316 Q_ASSERT(psD->pipeline);
6322 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
6326 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
6327 cmd.args.bindPipeline.pipeline = psD->pipeline;
6330 cbD->currentGraphicsPipeline = ps;
6331 cbD->currentComputePipeline =
nullptr;
6338 psD->lastActiveFrameSlot = currentFrameSlot;
6342 int dynamicOffsetCount,
6343 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
6353 srb = gfxPsD->m_shaderResourceBindings;
6355 srb = compPsD->m_shaderResourceBindings;
6359 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
6360 bool rewriteDescSet =
false;
6361 bool addWriteBarrier =
false;
6362 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
6363 VkPipelineStageFlags writeBarrierDstStageMask = 0;
6367 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
6368 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
6371 case QRhiShaderResourceBinding::UniformBuffer:
6374 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
6375 sanityCheckResourceOwnership(bufD);
6377 if (bufD->m_type == QRhiBuffer::Dynamic)
6380 bufD->lastActiveFrameSlot = currentFrameSlot;
6381 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6383 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
6389 if (bufD
->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
6390 rewriteDescSet =
true;
6391 bd.ubuf.id = bufD->m_id;
6396 case QRhiShaderResourceBinding::SampledTexture:
6397 case QRhiShaderResourceBinding::Texture:
6398 case QRhiShaderResourceBinding::Sampler:
6400 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
6401 if (bd.stex.d.size() != data->count()) {
6402 bd.stex.d.resize(data->count());
6403 rewriteDescSet =
true;
6405 for (
int elem = 0; elem < data->count(); ++elem) {
6411 Q_ASSERT(texD || samplerD);
6412 sanityCheckResourceOwnership(texD);
6413 sanityCheckResourceOwnership(samplerD);
6415 texD->lastActiveFrameSlot = currentFrameSlot;
6421 samplerD->lastActiveFrameSlot = currentFrameSlot;
6422 const quint64 texId = texD ? texD->m_id : 0;
6424 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6425 const uint samplerGen = samplerD ? samplerD
->generation : 0;
6426 if (texGen != bd.stex.d[elem].texGeneration
6427 || texId != bd.stex.d[elem].texId
6428 || samplerGen != bd.stex.d[elem].samplerGeneration
6429 || samplerId != bd.stex.d[elem].samplerId)
6431 rewriteDescSet =
true;
6432 bd.stex.d[elem].texId = texId;
6433 bd.stex.d[elem].texGeneration = texGen;
6434 bd.stex.d[elem].samplerId = samplerId;
6435 bd.stex.d[elem].samplerGeneration = samplerGen;
6440 case QRhiShaderResourceBinding::ImageLoad:
6441 case QRhiShaderResourceBinding::ImageStore:
6442 case QRhiShaderResourceBinding::ImageLoadStore:
6445 sanityCheckResourceOwnership(texD);
6446 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6447 texD->lastActiveFrameSlot = currentFrameSlot;
6449 if (b->type == QRhiShaderResourceBinding::ImageLoad)
6451 else if (b->type == QRhiShaderResourceBinding::ImageStore)
6456 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6457 const auto prevAccess = passResTracker
.textures().find(texD);
6458 if (prevAccess != passResTracker
.textures().end()) {
6462 addWriteBarrier =
true;
6463 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6464 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6472 if (texD
->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6473 rewriteDescSet =
true;
6474 bd.simage.id = texD->m_id;
6479 case QRhiShaderResourceBinding::BufferLoad:
6480 case QRhiShaderResourceBinding::BufferStore:
6481 case QRhiShaderResourceBinding::BufferLoadStore:
6484 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6485 sanityCheckResourceOwnership(bufD);
6487 if (bufD->m_type == QRhiBuffer::Dynamic)
6490 bufD->lastActiveFrameSlot = currentFrameSlot;
6492 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6494 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6499 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6500 const auto prevAccess = passResTracker
.buffers().find(bufD);
6501 if (prevAccess != passResTracker
.buffers().end()) {
6505 addWriteBarrier =
true;
6506 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6507 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6510 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6514 if (bufD
->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6515 rewriteDescSet =
true;
6516 bd.sbuf.id = bufD->m_id;
6527 if (addWriteBarrier) {
6529 VkMemoryBarrier barrier = {};
6530 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6531 barrier.pNext =
nullptr;
6532 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6533 barrier.srcAccessMask = barrier.dstAccessMask;
6534 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6541 cmd.args.memoryBarrier.dependencyFlags = 0;
6542 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6543 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6544 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6545 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6551 updateShaderResourceBindings(srb);
6555 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6556 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6558 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6561 QVarLengthArray<uint32_t, 4> dynOfs;
6566 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6567 uint32_t offset = 0;
6568 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6569 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6570 if (bindingOffsetPair.first == bindingNumber) {
6571 offset = bindingOffsetPair.second;
6575 dynOfs.append(offset);
6579 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6580 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6581 gfxPsD ? gfxPsD->layout : compPsD->layout,
6582 0, 1, &srbD->descSets[currentFrameSlot],
6583 uint32_t(dynOfs.size()),
6584 dynOfs.size() ? dynOfs.constData() :
nullptr);
6588 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6589 : VK_PIPELINE_BIND_POINT_COMPUTE;
6590 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6591 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6592 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6593 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6594 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6598 cbD->currentGraphicsSrb = srb;
6599 cbD->currentComputeSrb =
nullptr;
6601 cbD->currentGraphicsSrb =
nullptr;
6602 cbD->currentComputeSrb = srb;
6605 cbD->currentDescSetSlot = currentFrameSlot;
6608 srbD->lastActiveFrameSlot = currentFrameSlot;
6612 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6613 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6619 bool needsBindVBuf =
false;
6620 for (
int i = 0; i < bindingCount; ++i) {
6621 const int inputSlot = startBinding + i;
6623 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6624 bufD->lastActiveFrameSlot = currentFrameSlot;
6625 if (bufD->m_type == QRhiBuffer::Dynamic)
6628 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6629 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6630 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6632 needsBindVBuf =
true;
6633 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6634 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6638 if (needsBindVBuf) {
6639 QVarLengthArray<VkBuffer, 4> bufs;
6640 QVarLengthArray<VkDeviceSize, 4> ofs;
6641 for (
int i = 0; i < bindingCount; ++i) {
6643 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6644 bufs.append(bufD->buffers[slot]);
6645 ofs.append(bindings[i].second);
6652 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6653 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6657 cmd.args.bindVertexBuffer.startBinding = startBinding;
6658 cmd.args.bindVertexBuffer.count = bufs.size();
6659 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6660 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6661 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6662 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6668 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6669 ibufD->lastActiveFrameSlot = currentFrameSlot;
6670 if (ibufD->m_type == QRhiBuffer::Dynamic)
6673 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6674 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6675 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6676 : VK_INDEX_TYPE_UINT32;
6678 if (cbD->currentIndexBuffer != vkindexbuf
6679 || cbD->currentIndexOffset != indexOffset
6680 || cbD->currentIndexFormat != type)
6682 cbD->currentIndexBuffer = vkindexbuf;
6683 cbD->currentIndexOffset = indexOffset;
6684 cbD->currentIndexFormat = type;
6687 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6691 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6692 cmd.args.bindIndexBuffer.ofs = indexOffset;
6693 cmd.args.bindIndexBuffer.type = type;
6707 const QSize outputSize = cbD->currentTarget->pixelSize();
6708 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6709 float x = 0, y = 0, w = 0, h = 0;
6711 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6714 w = outputSize.width();
6715 h = outputSize.height();
6718 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6722 VkRect2D *s = &cmd.args.setScissor.scissor;
6723 s->offset.x = int32_t(x);
6724 s->offset.y = int32_t(y);
6725 s->extent.width = uint32_t(w);
6726 s->extent.height = uint32_t(h);
6729 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6730 cbD->commands.unget();
6740 const QSize outputSize = cbD->currentTarget->pixelSize();
6744 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6748 VkViewport *vp = &cmd.args.setViewport.viewport;
6753 vp->minDepth = viewport.minDepth();
6754 vp->maxDepth = viewport.maxDepth();
6757 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6758 cbD->commands.unget();
6763 cbD->currentViewport = viewport;
6764 if (cbD->currentGraphicsPipeline
6765 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6775 Q_ASSERT(!cbD->currentGraphicsPipeline
6777 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6778 const QSize outputSize = cbD->currentTarget->pixelSize();
6782 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6786 VkRect2D *s = &cmd.args.setScissor.scissor;
6789 s->extent.width = uint32_t(w);
6790 s->extent.height = uint32_t(h);
6793 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6794 cbD->commands.unget();
6808 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6809 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6813 cmd.args.setBlendConstants.c[0] = c.redF();
6814 cmd.args.setBlendConstants.c[1] = c.greenF();
6815 cmd.args.setBlendConstants.c[2] = c.blueF();
6816 cmd.args.setBlendConstants.c[3] = c.alphaF();
6826 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6830 cmd.args.setStencilRef.ref = refValue;
6839 VkPipelineLayout layout = VK_NULL_HANDLE;
6840 VkShaderStageFlags stages = 0;
6843 layout = psD->layout;
6844 stages = psD->pushConstantStages;
6848 layout = psD->layout;
6849 stages = psD->pushConstantStages;
6852 if (!layout || !stages) {
6853 qWarning(
"No pipeline with a push constant block is active; setPushConstants ignored");
6858 df->vkCmdPushConstants(cbD->activeSecondaryCbStack.last(), layout, stages, offset, size, data);
6860 const int dataIndex = cbD->pools.pushConstantData.size();
6861 cbD->pools.pushConstantData.append(
static_cast<
const char *>(data), size);
6864 cmd.args.setPushConstants.layout = layout;
6865 cmd.args.setPushConstants.stages = stages;
6866 cmd.args.setPushConstants.offset = offset;
6867 cmd.args.setPushConstants.size = size;
6868 cmd.args.setPushConstants.dataIndex = dataIndex;
6874#ifdef VK_KHR_fragment_shading_rate
6875 if (!vkCmdSetFragmentShadingRateKHR)
6878 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6879 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6880 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6882 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6883 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6884 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6886 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6887 if (cbD->passUsesSecondaryCb) {
6888 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6890 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6891 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6892 cmd.args.setShadingRate.w = size.width;
6893 cmd.args.setShadingRate.h = size.height;
6895 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6896 cbD->hasShadingRateSet =
true;
6899 Q_UNUSED(coarsePixelSize);
6904 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6910 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6914 cmd.args.draw.vertexCount = vertexCount;
6915 cmd.args.draw.instanceCount = instanceCount;
6916 cmd.args.draw.firstVertex = firstVertex;
6917 cmd.args.draw.firstInstance = firstInstance;
6922 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6928 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6929 firstIndex, vertexOffset, firstInstance);
6933 cmd.args.drawIndexed.indexCount = indexCount;
6934 cmd.args.drawIndexed.instanceCount = instanceCount;
6935 cmd.args.drawIndexed.firstIndex = firstIndex;
6936 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6937 cmd.args.drawIndexed.firstInstance = firstInstance;
6942 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6949 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6950 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6952 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6956 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6959 if (caps.drawIndirectMulti) {
6960 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6961 indirectBufVk, indirectBufferOffset,
6964 VkDeviceSize offset = indirectBufferOffset;
6965 for (quint32 i = 0; i < drawCount; ++i) {
6966 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6967 indirectBufVk, offset,
6973 if (caps.drawIndirectMulti) {
6976 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6977 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6978 cmd.args.drawIndirect.drawCount = drawCount;
6979 cmd.args.drawIndirect.stride = stride;
6981 VkDeviceSize offset = indirectBufferOffset;
6982 for (quint32 i = 0; i < drawCount; ++i) {
6985 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6986 cmd.args.drawIndirect.indirectBufferOffset = offset;
6987 cmd.args.drawIndirect.drawCount = 1;
6988 cmd.args.drawIndirect.stride = stride;
6996 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
7003 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
7004 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
7006 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
7010 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
7013 if (caps.drawIndirectMulti) {
7014 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
7015 indirectBufVk, indirectBufferOffset,
7018 VkDeviceSize offset = indirectBufferOffset;
7019 for (quint32 i = 0; i < drawCount; ++i) {
7020 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
7021 indirectBufVk, offset,
7027 if (caps.drawIndirectMulti) {
7030 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
7031 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
7032 cmd.args.drawIndexedIndirect.drawCount = drawCount;
7033 cmd.args.drawIndexedIndirect.stride = stride;
7035 VkDeviceSize offset = indirectBufferOffset;
7036 for (quint32 i = 0; i < drawCount; ++i) {
7039 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
7040 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
7041 cmd.args.drawIndexedIndirect.drawCount = 1;
7042 cmd.args.drawIndexedIndirect.stride = stride;
7051#ifdef VK_EXT_debug_utils
7052 if (!debugMarkers || !caps.debugUtils)
7055 VkDebugUtilsLabelEXT label = {};
7056 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
7058 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7059 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7060 label.pLabelName = name.constData();
7061 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
7063 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7064 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
7065 cmd.args.debugMarkerBegin.label = label;
7066 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
7067 cbD->pools.debugMarkerData.append(name);
7077#ifdef VK_EXT_debug_utils
7078 if (!debugMarkers || !caps.debugUtils)
7081 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7082 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7083 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
7085 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7086 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
7095#ifdef VK_EXT_debug_utils
7096 if (!debugMarkers || !caps.debugUtils)
7099 VkDebugUtilsLabelEXT label = {};
7100 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
7102 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
7103 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
7104 label.pLabelName = msg.constData();
7105 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
7107 QVkCommandBuffer::Command &cmd(cbD->commands.get());
7108 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
7109 cmd.args.debugMarkerInsert.label = label;
7110 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
7111 cbD->pools.debugMarkerData.append(msg);
7121 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
7126 Q_ASSERT(cbD->currentTarget);
7129 switch (cbD->currentTarget->resourceType()) {
7130 case QRhiResource::SwapChainRenderTarget:
7133 case QRhiResource::TextureRenderTarget:
7165 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
7166 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
7170 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
7171 cbD->activeSecondaryCbStack.removeLast();
7172 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
7174 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
7176 cbD->activeSecondaryCbStack.append(extCb);
7188 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
7189 cbD->activeSecondaryCbStack.removeLast();
7190 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
7191 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
7205 if (!debugMarkers || name.isEmpty())
7208 QByteArray decoratedName = name;
7210 decoratedName +=
'/';
7211 decoratedName += QByteArray::number(slot);
7213 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
7218#ifdef VK_EXT_debug_utils
7219 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
7222 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
7223 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
7224 nameInfo.objectType = type;
7225 nameInfo.objectHandle = object;
7226 QByteArray decoratedName = name;
7228 decoratedName +=
'/';
7229 decoratedName += QByteArray::number(slot);
7231 nameInfo.pObjectName = decoratedName.constData();
7232 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
7244 if (usage.testFlag(QRhiBuffer::VertexBuffer))
7245 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
7246 if (usage.testFlag(QRhiBuffer::IndexBuffer))
7247 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
7248 if (usage.testFlag(QRhiBuffer::UniformBuffer))
7249 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
7250 if (usage.testFlag(QRhiBuffer::StorageBuffer))
7251 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
7252 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
7253 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
7254 return VkBufferUsageFlagBits(u);
7260 case QRhiSampler::Nearest:
7261 return VK_FILTER_NEAREST;
7262 case QRhiSampler::Linear:
7263 return VK_FILTER_LINEAR;
7265 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
7272 case QRhiSampler::None:
7273 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7274 case QRhiSampler::Nearest:
7275 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7276 case QRhiSampler::Linear:
7277 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
7279 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
7286 case QRhiSampler::Repeat:
7287 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
7288 case QRhiSampler::ClampToEdge:
7289 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
7290 case QRhiSampler::Mirror:
7291 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
7293 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
7300 case QRhiShaderStage::Vertex:
7301 return VK_SHADER_STAGE_VERTEX_BIT;
7302 case QRhiShaderStage::TessellationControl:
7303 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7304 case QRhiShaderStage::TessellationEvaluation:
7305 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7306 case QRhiShaderStage::Fragment:
7307 return VK_SHADER_STAGE_FRAGMENT_BIT;
7308 case QRhiShaderStage::Compute:
7309 return VK_SHADER_STAGE_COMPUTE_BIT;
7310 case QRhiShaderStage::Geometry:
7311 return VK_SHADER_STAGE_GEOMETRY_BIT;
7313 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
7320 case QRhiVertexInputAttribute::Float4:
7321 return VK_FORMAT_R32G32B32A32_SFLOAT;
7322 case QRhiVertexInputAttribute::Float3:
7323 return VK_FORMAT_R32G32B32_SFLOAT;
7324 case QRhiVertexInputAttribute::Float2:
7325 return VK_FORMAT_R32G32_SFLOAT;
7326 case QRhiVertexInputAttribute::Float:
7327 return VK_FORMAT_R32_SFLOAT;
7328 case QRhiVertexInputAttribute::UNormByte4:
7329 return VK_FORMAT_R8G8B8A8_UNORM;
7330 case QRhiVertexInputAttribute::UNormByte2:
7331 return VK_FORMAT_R8G8_UNORM;
7332 case QRhiVertexInputAttribute::UNormByte:
7333 return VK_FORMAT_R8_UNORM;
7334 case QRhiVertexInputAttribute::UInt4:
7335 return VK_FORMAT_R32G32B32A32_UINT;
7336 case QRhiVertexInputAttribute::UInt3:
7337 return VK_FORMAT_R32G32B32_UINT;
7338 case QRhiVertexInputAttribute::UInt2:
7339 return VK_FORMAT_R32G32_UINT;
7340 case QRhiVertexInputAttribute::UInt:
7341 return VK_FORMAT_R32_UINT;
7342 case QRhiVertexInputAttribute::SInt4:
7343 return VK_FORMAT_R32G32B32A32_SINT;
7344 case QRhiVertexInputAttribute::SInt3:
7345 return VK_FORMAT_R32G32B32_SINT;
7346 case QRhiVertexInputAttribute::SInt2:
7347 return VK_FORMAT_R32G32_SINT;
7348 case QRhiVertexInputAttribute::SInt:
7349 return VK_FORMAT_R32_SINT;
7350 case QRhiVertexInputAttribute::Half4:
7351 return VK_FORMAT_R16G16B16A16_SFLOAT;
7352 case QRhiVertexInputAttribute::Half3:
7353 return VK_FORMAT_R16G16B16_SFLOAT;
7354 case QRhiVertexInputAttribute::Half2:
7355 return VK_FORMAT_R16G16_SFLOAT;
7356 case QRhiVertexInputAttribute::Half:
7357 return VK_FORMAT_R16_SFLOAT;
7358 case QRhiVertexInputAttribute::UShort4:
7359 return VK_FORMAT_R16G16B16A16_UINT;
7360 case QRhiVertexInputAttribute::UShort3:
7361 return VK_FORMAT_R16G16B16_UINT;
7362 case QRhiVertexInputAttribute::UShort2:
7363 return VK_FORMAT_R16G16_UINT;
7364 case QRhiVertexInputAttribute::UShort:
7365 return VK_FORMAT_R16_UINT;
7366 case QRhiVertexInputAttribute::SShort4:
7367 return VK_FORMAT_R16G16B16A16_SINT;
7368 case QRhiVertexInputAttribute::SShort3:
7369 return VK_FORMAT_R16G16B16_SINT;
7370 case QRhiVertexInputAttribute::SShort2:
7371 return VK_FORMAT_R16G16_SINT;
7372 case QRhiVertexInputAttribute::SShort:
7373 return VK_FORMAT_R16_SINT;
7375 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
7382 case QRhiGraphicsPipeline::Triangles:
7383 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
7384 case QRhiGraphicsPipeline::TriangleStrip:
7385 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
7386 case QRhiGraphicsPipeline::TriangleFan:
7387 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
7388 case QRhiGraphicsPipeline::Lines:
7389 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
7390 case QRhiGraphicsPipeline::LineStrip:
7391 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7392 case QRhiGraphicsPipeline::Points:
7393 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
7394 case QRhiGraphicsPipeline::Patches:
7395 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7397 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
7404 case QRhiGraphicsPipeline::None:
7405 return VK_CULL_MODE_NONE;
7406 case QRhiGraphicsPipeline::Front:
7407 return VK_CULL_MODE_FRONT_BIT;
7408 case QRhiGraphicsPipeline::Back:
7409 return VK_CULL_MODE_BACK_BIT;
7411 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
7418 case QRhiGraphicsPipeline::CCW:
7419 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
7420 case QRhiGraphicsPipeline::CW:
7421 return VK_FRONT_FACE_CLOCKWISE;
7423 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
7430 if (c.testFlag(QRhiGraphicsPipeline::R))
7431 f |= VK_COLOR_COMPONENT_R_BIT;
7432 if (c.testFlag(QRhiGraphicsPipeline::G))
7433 f |= VK_COLOR_COMPONENT_G_BIT;
7434 if (c.testFlag(QRhiGraphicsPipeline::B))
7435 f |= VK_COLOR_COMPONENT_B_BIT;
7436 if (c.testFlag(QRhiGraphicsPipeline::A))
7437 f |= VK_COLOR_COMPONENT_A_BIT;
7438 return VkColorComponentFlags(f);
7444 case QRhiGraphicsPipeline::Zero:
7445 return VK_BLEND_FACTOR_ZERO;
7446 case QRhiGraphicsPipeline::One:
7447 return VK_BLEND_FACTOR_ONE;
7448 case QRhiGraphicsPipeline::SrcColor:
7449 return VK_BLEND_FACTOR_SRC_COLOR;
7450 case QRhiGraphicsPipeline::OneMinusSrcColor:
7451 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
7452 case QRhiGraphicsPipeline::DstColor:
7453 return VK_BLEND_FACTOR_DST_COLOR;
7454 case QRhiGraphicsPipeline::OneMinusDstColor:
7455 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
7456 case QRhiGraphicsPipeline::SrcAlpha:
7457 return VK_BLEND_FACTOR_SRC_ALPHA;
7458 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7459 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
7460 case QRhiGraphicsPipeline::DstAlpha:
7461 return VK_BLEND_FACTOR_DST_ALPHA;
7462 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7463 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7464 case QRhiGraphicsPipeline::ConstantColor:
7465 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7466 case QRhiGraphicsPipeline::OneMinusConstantColor:
7467 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7468 case QRhiGraphicsPipeline::ConstantAlpha:
7469 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7470 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7471 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7472 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7473 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7474 case QRhiGraphicsPipeline::Src1Color:
7475 return VK_BLEND_FACTOR_SRC1_COLOR;
7476 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7477 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7478 case QRhiGraphicsPipeline::Src1Alpha:
7479 return VK_BLEND_FACTOR_SRC1_ALPHA;
7480 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7481 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7483 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7490 case QRhiGraphicsPipeline::Add:
7491 return VK_BLEND_OP_ADD;
7492 case QRhiGraphicsPipeline::Subtract:
7493 return VK_BLEND_OP_SUBTRACT;
7494 case QRhiGraphicsPipeline::ReverseSubtract:
7495 return VK_BLEND_OP_REVERSE_SUBTRACT;
7496 case QRhiGraphicsPipeline::Min:
7497 return VK_BLEND_OP_MIN;
7498 case QRhiGraphicsPipeline::Max:
7499 return VK_BLEND_OP_MAX;
7501 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7508 case QRhiGraphicsPipeline::Never:
7509 return VK_COMPARE_OP_NEVER;
7510 case QRhiGraphicsPipeline::Less:
7511 return VK_COMPARE_OP_LESS;
7512 case QRhiGraphicsPipeline::Equal:
7513 return VK_COMPARE_OP_EQUAL;
7514 case QRhiGraphicsPipeline::LessOrEqual:
7515 return VK_COMPARE_OP_LESS_OR_EQUAL;
7516 case QRhiGraphicsPipeline::Greater:
7517 return VK_COMPARE_OP_GREATER;
7518 case QRhiGraphicsPipeline::NotEqual:
7519 return VK_COMPARE_OP_NOT_EQUAL;
7520 case QRhiGraphicsPipeline::GreaterOrEqual:
7521 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7522 case QRhiGraphicsPipeline::Always:
7523 return VK_COMPARE_OP_ALWAYS;
7525 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7532 case QRhiGraphicsPipeline::StencilZero:
7533 return VK_STENCIL_OP_ZERO;
7534 case QRhiGraphicsPipeline::Keep:
7535 return VK_STENCIL_OP_KEEP;
7536 case QRhiGraphicsPipeline::Replace:
7537 return VK_STENCIL_OP_REPLACE;
7538 case QRhiGraphicsPipeline::IncrementAndClamp:
7539 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7540 case QRhiGraphicsPipeline::DecrementAndClamp:
7541 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7542 case QRhiGraphicsPipeline::Invert:
7543 return VK_STENCIL_OP_INVERT;
7544 case QRhiGraphicsPipeline::IncrementAndWrap:
7545 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7546 case QRhiGraphicsPipeline::DecrementAndWrap:
7547 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7549 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7556 case QRhiGraphicsPipeline::Fill:
7557 return VK_POLYGON_MODE_FILL;
7558 case QRhiGraphicsPipeline::Line:
7559 return VK_POLYGON_MODE_LINE;
7561 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7567 dst->failOp = toVkStencilOp(src.failOp);
7568 dst->passOp = toVkStencilOp(src.passOp);
7569 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7570 dst->compareOp = toVkCompareOp(src.compareOp);
7576 case QRhiShaderResourceBinding::UniformBuffer:
7577 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7578 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7580 case QRhiShaderResourceBinding::SampledTexture:
7581 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7583 case QRhiShaderResourceBinding::Texture:
7584 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7586 case QRhiShaderResourceBinding::Sampler:
7587 return VK_DESCRIPTOR_TYPE_SAMPLER;
7589 case QRhiShaderResourceBinding::ImageLoad:
7590 case QRhiShaderResourceBinding::ImageStore:
7591 case QRhiShaderResourceBinding::ImageLoadStore:
7592 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7594 case QRhiShaderResourceBinding::BufferLoad:
7595 case QRhiShaderResourceBinding::BufferStore:
7596 case QRhiShaderResourceBinding::BufferLoadStore:
7597 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7600 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7607 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7608 s |= VK_SHADER_STAGE_VERTEX_BIT;
7609 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7610 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7611 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7612 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7613 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7614 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7615 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7616 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7617 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7618 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7619 return VkShaderStageFlags(s);
7625 case QRhiSampler::Never:
7626 return VK_COMPARE_OP_NEVER;
7627 case QRhiSampler::Less:
7628 return VK_COMPARE_OP_LESS;
7629 case QRhiSampler::Equal:
7630 return VK_COMPARE_OP_EQUAL;
7631 case QRhiSampler::LessOrEqual:
7632 return VK_COMPARE_OP_LESS_OR_EQUAL;
7633 case QRhiSampler::Greater:
7634 return VK_COMPARE_OP_GREATER;
7635 case QRhiSampler::NotEqual:
7636 return VK_COMPARE_OP_NOT_EQUAL;
7637 case QRhiSampler::GreaterOrEqual:
7638 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7639 case QRhiSampler::Always:
7640 return VK_COMPARE_OP_ALWAYS;
7642 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7650 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7670 e.buffer.buffers[i] = buffers[i];
7672 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7675 buffers[i] = VK_NULL_HANDLE;
7677 stagingBuffers[i] = VK_NULL_HANDLE;
7679 pendingDynamicUpdates[i].clear();
7687 rhiD->releaseQueue.append(e);
7688 rhiD->unregisterResource(
this);
7697 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7698 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7702 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7704 VkBufferCreateInfo bufferInfo = {};
7705 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7706 bufferInfo.size = nonZeroSize;
7707 bufferInfo.usage = toVkBufferUsage(m_usage);
7709 VmaAllocationCreateInfo allocInfo = {};
7711 if (m_type == Dynamic) {
7716 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7719 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7721 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7722 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7726 VkResult err = VK_SUCCESS;
7728 buffers[i] = VK_NULL_HANDLE;
7730 usageState[i].access = usageState[i].stage = 0;
7731 if (i == 0 || m_type == Dynamic) {
7732 VmaAllocation allocation;
7733 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7734 if (err != VK_SUCCESS)
7737 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7738 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7739 m_type == Dynamic ? i : -1);
7743 if (err != VK_SUCCESS) {
7744 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7745 rhiD->printExtraErrorInfo(err);
7751 rhiD->registerResource(
this);
7757 if (m_type == Dynamic) {
7763 b.objects[i] = &buffers[i];
7768 return { { &buffers[0] }, 1 };
7778 Q_ASSERT(m_type == Dynamic);
7780 Q_ASSERT(rhiD->inFrame);
7781 const int slot = rhiD->currentFrameSlot;
7783 VmaAllocation a = toVmaAllocation(allocations[slot]);
7784 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7785 if (err != VK_SUCCESS) {
7786 qWarning(
"Failed to map buffer: %d", err);
7789 return static_cast<
char *>(p);
7795 const int slot = rhiD->currentFrameSlot;
7796 VmaAllocation a = toVmaAllocation(allocations[slot]);
7797 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7798 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7802 int sampleCount, Flags flags,
7803 QRhiTexture::Format backingFormatHint)
7816 if (!memory && !backingTexture)
7823 e.renderBuffer.memory = memory;
7824 e.renderBuffer.image = image;
7825 e.renderBuffer.imageView = imageView;
7827 memory = VK_NULL_HANDLE;
7828 image = VK_NULL_HANDLE;
7829 imageView = VK_NULL_HANDLE;
7839 rhiD->releaseQueue.append(e);
7840 rhiD->unregisterResource(
this);
7846 if (memory || backingTexture)
7849 if (m_pixelSize.isEmpty())
7853 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7856 case QRhiRenderBuffer::Color:
7864 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7872 vkformat = backingTexture->vkformat;
7875 case QRhiRenderBuffer::DepthStencil:
7876 vkformat = rhiD->optimalDepthStencilFormat();
7877 if (!rhiD->createTransientImage(vkformat,
7879 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7880 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7889 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7898 rhiD->registerResource(
this);
7904 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7905 return m_backingFormatHint;
7907 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7911 int arraySize,
int sampleCount, Flags flags)
7915 stagingBuffers[i] = VK_NULL_HANDLE;
7918 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7919 perLevelImageViews[i] = VK_NULL_HANDLE;
7936 e.texture.image = owns ? image : VK_NULL_HANDLE;
7937 e.texture.imageView = imageView;
7941 e.texture.stagingBuffers[i] = stagingBuffers[i];
7944 stagingBuffers[i] = VK_NULL_HANDLE;
7948 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7949 e.texture.extraImageViews[i] = perLevelImageViews[i];
7950 perLevelImageViews[i] = VK_NULL_HANDLE;
7953 image = VK_NULL_HANDLE;
7954 imageView = VK_NULL_HANDLE;
7959 rhiD->releaseQueue.append(e);
7960 rhiD->unregisterResource(
this);
7970 vkformat = toVkTextureFormat(m_format, m_flags);
7971 if (m_writeViewFormat.format != UnknownFormat)
7972 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7974 viewFormat = vkformat;
7975 if (m_readViewFormat.format != UnknownFormat)
7976 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7978 viewFormatForSampling = vkformat;
7980 VkFormatProperties props;
7981 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7982 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7983 if (!canSampleOptimal) {
7984 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7988 const bool isCube = m_flags.testFlag(CubeMap);
7989 const bool isArray = m_flags.testFlag(TextureArray);
7990 const bool is3D = m_flags.testFlag(ThreeDimensional);
7991 const bool is1D = m_flags.testFlag(OneDimensional);
7992 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7994 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7995 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7997 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7998 const int maxLevels = QRhi::MAX_MIP_LEVELS;
8000 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain",
mipLevelCount, maxLevels);
8003 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
8004 if (samples > VK_SAMPLE_COUNT_1_BIT) {
8006 qWarning(
"Cubemap texture cannot be multisample");
8010 qWarning(
"3D texture cannot be multisample");
8014 qWarning(
"Multisample texture cannot have mipmaps");
8018 if (isCube && is3D) {
8019 qWarning(
"Texture cannot be both cube and 3D");
8022 if (isArray && is3D) {
8023 qWarning(
"Texture cannot be both array and 3D");
8026 if (isCube && is1D) {
8027 qWarning(
"Texture cannot be both cube and 1D");
8031 qWarning(
"Texture cannot be both 1D and 3D");
8034 if (m_depth > 1 && !is3D) {
8035 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
8038 if (m_arraySize > 0 && !isArray) {
8039 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
8042 if (m_arraySize < 1 && isArray) {
8043 qWarning(
"Texture is an array but array size is %d", m_arraySize);
8047 usageState.layout = VK_IMAGE_LAYOUT_UNDEFINED;
8048 usageState.access = 0;
8049 usageState.stage = 0;
8051 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
8055 *adjustedSize = size;
8064 const auto aspectMask = aspectMaskForTextureFormat(m_format);
8065 const bool isCube = m_flags.testFlag(CubeMap);
8066 const bool isArray = m_flags.testFlag(TextureArray);
8067 const bool is3D = m_flags.testFlag(ThreeDimensional);
8068 const bool is1D = m_flags.testFlag(OneDimensional);
8070 VkImageViewCreateInfo viewInfo = {};
8071 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8072 viewInfo.image = image;
8073 viewInfo.viewType = isCube
8074 ? VK_IMAGE_VIEW_TYPE_CUBE
8075 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8076 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8077 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8078 viewInfo.format = viewFormatForSampling;
8079 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8080 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8081 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8082 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8083 viewInfo.subresourceRange.aspectMask = aspectMask;
8086 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8088 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
8089 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
8090 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
8092 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8095 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
8096 if (err != VK_SUCCESS) {
8097 qWarning(
"Failed to create image view: %d", err);
8110 if (!prepareCreate(&size))
8114 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
8115 const bool isDepth = isDepthTextureFormat(m_format);
8116 const bool isCube = m_flags.testFlag(CubeMap);
8117 const bool isArray = m_flags.testFlag(TextureArray);
8118 const bool is3D = m_flags.testFlag(ThreeDimensional);
8119 const bool is1D = m_flags.testFlag(OneDimensional);
8121 VkImageCreateInfo imageInfo = {};
8122 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
8123 imageInfo.flags = 0;
8125 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
8126 if (viewFormat != vkformat || viewFormatForSampling != vkformat)
8127 imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
8129 if (is3D && isRenderTarget) {
8135 if (!rhiD->caps.texture3DSliceAs2D)
8136 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
8137#ifdef VK_VERSION_1_1
8138 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
8140 imageInfo.flags |= 0x00000020;
8144 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
8145 imageInfo.format = vkformat;
8146 imageInfo.extent.width = uint32_t(size.width());
8147 imageInfo.extent.height = uint32_t(size.height());
8148 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
8150 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8151 imageInfo.samples = samples;
8152 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
8155 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
8157 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
8158 if (isRenderTarget) {
8160 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
8162 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
8164 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
8165 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8166 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
8167 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8168 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
8169 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
8170#ifdef VK_KHR_fragment_shading_rate
8171 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
8172 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
8175 VmaAllocationCreateInfo allocInfo = {};
8176 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
8178 VmaAllocation allocation;
8179 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
8180 if (err != VK_SUCCESS) {
8181 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
8182 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
8183 int(imageInfo.format),
8184 imageInfo.mipLevels,
8185 imageInfo.arrayLayers,
8186 int(imageInfo.samples),
8188 rhiD->printExtraErrorInfo(err);
8192 rhiD->setAllocationName(allocation, m_objectName);
8197 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
8200 rhiD->registerResource(
this);
8206 VkImage img = VkImage(src.object);
8210 if (!prepareCreate())
8218 usageState.layout = VkImageLayout(src.layout);
8222 rhiD->registerResource(
this);
8228 return {quint64(image), usageState.layout};
8233 usageState.layout = VkImageLayout(layout);
8239 if (perLevelImageViews[level] != VK_NULL_HANDLE)
8240 return perLevelImageViews[level];
8242 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
8243 const bool isCube = m_flags.testFlag(CubeMap);
8244 const bool isArray = m_flags.testFlag(TextureArray);
8245 const bool is3D = m_flags.testFlag(ThreeDimensional);
8246 const bool is1D = m_flags.testFlag(OneDimensional);
8248 VkImageViewCreateInfo viewInfo = {};
8249 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8250 viewInfo.image = image;
8251 viewInfo.viewType = isCube
8252 ? VK_IMAGE_VIEW_TYPE_CUBE
8253 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8254 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8255 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8256 viewInfo.format = viewFormat;
8257 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8258 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8259 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8260 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8261 viewInfo.subresourceRange.aspectMask = aspectMask;
8262 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
8263 viewInfo.subresourceRange.levelCount = 1;
8264 viewInfo.subresourceRange.baseArrayLayer = 0;
8265 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8267 VkImageView v = VK_NULL_HANDLE;
8269 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
8270 if (err != VK_SUCCESS) {
8271 qWarning(
"Failed to create image view: %d", err);
8272 return VK_NULL_HANDLE;
8275 perLevelImageViews[level] = v;
8280 AddressMode u, AddressMode v, AddressMode w)
8299 e.sampler.sampler = sampler;
8300 sampler = VK_NULL_HANDLE;
8304 rhiD->releaseQueue.append(e);
8305 rhiD->unregisterResource(
this);
8314 VkSamplerCreateInfo samplerInfo = {};
8315 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
8316 samplerInfo.magFilter = toVkFilter(m_magFilter);
8317 samplerInfo.minFilter = toVkFilter(m_minFilter);
8318 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
8319 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
8320 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
8321 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
8322 samplerInfo.maxAnisotropy = 1.0f;
8323 samplerInfo.compareEnable = m_compareOp != Never;
8324 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
8325 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
8328 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
8329 if (err != VK_SUCCESS) {
8330 qWarning(
"Failed to create sampler: %d", err);
8336 rhiD->registerResource(
this);
8343 serializedFormatData.reserve(64);
8357 rp = VK_NULL_HANDLE;
8365 e.renderPass.rp = rp;
8367 rp = VK_NULL_HANDLE;
8371 rhiD->releaseQueue.append(e);
8372 rhiD->unregisterResource(
this);
8378 return a.format == b.format
8379 && a.samples == b.samples
8380 && a.loadOp == b.loadOp
8381 && a.storeOp == b.storeOp
8382 && a.stencilLoadOp == b.stencilLoadOp
8383 && a.stencilStoreOp == b.stencilStoreOp
8384 && a.initialLayout == b.initialLayout
8385 && a.finalLayout == b.finalLayout;
8398 if (attDescs.size() != o->attDescs.size())
8400 if (colorRefs.size() != o->colorRefs.size())
8402 if (resolveRefs.size() != o->resolveRefs.size())
8408 if (multiViewCount != o->multiViewCount)
8413 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8414 const uint32_t attIdx = colorRefs[i].attachment;
8415 if (attIdx != o->colorRefs[i].attachment)
8417 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8422 const uint32_t attIdx = dsRef.attachment;
8423 if (attIdx != o->dsRef.attachment)
8425 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8429 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8430 const uint32_t attIdx = resolveRefs[i].attachment;
8431 if (attIdx != o->resolveRefs[i].attachment)
8433 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8438 const uint32_t attIdx = dsResolveRef.attachment;
8439 if (attIdx != o->dsResolveRef.attachment)
8441 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8446 const uint32_t attIdx = shadingRateRef.attachment;
8447 if (attIdx != o->shadingRateRef.attachment)
8449 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8460 serializedFormatData.clear();
8461 auto p =
std::back_inserter(serializedFormatData);
8463 *p++ = attDescs.size();
8464 *p++ = colorRefs.size();
8465 *p++ = resolveRefs.size();
8469 *p++ = multiViewCount;
8471 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8472 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8473 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8474 *p++ = used ? a->format : 0;
8475 *p++ = used ? a->samples : 0;
8476 *p++ = used ? a->loadOp : 0;
8477 *p++ = used ? a->storeOp : 0;
8478 *p++ = used ? a->stencilLoadOp : 0;
8479 *p++ = used ? a->stencilStoreOp : 0;
8480 *p++ = used ? a->initialLayout : 0;
8481 *p++ = used ? a->finalLayout : 0;
8484 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8485 const uint32_t attIdx = colorRefs[i].attachment;
8487 serializeAttachmentData(attIdx);
8491 const uint32_t attIdx = dsRef.attachment;
8493 serializeAttachmentData(attIdx);
8496 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8497 const uint32_t attIdx = resolveRefs[i].attachment;
8499 serializeAttachmentData(attIdx);
8503 const uint32_t attIdx = dsResolveRef.attachment;
8505 serializeAttachmentData(attIdx);
8509 const uint32_t attIdx = shadingRateRef.attachment;
8511 serializeAttachmentData(attIdx);
8520 rpD->attDescs = attDescs;
8521 rpD->colorRefs = colorRefs;
8522 rpD->resolveRefs = resolveRefs;
8523 rpD->subpassDeps = subpassDeps;
8527 rpD->multiViewCount = multiViewCount;
8529 rpD->dsResolveRef = dsResolveRef;
8530 rpD->shadingRateRef = shadingRateRef;
8532 VkRenderPassCreateInfo rpInfo;
8533 VkSubpassDescription subpassDesc;
8534 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8538 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8543#ifdef VK_KHR_create_renderpass2
8544 if (rhiD->caps.renderPass2KHR) {
8546 VkRenderPassCreateInfo2KHR rpInfo2;
8547 RenderPass2SetupHelper rp2Helper(rhiD);
8548 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8552 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8553 if (err != VK_SUCCESS) {
8554 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8561 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8562 if (err != VK_SUCCESS) {
8563 qWarning(
"Failed to create renderpass: %d", err);
8570 rhiD->registerResource(rpD);
8576 return serializedFormatData;
8581 nativeHandlesStruct.renderPass = rp;
8582 return &nativeHandlesStruct;
8608 texture =
QRHI_RES(QVkTexture, src);
8640 return d.sampleCount;
8644 const QRhiTextureRenderTargetDescription &desc,
8649 rtv[att] = VK_NULL_HANDLE;
8650 resrtv[att] = VK_NULL_HANDLE;
8668 e.textureRenderTarget.fb = d.fb;
8669 d.fb = VK_NULL_HANDLE;
8672 e.textureRenderTarget.rtv[att] = rtv[att];
8673 e.textureRenderTarget.resrtv[att] = resrtv[att];
8674 rtv[att] = VK_NULL_HANDLE;
8675 resrtv[att] = VK_NULL_HANDLE;
8678 e.textureRenderTarget.dsv = dsv;
8679 dsv = VK_NULL_HANDLE;
8680 e.textureRenderTarget.resdsv = resdsv;
8681 resdsv = VK_NULL_HANDLE;
8683 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8684 shadingRateMapView = VK_NULL_HANDLE;
8688 rhiD->releaseQueue.append(e);
8689 rhiD->unregisterResource(
this);
8699 if (!rhiD->createOffscreenRenderPass(rp,
8700 m_desc.cbeginColorAttachments(),
8701 m_desc.cendColorAttachments(),
8702 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8703 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8704 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8705 m_desc.depthStencilBuffer(),
8706 m_desc.depthTexture(),
8707 m_desc.depthResolveTexture(),
8708 m_desc.depthLayer(),
8709 m_desc.shadingRateMap()))
8717 rhiD->registerResource(rp);
8726 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8727 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8728 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8731 QVarLengthArray<VkImageView, 8> views;
8732 d.multiViewCount = 0;
8734 d.colorAttCount = 0;
8736 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8737 d.colorAttCount += 1;
8740 Q_ASSERT(texD || rbD);
8742 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8743 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8744 const bool isMultiView = it->multiViewCount() >= 2;
8745 if (isMultiView && d.multiViewCount == 0)
8746 d.multiViewCount = it->multiViewCount();
8747 VkImageViewCreateInfo viewInfo = {};
8748 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8749 viewInfo.image = texD->image;
8750 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8751 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8752 : VK_IMAGE_VIEW_TYPE_2D);
8753 viewInfo.format = texD->viewFormat;
8754 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8755 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8756 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8757 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8758 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8759 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8760 viewInfo.subresourceRange.levelCount = 1;
8761 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8762 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8763 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8764 if (err != VK_SUCCESS) {
8765 qWarning(
"Failed to create render target image view: %d", err);
8768 views.append(rtv[attIndex]);
8769 if (attIndex == 0) {
8770 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8771 d.sampleCount = texD->samples;
8776 if (attIndex == 0) {
8777 d.pixelSize = rbD->pixelSize();
8778 d.sampleCount = rbD->samples;
8784 if (hasDepthStencil) {
8785 if (m_desc.depthTexture()) {
8788 VkImageViewCreateInfo viewInfo = {};
8789 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8790 viewInfo.image = depthTexD->image;
8791 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8792 viewInfo.format = depthTexD->viewFormat;
8793 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8794 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8795 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8796 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8797 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8798 viewInfo.subresourceRange.levelCount = 1;
8799 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8800 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8801 viewInfo.subresourceRange.layerCount = 1;
8804 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8805 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8806 if (err != VK_SUCCESS) {
8807 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8811 if (d.colorAttCount == 0) {
8812 d.pixelSize = depthTexD->pixelSize();
8813 d.sampleCount = depthTexD->samples;
8817 views.append(depthRbD->imageView);
8818 if (d.colorAttCount == 0) {
8819 d.pixelSize = depthRbD->pixelSize();
8820 d.sampleCount = depthRbD->samples;
8828 d.resolveAttCount = 0;
8830 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8831 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8832 if (it->resolveTexture()) {
8834 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8835 d.resolveAttCount += 1;
8837 VkImageViewCreateInfo viewInfo = {};
8838 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8839 viewInfo.image = resTexD->image;
8840 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8841 : VK_IMAGE_VIEW_TYPE_2D;
8842 viewInfo.format = resTexD->viewFormat;
8843 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8844 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8845 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8846 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8847 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8848 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8849 viewInfo.subresourceRange.levelCount = 1;
8850 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8851 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8852 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8853 if (err != VK_SUCCESS) {
8854 qWarning(
"Failed to create render target resolve image view: %d", err);
8857 views.append(resrtv[attIndex]);
8861 if (m_desc.depthResolveTexture()) {
8863 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8865 VkImageViewCreateInfo viewInfo = {};
8866 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8867 viewInfo.image = resTexD->image;
8868 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8869 : VK_IMAGE_VIEW_TYPE_2D;
8870 viewInfo.format = resTexD->viewFormat;
8871 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8872 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8873 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8874 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8875 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8876 viewInfo.subresourceRange.baseMipLevel = 0;
8877 viewInfo.subresourceRange.levelCount = 1;
8878 viewInfo.subresourceRange.baseArrayLayer = 0;
8879 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8880 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8881 if (err != VK_SUCCESS) {
8882 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8885 views.append(resdsv);
8886 d.dsResolveAttCount = 1;
8888 d.dsResolveAttCount = 0;
8891 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8893 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8895 VkImageViewCreateInfo viewInfo = {};
8896 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8897 viewInfo.image = texD->image;
8898 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8899 : VK_IMAGE_VIEW_TYPE_2D;
8900 viewInfo.format = texD->viewFormat;
8901 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8902 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8903 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8904 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8905 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8906 viewInfo.subresourceRange.baseMipLevel = 0;
8907 viewInfo.subresourceRange.levelCount = 1;
8908 viewInfo.subresourceRange.baseArrayLayer = 0;
8909 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8910 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8911 if (err != VK_SUCCESS) {
8912 qWarning(
"Failed to create render target shading rate map view: %d", err);
8915 views.append(shadingRateMapView);
8916 d.shadingRateAttCount = 1;
8918 d.shadingRateAttCount = 0;
8921 if (!m_renderPassDesc)
8922 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8924 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8925 Q_ASSERT(d.rp && d.rp->rp);
8927 VkFramebufferCreateInfo fbInfo = {};
8928 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8929 fbInfo.renderPass = d.rp->rp;
8930 fbInfo.attachmentCount = uint32_t(views.count());
8931 fbInfo.pAttachments = views.constData();
8932 fbInfo.width = uint32_t(d.pixelSize.width());
8933 fbInfo.height = uint32_t(d.pixelSize.height());
8936 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8937 if (err != VK_SUCCESS) {
8938 qWarning(
"Failed to create framebuffer: %d", err);
8942 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8945 rhiD->registerResource(
this);
8951 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8964 return d.sampleCount;
8982 sortedBindings.clear();
8983 sortedDynamicOffsetBindingNumbers.clear();
8989 e.shaderResourceBindings.poolIndex =
poolIndex;
8990 e.shaderResourceBindings.layout = layout;
8993 layout = VK_NULL_HANDLE;
8994 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8995 descSets[i] = VK_NULL_HANDLE;
8999 rhiD->releaseQueue.append(e);
9000 rhiD->unregisterResource(
this);
9010 if (!rhiD->sanityCheckShaderResourceBindings(
this))
9013 rhiD->updateLayoutDesc(
this);
9015 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9016 descSets[i] = VK_NULL_HANDLE;
9018 sortedBindings.clear();
9019 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
9020 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
9022 sortedDynamicOffsetBindingNumbers.clear();
9023 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9024 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9025 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
9026 if (b->u.ubuf.hasDynamicOffset)
9027 sortedDynamicOffsetBindingNumbers.append(b->binding);
9031 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
9032 vkbindings.reserve(sortedBindings.size());
9033 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9034 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9035 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
9036 vkbinding.binding = uint32_t(b->binding);
9037 vkbinding.descriptorType = toVkDescriptorType(b);
9038 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
9039 vkbinding.descriptorCount = b->stex.count();
9041 vkbinding.descriptorCount = 1;
9042 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
9045 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
9046 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
9047 layoutInfo.bindingCount = uint32_t(vkbindings.size());
9048 layoutInfo.pBindings = vkbindings.constData();
9050 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
9051 if (err != VK_SUCCESS) {
9052 qWarning(
"Failed to create descriptor set layout: %d", err);
9055 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
9057 VkDescriptorSetAllocateInfo allocInfo = {};
9058 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
9061 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
9062 layouts[i] = layout;
9063 allocInfo.pSetLayouts = layouts;
9064 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
9068 boundResourceData[i].resize(sortedBindings.size());
9069 for (BoundResourceData &bd : boundResourceData[i])
9074 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
9078 rhiD->registerResource(
this);
9084 sortedBindings.clear();
9085 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
9086 if (!flags.testFlag(BindingsAreSorted))
9087 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
9089 sortedDynamicOffsetBindingNumbers.clear();
9090 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
9091 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
9092 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
9093 if (b->u.ubuf.hasDynamicOffset)
9094 sortedDynamicOffsetBindingNumbers.append(b->binding);
9108 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
9109 for (BoundResourceData &bd : boundResourceData[i])
9128 if (!pipeline && !layout)
9135 e.pipelineState.pipeline = pipeline;
9136 e.pipelineState.layout = layout;
9138 pipeline = VK_NULL_HANDLE;
9139 layout = VK_NULL_HANDLE;
9143 rhiD->releaseQueue.append(e);
9144 rhiD->unregisterResource(
this);
9150 if (pipeline || layout)
9154 rhiD->pipelineCreationStart();
9155 if (!rhiD->sanityCheckGraphicsPipeline(
this))
9158 if (!rhiD->ensurePipelineCache())
9161 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9162 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9163 pipelineLayoutInfo.setLayoutCount = 1;
9165 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9166 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9167 VkPushConstantRange pushConstantRange = {};
9168 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
9169 for (
const QShaderDescription::PushConstantBlock &block : shaderStage.shader().description().pushConstantBlocks()) {
9170 pushConstantRange.stageFlags |= toVkShaderStage(shaderStage.type());
9171 pushConstantRange.size = qMax(pushConstantRange.size, uint32_t((block.size + 3) & ~3));
9174 if (pushConstantRange.size) {
9175 pipelineLayoutInfo.pushConstantRangeCount = 1;
9176 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
9178 pushConstantStages = pushConstantRange.stageFlags;
9179 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9180 if (err != VK_SUCCESS) {
9181 qWarning(
"Failed to create pipeline layout: %d", err);
9184 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9185 rhiD->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9186 layout = VK_NULL_HANDLE;
9189 VkGraphicsPipelineCreateInfo pipelineInfo = {};
9190 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
9192 QVarLengthArray<VkShaderModule, 4> shaders;
9193 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
9194 for (VkShaderModule shader : shaders)
9195 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9197 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
9198 QVarLengthArray<QByteArray, 4> entryPointNames;
9199 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
9200 const QShader bakedShader = shaderStage.shader();
9201 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
9202 if (spirv.shader().isEmpty()) {
9203 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9206 VkShaderModule shader = rhiD->createShader(spirv.shader());
9208 shaders.append(shader);
9209 VkPipelineShaderStageCreateInfo shaderInfo = {};
9210 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9211 shaderInfo.stage = toVkShaderStage(shaderStage.type());
9212 shaderInfo.module = shader;
9213 entryPointNames.append(spirv.entryPoint());
9214 shaderInfo.pName =
nullptr;
9215 shaderStageCreateInfos.append(shaderInfo);
9220 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
9221 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
9223 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
9224 pipelineInfo.pStages = shaderStageCreateInfos.constData();
9226 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
9227#ifdef VK_EXT_vertex_attribute_divisor
9228 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
9230 int bindingIndex = 0;
9231 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
9232 it != itEnd; ++it, ++bindingIndex)
9234 VkVertexInputBindingDescription bindingInfo = {
9235 uint32_t(bindingIndex),
9237 it->classification() == QRhiVertexInputBinding::PerVertex
9238 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
9240 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
9241#ifdef VK_EXT_vertex_attribute_divisor
9242 if (rhiD->caps.vertexAttribDivisor) {
9243 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
9247 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
9248 "VK_EXT_vertex_attribute_divisor on the device and "
9249 "VK_KHR_get_physical_device_properties2 on the instance");
9252 vertexBindings.append(bindingInfo);
9254 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
9255 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
9258 VkVertexInputAttributeDescription attributeInfo = {
9259 uint32_t(it->location()),
9260 uint32_t(it->binding()),
9261 toVkAttributeFormat(it->format()),
9264 vertexAttributes.append(attributeInfo);
9266 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
9267 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
9268 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
9269 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
9270 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
9271 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
9272#ifdef VK_EXT_vertex_attribute_divisor
9273 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
9274 if (!nonOneStepRates.isEmpty()) {
9275 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
9276 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
9277 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
9278 vertexInputInfo.pNext = &divisorInfo;
9281 pipelineInfo.pVertexInputState = &vertexInputInfo;
9283 QVarLengthArray<VkDynamicState, 8> dynEnable;
9284 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
9285 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
9286 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
9287 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
9288 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
9289 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
9290#ifdef VK_KHR_fragment_shading_rate
9291 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
9292 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
9295 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
9296 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
9297 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
9298 dynamicInfo.pDynamicStates = dynEnable.constData();
9299 pipelineInfo.pDynamicState = &dynamicInfo;
9301 VkPipelineViewportStateCreateInfo viewportInfo = {};
9302 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
9303 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
9304 pipelineInfo.pViewportState = &viewportInfo;
9306 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
9307 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
9308 inputAsmInfo.topology = toVkTopology(m_topology);
9309 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
9310 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
9312 VkPipelineTessellationStateCreateInfo tessInfo = {};
9313#ifdef VK_VERSION_1_1
9314 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
9316 if (m_topology == Patches) {
9317 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
9318 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
9325#ifdef VK_VERSION_1_1
9326 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
9327 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
9328 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
9329 tessInfo.pNext = &originInfo;
9331 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
9334 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
9337 pipelineInfo.pTessellationState = &tessInfo;
9340 VkPipelineRasterizationStateCreateInfo rastInfo = {};
9341 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
9342 if (m_depthClamp && rhiD->caps.depthClamp)
9343 rastInfo.depthClampEnable = m_depthClamp;
9344 rastInfo.cullMode = toVkCullMode(m_cullMode);
9345 rastInfo.frontFace = toVkFrontFace(m_frontFace);
9346 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
9347 rastInfo.depthBiasEnable =
true;
9348 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
9349 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
9351 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
9352 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
9353 pipelineInfo.pRasterizationState = &rastInfo;
9355 VkPipelineMultisampleStateCreateInfo msInfo = {};
9356 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
9357 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
9358 pipelineInfo.pMultisampleState = &msInfo;
9360 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
9361 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
9362 dsInfo.depthTestEnable = m_depthTest;
9363 dsInfo.depthWriteEnable = m_depthWrite;
9364 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
9365 dsInfo.stencilTestEnable = m_stencilTest;
9366 if (m_stencilTest) {
9367 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
9368 dsInfo.front.compareMask = m_stencilReadMask;
9369 dsInfo.front.writeMask = m_stencilWriteMask;
9370 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
9371 dsInfo.back.compareMask = m_stencilReadMask;
9372 dsInfo.back.writeMask = m_stencilWriteMask;
9374 pipelineInfo.pDepthStencilState = &dsInfo;
9376 VkPipelineColorBlendStateCreateInfo blendInfo = {};
9377 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
9378 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
9379 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
9380 VkPipelineColorBlendAttachmentState blend = {};
9381 blend.blendEnable = b.enable;
9382 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
9383 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
9384 blend.colorBlendOp = toVkBlendOp(b.opColor);
9385 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
9386 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
9387 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
9388 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
9389 vktargetBlends.append(blend);
9391 if (vktargetBlends.isEmpty()) {
9392 VkPipelineColorBlendAttachmentState blend = {};
9393 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
9394 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
9395 vktargetBlends.append(blend);
9397 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
9398 blendInfo.pAttachments = vktargetBlends.constData();
9399 pipelineInfo.pColorBlendState = &blendInfo;
9401 pipelineInfo.layout = layout;
9403 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
9404 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
9406 err = rhiD->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9408 if (err != VK_SUCCESS) {
9409 qWarning(
"Failed to create graphics pipeline: %d", err);
9412 pipelineLayoutCleanup.dismiss();
9414 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9416 rhiD->pipelineCreationEnd();
9417 lastActiveFrameSlot = -1;
9419 rhiD->registerResource(
this);
9423QVkComputePipeline::QVkComputePipeline(QRhiImplementation *rhi)
9424 : QRhiComputePipeline(rhi)
9428QVkComputePipeline::~QVkComputePipeline()
9433void QVkComputePipeline::destroy()
9435 if (!pipeline && !layout)
9438 QRhiVulkan::DeferredReleaseEntry e;
9439 e.type = QRhiVulkan::DeferredReleaseEntry::Pipeline;
9440 e.lastActiveFrameSlot = lastActiveFrameSlot;
9442 e.pipelineState.pipeline = pipeline;
9443 e.pipelineState.layout = layout;
9445 pipeline = VK_NULL_HANDLE;
9446 layout = VK_NULL_HANDLE;
9450 rhiD->releaseQueue.append(e);
9451 rhiD->unregisterResource(
this);
9455bool QVkComputePipeline::create()
9457 if (pipeline || layout)
9461 rhiD->pipelineCreationStart();
9462 if (!rhiD->ensurePipelineCache())
9465 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9466 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9467 pipelineLayoutInfo.setLayoutCount = 1;
9468 QVkShaderResourceBindings *srbD =
QRHI_RES(QVkShaderResourceBindings, m_shaderResourceBindings);
9469 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9470 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9471 VkPushConstantRange pushConstantRange = {};
9472 for (
const QShaderDescription::PushConstantBlock &block : m_shaderStage.shader().description().pushConstantBlocks()) {
9473 pushConstantRange.stageFlags |= VK_SHADER_STAGE_COMPUTE_BIT;
9474 pushConstantRange.size = qMax(pushConstantRange.size, uint32_t((block.size + 3) & ~3));
9476 if (pushConstantRange.size) {
9477 pipelineLayoutInfo.pushConstantRangeCount = 1;
9478 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
9480 pushConstantStages = pushConstantRange.stageFlags;
9481 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9482 if (err != VK_SUCCESS) {
9483 qWarning(
"Failed to create pipeline layout: %d", err);
9486 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9487 rhiD->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9488 layout = VK_NULL_HANDLE;
9491 VkComputePipelineCreateInfo pipelineInfo = {};
9492 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9493 pipelineInfo.layout = layout;
9495 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9496 qWarning(
"Compute pipeline requires a compute shader stage");
9499 const QShader bakedShader = m_shaderStage.shader();
9500 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9501 if (spirv.shader().isEmpty()) {
9502 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9505 if (bakedShader.stage() != QShader::ComputeStage) {
9506 qWarning() << bakedShader <<
"is not a compute shader";
9509 VkShaderModule shader = rhiD->createShader(spirv.shader());
9512 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9513 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9515 VkPipelineShaderStageCreateInfo shaderInfo = {};
9516 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9517 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9518 shaderInfo.module = shader;
9519 const QByteArray entryPointName = spirv.entryPoint();
9520 shaderInfo.pName = entryPointName.constData();
9521 pipelineInfo.stage = shaderInfo;
9523 err = rhiD->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9524 if (err != VK_SUCCESS) {
9525 qWarning(
"Failed to create graphics pipeline: %d", err);
9528 pipelineLayoutCleanup.dismiss();
9530 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9532 rhiD->pipelineCreationEnd();
9533 lastActiveFrameSlot = -1;
9535 rhiD->registerResource(
this);
9539QVkCommandBuffer::QVkCommandBuffer(QRhiImplementation *rhi)
9540 : QRhiCommandBuffer(rhi)
9545QVkCommandBuffer::~QVkCommandBuffer()
9550void QVkCommandBuffer::destroy()
9555const QRhiNativeHandles *QVkCommandBuffer::nativeHandles()
9563 if (recordingPass == QVkCommandBuffer::NoPass) {
9564 nativeHandlesStruct.commandBuffer = cb;
9566 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9567 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9569 nativeHandlesStruct.commandBuffer = cb;
9572 return &nativeHandlesStruct;
9575QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi)
9576 : QRhiSwapChain(rhi),
9577 rtWrapper(rhi,
this),
9578 rtWrapperRight(rhi,
this),
9583QVkSwapChain::~QVkSwapChain()
9588void QVkSwapChain::destroy()
9590 if (sc == VK_NULL_HANDLE)
9595 rhiD->swapchains.remove(
this);
9596 rhiD->releaseSwapChainResources(
this);
9599 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) {
9600 QVkSwapChain::FrameResources &frame(frameRes[i]);
9601 frame.cmdBuf = VK_NULL_HANDLE;
9602 frame.timestampQueryIndex = -1;
9605 surface = lastConnectedSurface = VK_NULL_HANDLE;
9608 rhiD->unregisterResource(
this);
9611QRhiCommandBuffer *QVkSwapChain::currentFrameCommandBuffer()
9616QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget()
9621QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
9623 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9626QSize QVkSwapChain::surfacePixelSize()
9628 if (!ensureSurface())
9633 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9635 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9636 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9637 if (bufferSize.width == uint32_t(-1)) {
9638 Q_ASSERT(bufferSize.height == uint32_t(-1));
9639 return m_window->size() * m_window->devicePixelRatio();
9641 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9644static inline bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f,
const VkSurfaceFormatKHR &s)
9647 case QRhiSwapChain::HDRExtendedSrgbLinear:
9648 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9649 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9650 case QRhiSwapChain::HDR10:
9651 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9652 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9653 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9654 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9655 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9662bool QVkSwapChain::isFormatSupported(Format f)
9668 qWarning(
"Attempted to call isFormatSupported() without a window set");
9673 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9676 uint32_t formatCount = 0;
9677 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9678 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9680 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9681 for (uint32_t i = 0; i < formatCount; ++i) {
9682 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9690QRhiSwapChainHdrInfo QVkSwapChain::hdrInfo()
9692 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
9694 QRHI_RES_RHI(QRhiVulkan);
9696 if (m_window && rhiD->adapterLuidValid)
9697 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9702QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor()
9706 if (!ensureSurface())
9710 QVkRenderPassDescriptor *rp =
new QVkRenderPassDescriptor(m_rhi);
9711 if (!rhiD->createDefaultRenderPass(rp,
9712 m_depthStencil !=
nullptr,
9722 rp->updateSerializedFormat();
9723 rhiD->registerResource(rp);
9727static inline bool isSrgbFormat(VkFormat format)
9730 case VK_FORMAT_R8_SRGB:
9731 case VK_FORMAT_R8G8_SRGB:
9732 case VK_FORMAT_R8G8B8_SRGB:
9733 case VK_FORMAT_B8G8R8_SRGB:
9734 case VK_FORMAT_R8G8B8A8_SRGB:
9735 case VK_FORMAT_B8G8R8A8_SRGB:
9736 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9743bool QVkSwapChain::ensureSurface()
9751 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9753 qWarning(
"Failed to get surface for window");
9756 if (surface == surf)
9762 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9763 qWarning(
"Presenting not supported on this window");
9767 quint32 formatCount = 0;
9768 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9769 QList<VkSurfaceFormatKHR> formats(formatCount);
9770 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9774 colorFormat = formats.constFirst().format;
9775 colorSpace = formats.constFirst().colorSpace;
9778 const bool srgbRequested = m_flags.testFlag(sRGB);
9779 bool foundBestFormat =
false;
9780 if (m_format == SDR) {
9781 for (
int i = 0; i <
int(formatCount); ++i) {
9783 if (srgbRequested) {
9784 ok = defaultSrgbColorFormat == formats[i].format;
9786 ok = defaultColorFormat == formats[i].format;
9789 foundBestFormat =
true;
9790 colorFormat = formats[i].format;
9791 colorSpace = formats[i].colorSpace;
9798 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9799 for (
int i = 0; i <
int(formatCount); ++i) {
9801 if (m_format != SDR) {
9802 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9803 }
else if (srgbRequested) {
9804 ok = isSrgbFormat(formats[i].format);
9807 colorFormat = formats[i].format;
9808 colorSpace = formats[i].colorSpace;
9815 if (m_format != SDR) {
9816 VkSurfaceFormatKHR format{};
9817 format.format = colorFormat;
9818 format.colorSpace = colorSpace;
9819 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9820 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9824 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9825 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9830#if QT_CONFIG(wayland)
9835 const bool hasPassThrough =
9836 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9837 return fmt.format == colorFormat
9838 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9840 if (hasPassThrough) {
9841 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9845 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9847 quint32 presModeCount = 0;
9848 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9849 supportedPresentationModes.resize(presModeCount);
9850 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9851 supportedPresentationModes.data());
9856bool QVkSwapChain::createOrResize()
9859 const bool needsRegistration = !window || window != m_window;
9866 if (window && window != m_window)
9870 m_currentPixelSize = surfacePixelSize();
9871 pixelSize = m_currentPixelSize;
9873 if (!rhiD->recreateSwapChain(
this)) {
9874 qWarning(
"Failed to create new swapchain");
9878 if (needsRegistration || !rhiD->swapchains.contains(
this))
9879 rhiD->swapchains.insert(
this);
9881 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9882 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9883 m_depthStencil->sampleCount(), m_sampleCount);
9885 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9886 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9887 m_depthStencil->setPixelSize(pixelSize);
9888 if (!m_depthStencil->create())
9889 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9890 pixelSize.width(), pixelSize.height());
9892 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9893 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9894 pixelSize.width(), pixelSize.height());
9898 if (!m_renderPassDesc)
9899 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9901 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9902 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9903 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9905 rtWrapper.d.pixelSize = pixelSize;
9906 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9907 rtWrapper.d.sampleCount = samples;
9908 rtWrapper.d.colorAttCount = 1;
9909 if (m_depthStencil) {
9910 rtWrapper.d.dsAttCount = 1;
9911 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9913 rtWrapper.d.dsAttCount = 0;
9916 rtWrapper.d.dsResolveAttCount = 0;
9917 if (samples > VK_SAMPLE_COUNT_1_BIT)
9918 rtWrapper.d.resolveAttCount = 1;
9920 rtWrapper.d.resolveAttCount = 0;
9922 if (shadingRateMapView)
9923 rtWrapper.d.shadingRateAttCount = 1;
9925 rtWrapper.d.shadingRateAttCount = 0;
9927 for (
int i = 0; i < bufferCount; ++i) {
9928 QVkSwapChain::ImageResources &image(imageRes[i]);
9930 QVarLengthArray<VkImageView, 4> views;
9931 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9933 views.append(ds->imageView);
9934 if (samples > VK_SAMPLE_COUNT_1_BIT)
9935 views.append(image.imageView);
9936 if (shadingRateMapView)
9937 views.append(shadingRateMapView);
9939 VkFramebufferCreateInfo fbInfo = {};
9940 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9941 fbInfo.renderPass = rtWrapper.d.rp->rp;
9942 fbInfo.attachmentCount = uint32_t(views.count());
9943 fbInfo.pAttachments = views.constData();
9944 fbInfo.width = uint32_t(pixelSize.width());
9945 fbInfo.height = uint32_t(pixelSize.height());
9948 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9949 if (err != VK_SUCCESS) {
9950 qWarning(
"Failed to create framebuffer: %d", err);
9956 rtWrapperRight.setRenderPassDescriptor(
9958 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9959 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9961 rtWrapperRight.d.pixelSize = pixelSize;
9962 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9963 rtWrapperRight.d.sampleCount = samples;
9964 rtWrapperRight.d.colorAttCount = 1;
9965 if (m_depthStencil) {
9966 rtWrapperRight.d.dsAttCount = 1;
9967 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9969 rtWrapperRight.d.dsAttCount = 0;
9972 rtWrapperRight.d.dsResolveAttCount = 0;
9973 if (samples > VK_SAMPLE_COUNT_1_BIT)
9974 rtWrapperRight.d.resolveAttCount = 1;
9976 rtWrapperRight.d.resolveAttCount = 0;
9978 for (
int i = 0; i < bufferCount; ++i) {
9979 QVkSwapChain::ImageResources &image(imageRes[i + bufferCount]);
9981 QVarLengthArray<VkImageView, 4> views;
9982 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9984 views.append(ds->imageView);
9985 if (samples > VK_SAMPLE_COUNT_1_BIT)
9986 views.append(image.imageView);
9987 if (shadingRateMapView)
9988 views.append(shadingRateMapView);
9990 VkFramebufferCreateInfo fbInfo = {};
9991 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9992 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9993 fbInfo.attachmentCount = uint32_t(views.count());
9994 fbInfo.pAttachments = views.constData();
9995 fbInfo.width = uint32_t(pixelSize.width());
9996 fbInfo.height = uint32_t(pixelSize.height());
9999 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
10000 if (err != VK_SUCCESS) {
10001 qWarning(
"Failed to create framebuffer: %d", err);
10009 if (needsRegistration)
10010 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)