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>
57
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
88
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
198
199
200
201
202
205
206
207
208
211
212
213
214
215
219
220
221
222
223
224
225
226
227
228
231
232
233
234
237
238
239
240
241
244
245
246
247
250
251
252
253
256
257
258
259
260
261
262
263
264
265
268
269
270
271
272
275
276
277
278
279
282
283
284
285
286
290
291
292
293
294
295
296
297
298
299
300
301
302
303
306
307
308
309
313
314
315
316
317
318
319
320
323
324
325
326
330
331
332
333
334
335
336
339
340
341
342
343
344
347
348
349
350
351
352
355
356
357
358
359
360
363
364
365
366
367
368
371
372
373
374
375
376
379
380
381
382
383
384
387inline Int aligned(Int v, Int byteAlign)
389 return (v + byteAlign - 1) & ~(byteAlign - 1);
394static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
396 return globalVulkanInstance->getInstanceProcAddr(pName);
399static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
401 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
406 return reinterpret_cast<VmaAllocation>(a);
411 return reinterpret_cast<VmaAllocator>(a);
415
416
417
418
419
420
421QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
424 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"),
426 QByteArrayLiteral(
"VK_EXT_swapchain_colorspace")
431
432
433
434
435QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
438 QByteArrayLiteral(
"VK_KHR_swapchain"),
439 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
440 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
441 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
442 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
455 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
456 inst = QVulkanDefaultInstance::instance();
460 requestedDeviceExtensions = params->deviceExtensions;
463 physDev = importParams->physDev;
464 dev = importParams->dev;
465 if (dev && physDev) {
467 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
468 gfxQueueIdx = importParams->gfxQueueIdx;
469 gfxQueueFlags = importParams->gfxQueueFlags;
471 if (importParams->vmemAllocator) {
480 QVulkanInstance::DebugMessageTypeFlags type,
481 const void *callbackData)
485#ifdef VK_EXT_debug_utils
486 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
490 if (strstr(d->pMessage,
"Mapping an image with layout")
491 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
502 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
505 Q_UNUSED(callbackData);
513 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
514 return QRhiDriverInfo::UnknownDevice;
515 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
516 return QRhiDriverInfo::IntegratedDevice;
517 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
518 return QRhiDriverInfo::DiscreteDevice;
519 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
520 return QRhiDriverInfo::VirtualDevice;
521 case VK_PHYSICAL_DEVICE_TYPE_CPU:
522 return QRhiDriverInfo::CpuDevice;
524 return QRhiDriverInfo::UnknownDevice;
528static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
530 info->deviceName = QByteArray(physDevProperties.deviceName);
531 info->deviceId = physDevProperties.deviceID;
532 info->vendorId = physDevProperties.vendorID;
533 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
539 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
541 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
547 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
553 if (!inst->isValid()) {
554 qWarning(
"Vulkan instance is not valid");
559 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
561 globalVulkanInstance = inst;
562 f = inst->functions();
563 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
564 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
565 const QByteArrayList extensions = inst->extensions();
566 for (
const char *ext : extensions)
567 qCDebug(QRHI_LOG_INFO,
" %s", ext);
571 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
573 QList<VkQueueFamilyProperties> queueFamilyProps;
574 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
575 uint32_t queueCount = 0;
576 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
577 queueFamilyProps.resize(
int(queueCount));
578 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
583 uint32_t physDevCount = 0;
584 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
586 qWarning(
"No physical devices");
589 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
590 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
591 if (err != VK_SUCCESS || !physDevCount) {
592 qWarning(
"Failed to enumerate physical devices: %d", err);
596 int physDevIndex = -1;
597 int requestedPhysDevIndex = -1;
598 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
599 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
601 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
602 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
603 for (
int i = 0; i <
int(physDevCount); ++i) {
604 if (physDevs[i] == requestedPhysDev) {
605 requestedPhysDevIndex = i;
611 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
612 for (
int i = 0; i <
int(physDevCount); ++i) {
613 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
614 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
615 requestedPhysDevIndex = i;
621 for (
int i = 0; i <
int(physDevCount); ++i) {
622 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
623 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
625 physDevProperties.deviceName,
626 VK_VERSION_MAJOR(physDevProperties.driverVersion),
627 VK_VERSION_MINOR(physDevProperties.driverVersion),
628 VK_VERSION_PATCH(physDevProperties.driverVersion),
629 VK_VERSION_MAJOR(physDevProperties.apiVersion),
630 VK_VERSION_MINOR(physDevProperties.apiVersion),
631 VK_VERSION_PATCH(physDevProperties.apiVersion),
632 physDevProperties.vendorID,
633 physDevProperties.deviceID,
634 physDevProperties.deviceType);
635 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
637 qCDebug(QRHI_LOG_INFO,
" using this physical device");
641 if (physDevIndex < 0) {
642 qWarning(
"No matching physical device");
645 physDev = physDevs[physDevIndex];
646 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
648 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
649 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
650 physDevProperties.deviceName,
651 VK_VERSION_MAJOR(physDevProperties.driverVersion),
652 VK_VERSION_MINOR(physDevProperties.driverVersion),
653 VK_VERSION_PATCH(physDevProperties.driverVersion),
654 VK_VERSION_MAJOR(physDevProperties.apiVersion),
655 VK_VERSION_MINOR(physDevProperties.apiVersion),
656 VK_VERSION_PATCH(physDevProperties.apiVersion),
657 physDevProperties.vendorID,
658 physDevProperties.deviceID,
659 physDevProperties.deviceType);
662 caps.apiVersion = inst->apiVersion();
668 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
669 VK_VERSION_MINOR(physDevProperties.apiVersion));
670 if (physDevApiVersion < caps.apiVersion) {
671 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
672 <<
"whereas the chosen physical device has" << physDevApiVersion
673 <<
"- restricting to the latter";
674 caps.apiVersion = physDevApiVersion;
679 QVulkanInfoVector<QVulkanExtension> devExts;
680 uint32_t devExtCount = 0;
681 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
683 QList<VkExtensionProperties> extProps(devExtCount);
684 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
685 for (
const VkExtensionProperties &p : std::as_const(extProps))
686 devExts.append({ p.extensionName, p.specVersion });
688 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
690 bool featuresQueried =
false;
692 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
693 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
696#ifdef VK_KHR_fragment_shading_rate
697 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
698 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
699 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
700 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
702#ifdef VK_EXT_device_fault
703 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
704 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
705 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
706 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
712 if (!featuresQueried) {
714 if (caps.apiVersion >= QVersionNumber(1, 2)) {
715 physDevFeatures11IfApi12OrNewer = {};
716 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
717 physDevFeatures12 = {};
718 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
720 physDevFeatures13 = {};
721 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
723 physDevFeatures14 = {};
724 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
727 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
728 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
730 if (caps.apiVersion >= QVersionNumber(1, 3))
731 physDevFeatures12.pNext = &physDevFeatures13;
733 if (caps.apiVersion >= QVersionNumber(1, 4))
734 physDevFeatures13.pNext = &physDevFeatures14;
737 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
738 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
739 featuresQueried =
true;
746 if (!featuresQueried) {
754 if (caps.apiVersion == QVersionNumber(1, 1)) {
756 multiviewFeaturesIfApi11 = {};
757 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
758 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
761 shaderDrawParametersFeaturesIfApi11 = {};
762 shaderDrawParametersFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
763 addToChain(&physDevFeaturesChainable, &shaderDrawParametersFeaturesIfApi11);
765 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
766 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
767 featuresQueried =
true;
772 if (!featuresQueried) {
775 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
776 featuresQueried =
true;
784 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
785 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
786 queryQueueFamilyProps();
787 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
788 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
789 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
790 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
791 if (!gfxQueueFamilyIdxOpt.has_value()
792 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
793 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
795 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
796 gfxQueueFamilyIdxOpt = i;
797 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
798 computelessGfxQueueCandidateIdxOpt = i;
801 if (gfxQueueFamilyIdxOpt.has_value()) {
802 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
804 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
805 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
807 qWarning(
"No graphics (or no graphics+present) queue family found");
812 VkDeviceQueueCreateInfo queueInfo = {};
813 const float prio[] = { 0 };
814 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
815 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
816 queueInfo.queueCount = 1;
817 queueInfo.pQueuePriorities = prio;
819 QList<
const char *> requestedDevExts;
820 requestedDevExts.append(
"VK_KHR_swapchain");
822 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
824 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
825 if (hasPhysDevProp2) {
826 requestedDevExts.append(
"VK_KHR_portability_subset");
828 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
829 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
834#ifdef VK_EXT_vertex_attribute_divisor
835 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
836 if (hasPhysDevProp2) {
837 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
838 caps.vertexAttribDivisor =
true;
843#ifdef VK_KHR_create_renderpass2
844 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
845 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
846 caps.renderPass2KHR =
true;
850#ifdef VK_KHR_depth_stencil_resolve
851 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
852 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
853 caps.depthStencilResolveKHR =
true;
857#ifdef VK_KHR_fragment_shading_rate
858 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
859 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
862#ifdef VK_EXT_device_fault
863 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
864 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
865 caps.deviceFault =
true;
869 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
870 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
871 if (devExts.contains(ext)) {
872 requestedDevExts.append(ext.constData());
874 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
880 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
881 for (
const QByteArray &ext : envExtList) {
882 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
883 if (devExts.contains(ext)) {
884 requestedDevExts.append(ext.constData());
886 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
892 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
893 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
894 for (
const char *ext : std::as_const(requestedDevExts))
895 qCDebug(QRHI_LOG_INFO,
" %s", ext);
898 VkDeviceCreateInfo devInfo = {};
899 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
900 devInfo.queueCreateInfoCount = 1;
901 devInfo.pQueueCreateInfos = &queueInfo;
903 devInfo.enabledLayerCount = 0;
904 devInfo.ppEnabledLayerNames =
nullptr;
905 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
906 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
922 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
925 physDevFeatures13.robustImageAccess = VK_FALSE;
929 if (caps.apiVersion >= QVersionNumber(1, 1)) {
936 devInfo.pNext = &physDevFeaturesChainable;
940 physDevFeatures.robustBufferAccess = VK_FALSE;
941 devInfo.pEnabledFeatures = &physDevFeatures;
944 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
945 if (err != VK_SUCCESS) {
946 qWarning(
"Failed to create device: %d", err);
950 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
955 caps.deviceFault =
true;
956 caps.vertexAttribDivisor =
true;
957 caps.renderPass2KHR =
true;
958 caps.depthStencilResolveKHR =
true;
961 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
962 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
963 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
964 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
965 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
966 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
968 df = inst->deviceFunctions(dev);
970 VkCommandPoolCreateInfo poolInfo = {};
971 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
972 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
974 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
975 if (err != VK_SUCCESS) {
976 qWarning(
"Failed to create command pool: %d", err);
981 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
982 gfxQueueFamilyIdx, gfxQueueIdx);
985 if (gfxQueueFlags && caps.apiVersion >= QVersionNumber(1, 1)) {
986 VkDeviceQueueInfo2 queueInfo = {};
987 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
988 queueInfo.flags = gfxQueueFlags;
989 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
990 queueInfo.queueIndex = gfxQueueIdx;
991 df->vkGetDeviceQueue2(dev, &queueInfo, &gfxQueue);
994 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
996 if (queueFamilyProps.isEmpty())
997 queryQueueFamilyProps();
999 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
1000 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
1002 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
1005 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
1007 caps.depthClamp = physDevFeatures.depthClamp;
1009 caps.wideLines = physDevFeatures.wideLines;
1011 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
1013 caps.tessellation = physDevFeatures.tessellationShader;
1014 caps.geometryShader = physDevFeatures.geometryShader;
1016 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
1018 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
1020#ifdef VK_VERSION_1_2
1021 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1022 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1023 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
1026 caps.drawIndirectCount = physDevFeatures12.drawIndirectCount && caps.drawIndirectMulti;
1030#ifdef VK_VERSION_1_1
1031 if (caps.apiVersion == QVersionNumber(1, 1)) {
1032 caps.multiView = multiviewFeaturesIfApi11.multiview;
1033 caps.shaderDrawParameters = shaderDrawParametersFeaturesIfApi11.shaderDrawParameters;
1037#ifdef VK_KHR_fragment_shading_rate
1038 fragmentShadingRates.clear();
1039 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1040 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1041 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1042 if (caps.imageBasedShadingRate) {
1043 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1044 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1045 VkPhysicalDeviceProperties2 props2 = {};
1046 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1047 props2.pNext = &shadingRateProps;
1048 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1049 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1052 if (caps.perDrawShadingRate) {
1053 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1054 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1055 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1056 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1058 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1059 fragmentShadingRates.resize(count);
1060 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1062 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1064 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1066 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1067 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1076#ifdef VK_KHR_create_renderpass2
1077 if (caps.renderPass2KHR) {
1078 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1079 if (!vkCreateRenderPass2KHR)
1080 caps.renderPass2KHR =
false;
1084#ifdef VK_VERSION_1_2
1085 if (caps.drawIndirectCount) {
1086 vkCmdDrawIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndirectCount>(
1087 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndirectCount"));
1088 vkCmdDrawIndexedIndirectCount =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirectCount>(
1089 f->vkGetDeviceProcAddr(dev,
"vkCmdDrawIndexedIndirectCount"));
1090 if (!vkCmdDrawIndirectCount || !vkCmdDrawIndexedIndirectCount) {
1091 qWarning(
"Failed to resolve vkCmdDrawIndirectCount/vkCmdDrawIndexedIndirectCount; disabling DrawIndirectCount feature.");
1092 caps.drawIndirectCount =
false;
1099 adapterLuidValid =
false;
1101#ifdef VK_VERSION_1_2
1102 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1103 VkPhysicalDeviceVulkan11Properties v11props = {};
1104 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1105 VkPhysicalDeviceProperties2 props2 = {};
1106 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1107 props2.pNext = &v11props;
1108 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1109 if (v11props.deviceLUIDValid) {
1110 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1111 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1112 adapterLuidValid =
true;
1113 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1114 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1115 adapterLuid.LowPart, adapterLuid.HighPart);
1122 VmaVulkanFunctions funcs = {};
1123 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1124 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1126 VmaAllocatorCreateInfo allocatorInfo = {};
1129 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1130 allocatorInfo.physicalDevice = physDev;
1131 allocatorInfo.device = dev;
1132 allocatorInfo.pVulkanFunctions = &funcs;
1133 allocatorInfo.instance = inst->vkInstance();
1141#ifdef VK_VERSION_1_4
1142 if (caps.apiVersion >= QVersionNumber(1, 4))
1143 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1146#ifdef VK_VERSION_1_3
1147 if (caps.apiVersion >= QVersionNumber(1, 3))
1148 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1151#ifdef VK_VERSION_1_2
1152 if (caps.apiVersion >= QVersionNumber(1, 2))
1153 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1156#ifdef VK_VERSION_1_1
1157 if (caps.apiVersion >= QVersionNumber(1, 1))
1158 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1161#ifdef VK_VERSION_1_0
1162 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1165 VmaAllocator vmaallocator;
1166 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1167 if (err != VK_SUCCESS) {
1168 qWarning(
"Failed to create allocator: %d", err);
1174 inst->installDebugOutputFilter(qvk_debug_filter);
1176 VkDescriptorPool pool;
1177 VkResult err = createDescriptorPool(&pool);
1178 if (err == VK_SUCCESS)
1179 descriptorPools.append(pool);
1181 qWarning(
"Failed to create initial descriptor pool: %d", err);
1183 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1184 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1185 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1187 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1188 if (err != VK_SUCCESS) {
1189 qWarning(
"Failed to create timestamp query pool: %d", err);
1192 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1193 timestampQueryPoolMap.fill(
false);
1195#ifdef VK_EXT_debug_utils
1196 if (caps.debugUtils) {
1197 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1198 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1199 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1200 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1204#ifdef VK_EXT_device_fault
1205 if (caps.deviceFault) {
1206 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1212 nativeHandlesStruct.physDev = physDev;
1213 nativeHandlesStruct.dev = dev;
1214 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1215 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1216 nativeHandlesStruct.gfxQueueFlags = gfxQueueFlags;
1217 nativeHandlesStruct.gfxQueue = gfxQueue;
1218 nativeHandlesStruct.vmemAllocator = allocator;
1219 nativeHandlesStruct.inst = inst;
1230 df->vkQueueWaitIdle(gfxQueue);
1237 dxgiHdrInfo =
nullptr;
1241 if (ofr.cmdFence[i]) {
1242 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1243 ofr.cmdFence[i] = VK_NULL_HANDLE;
1245 ofr.cmdFenceWaitable[i] =
false;
1248 if (pipelineCache) {
1249 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1250 pipelineCache = VK_NULL_HANDLE;
1253 for (
const DescriptorPoolData &pool : descriptorPools)
1254 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1256 descriptorPools.clear();
1258 if (timestampQueryPool) {
1259 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1260 timestampQueryPool = VK_NULL_HANDLE;
1264 vmaDestroyAllocator(toVmaAllocator(allocator));
1270 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1271 cmdPool[i] = VK_NULL_HANDLE;
1273 freeSecondaryCbs[i].clear();
1274 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1277 if (!importedDevice && dev) {
1278 df->vkDestroyDevice(dev,
nullptr);
1279 inst->resetDeviceFunctions(dev);
1280 dev = VK_NULL_HANDLE;
1290QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1292 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1293 if (nativeHandles) {
1294 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1295 requestedPhysDev = h->physDev;
1298 QRhi::AdapterList list;
1299 QVulkanFunctions *f = inst->functions();
1300 uint32_t physDevCount = 0;
1301 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1305 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1306 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1307 if (err != VK_SUCCESS || !physDevCount)
1310 VkPhysicalDeviceProperties physDevProperties = {};
1311 for (uint32_t i = 0; i < physDevCount; ++i) {
1312 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1315 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1316 QVulkanAdapter *a =
new QVulkanAdapter;
1317 a->physDev = physDevs[i];
1318 fillDriverInfo(&a->adapterInfo, physDevProperties);
1332 VkDescriptorPoolSize descPoolSizes[] = {
1333 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1334 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1335 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1336 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1337 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1338 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1339 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1341 VkDescriptorPoolCreateInfo descPoolInfo = {};
1342 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1346 descPoolInfo.flags = 0;
1348 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1349 descPoolInfo.pPoolSizes = descPoolSizes;
1350 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1355 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1356 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1357 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1358 if (r == VK_SUCCESS)
1359 descriptorPools[poolIndex].refCount += 1;
1363 int lastPoolIdx = descriptorPools.size() - 1;
1364 for (
int i = lastPoolIdx; i >= 0; --i) {
1365 if (descriptorPools[i].refCount == 0) {
1366 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1367 descriptorPools[i].allocedDescSets = 0;
1369 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1370 VkResult err = tryAllocate(i);
1371 if (err == VK_SUCCESS) {
1372 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1373 *resultPoolIndex = i;
1379 VkDescriptorPool newPool;
1380 VkResult poolErr = createDescriptorPool(&newPool);
1381 if (poolErr == VK_SUCCESS) {
1382 descriptorPools.append(newPool);
1383 lastPoolIdx = descriptorPools.size() - 1;
1384 VkResult err = tryAllocate(lastPoolIdx);
1385 if (err != VK_SUCCESS) {
1386 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1389 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1390 *resultPoolIndex = lastPoolIdx;
1393 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1400 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1402 case QRhiTexture::RGBA8:
1403 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1404 case QRhiTexture::BGRA8:
1405 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1406 case QRhiTexture::R8:
1407 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1408 case QRhiTexture::RG8:
1409 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1410 case QRhiTexture::R16:
1411 return VK_FORMAT_R16_UNORM;
1412 case QRhiTexture::RG16:
1413 return VK_FORMAT_R16G16_UNORM;
1414 case QRhiTexture::RED_OR_ALPHA8:
1415 return VK_FORMAT_R8_UNORM;
1417 case QRhiTexture::RGBA16F:
1418 return VK_FORMAT_R16G16B16A16_SFLOAT;
1419 case QRhiTexture::RGBA32F:
1420 return VK_FORMAT_R32G32B32A32_SFLOAT;
1421 case QRhiTexture::R16F:
1422 return VK_FORMAT_R16_SFLOAT;
1423 case QRhiTexture::R32F:
1424 return VK_FORMAT_R32_SFLOAT;
1426 case QRhiTexture::RGB10A2:
1428 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1430 case QRhiTexture::R8SI:
1431 return VK_FORMAT_R8_SINT;
1432 case QRhiTexture::R32SI:
1433 return VK_FORMAT_R32_SINT;
1434 case QRhiTexture::RG32SI:
1435 return VK_FORMAT_R32G32_SINT;
1436 case QRhiTexture::RGBA32SI:
1437 return VK_FORMAT_R32G32B32A32_SINT;
1439 case QRhiTexture::R8UI:
1440 return VK_FORMAT_R8_UINT;
1441 case QRhiTexture::R32UI:
1442 return VK_FORMAT_R32_UINT;
1443 case QRhiTexture::RG32UI:
1444 return VK_FORMAT_R32G32_UINT;
1445 case QRhiTexture::RGBA32UI:
1446 return VK_FORMAT_R32G32B32A32_UINT;
1448 case QRhiTexture::D16:
1449 return VK_FORMAT_D16_UNORM;
1450 case QRhiTexture::D24:
1451 return VK_FORMAT_X8_D24_UNORM_PACK32;
1452 case QRhiTexture::D24S8:
1453 return VK_FORMAT_D24_UNORM_S8_UINT;
1454 case QRhiTexture::D32F:
1455 return VK_FORMAT_D32_SFLOAT;
1456 case QRhiTexture::D32FS8:
1457 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1459 case QRhiTexture::BC1:
1460 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1461 case QRhiTexture::BC2:
1462 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1463 case QRhiTexture::BC3:
1464 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1465 case QRhiTexture::BC4:
1466 return VK_FORMAT_BC4_UNORM_BLOCK;
1467 case QRhiTexture::BC5:
1468 return VK_FORMAT_BC5_UNORM_BLOCK;
1469 case QRhiTexture::BC6H:
1470 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1471 case QRhiTexture::BC7:
1472 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1474 case QRhiTexture::ETC2_RGB8:
1475 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1476 case QRhiTexture::ETC2_RGB8A1:
1477 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1478 case QRhiTexture::ETC2_RGBA8:
1479 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1481 case QRhiTexture::ASTC_4x4:
1482 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1483 case QRhiTexture::ASTC_5x4:
1484 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1485 case QRhiTexture::ASTC_5x5:
1486 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1487 case QRhiTexture::ASTC_6x5:
1488 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1489 case QRhiTexture::ASTC_6x6:
1490 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1491 case QRhiTexture::ASTC_8x5:
1492 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1493 case QRhiTexture::ASTC_8x6:
1494 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1495 case QRhiTexture::ASTC_8x8:
1496 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1497 case QRhiTexture::ASTC_10x5:
1498 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1499 case QRhiTexture::ASTC_10x6:
1500 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1501 case QRhiTexture::ASTC_10x8:
1502 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1503 case QRhiTexture::ASTC_10x10:
1504 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1505 case QRhiTexture::ASTC_12x10:
1506 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1507 case QRhiTexture::ASTC_12x12:
1508 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1511 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1518 case VK_FORMAT_R8G8B8A8_UNORM:
1519 return QRhiTexture::RGBA8;
1520 case VK_FORMAT_R8G8B8A8_SRGB:
1522 (*flags) |= QRhiTexture::sRGB;
1523 return QRhiTexture::RGBA8;
1524 case VK_FORMAT_B8G8R8A8_UNORM:
1525 return QRhiTexture::BGRA8;
1526 case VK_FORMAT_B8G8R8A8_SRGB:
1528 (*flags) |= QRhiTexture::sRGB;
1529 return QRhiTexture::BGRA8;
1530 case VK_FORMAT_R16G16B16A16_SFLOAT:
1531 return QRhiTexture::RGBA16F;
1532 case VK_FORMAT_R32G32B32A32_SFLOAT:
1533 return QRhiTexture::RGBA32F;
1534 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1535 return QRhiTexture::RGB10A2;
1537 qWarning(
"VkFormat %d cannot be read back", format);
1540 return QRhiTexture::UnknownFormat;
1546 case QRhiTexture::Format::D16:
1547 case QRhiTexture::Format::D24:
1548 case QRhiTexture::Format::D24S8:
1549 case QRhiTexture::Format::D32F:
1550 case QRhiTexture::Format::D32FS8:
1561 case QRhiTexture::Format::D24S8:
1562 case QRhiTexture::Format::D32FS8:
1572 if (isDepthTextureFormat(format)) {
1573 if (isStencilTextureFormat(format))
1574 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1576 return VK_IMAGE_ASPECT_DEPTH_BIT;
1578 return VK_IMAGE_ASPECT_COLOR_BIT;
1589 VkPhysicalDeviceMemoryProperties physDevMemProps;
1590 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1592 VkMemoryRequirements memReq;
1593 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1594 uint32_t memTypeIndex = uint32_t(-1);
1596 if (memReq.memoryTypeBits) {
1598 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1599 bool foundDevLocal =
false;
1600 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1601 if (memReq.memoryTypeBits & (1 << i)) {
1602 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1603 if (!foundDevLocal) {
1604 foundDevLocal =
true;
1607 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1616 return memTypeIndex;
1620 const QSize &pixelSize,
1621 VkImageUsageFlags usage,
1622 VkImageAspectFlags aspectMask,
1623 VkSampleCountFlagBits samples,
1624 VkDeviceMemory *mem,
1629 VkMemoryRequirements memReq;
1632 *mem = VK_NULL_HANDLE;
1633 for (
int i = 0; i < count; ++i) {
1634 images[i] = VK_NULL_HANDLE;
1635 views[i] = VK_NULL_HANDLE;
1638 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1639 for (
int i = 0; i < count; ++i) {
1641 df->vkDestroyImageView(dev, views[i],
nullptr);
1642 views[i] = VK_NULL_HANDLE;
1645 df->vkDestroyImage(dev, images[i],
nullptr);
1646 images[i] = VK_NULL_HANDLE;
1650 df->vkFreeMemory(dev, *mem,
nullptr);
1651 *mem = VK_NULL_HANDLE;
1655 for (
int i = 0; i < count; ++i) {
1656 VkImageCreateInfo imgInfo = {};
1657 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1658 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1659 imgInfo.format = format;
1660 imgInfo.extent.width = uint32_t(pixelSize.width());
1661 imgInfo.extent.height = uint32_t(pixelSize.height());
1662 imgInfo.extent.depth = 1;
1663 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1664 imgInfo.samples = samples;
1665 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1666 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1667 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1669 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1670 if (err != VK_SUCCESS) {
1671 qWarning(
"Failed to create image: %d", err);
1678 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1681 VkMemoryAllocateInfo memInfo = {};
1682 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1683 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1685 uint32_t startIndex = 0;
1687 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1688 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1689 qWarning(
"No suitable memory type found");
1692 startIndex = memInfo.memoryTypeIndex + 1;
1693 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1694 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1695 qWarning(
"Failed to allocate image memory: %d", err);
1698 }
while (err != VK_SUCCESS);
1700 VkDeviceSize ofs = 0;
1701 for (
int i = 0; i < count; ++i) {
1702 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1703 if (err != VK_SUCCESS) {
1704 qWarning(
"Failed to bind image memory: %d", err);
1707 ofs += aligned(memReq.size, memReq.alignment);
1709 VkImageViewCreateInfo imgViewInfo = {};
1710 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1711 imgViewInfo.image = images[i];
1712 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1713 imgViewInfo.format = format;
1714 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1715 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1716 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1717 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1718 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1719 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1721 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1722 if (err != VK_SUCCESS) {
1723 qWarning(
"Failed to create image view: %d", err);
1734 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1735 return optimalDsFormat;
1737 const VkFormat dsFormatCandidates[] = {
1738 VK_FORMAT_D24_UNORM_S8_UINT,
1739 VK_FORMAT_D32_SFLOAT_S8_UINT,
1740 VK_FORMAT_D16_UNORM_S8_UINT
1742 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1743 int dsFormatIdx = 0;
1744 while (dsFormatIdx < dsFormatCandidateCount) {
1745 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1746 VkFormatProperties fmtProp;
1747 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1748 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1752 if (dsFormatIdx == dsFormatCandidateCount)
1753 qWarning(
"Failed to find an optimal depth-stencil format");
1755 return optimalDsFormat;
1760 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1762 if (multiViewCount < 2)
1764 if (!multiViewCap) {
1765 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1768#ifdef VK_VERSION_1_1
1769 uint32_t allViewsMask = 0;
1770 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1771 allViewsMask |= (1 << i);
1772 multiViewMask = allViewsMask;
1773 multiViewCorrelationMask = allViewsMask;
1774 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1775 multiViewInfo.subpassCount = 1;
1776 multiViewInfo.pViewMasks = &multiViewMask;
1777 multiViewInfo.correlationMaskCount = 1;
1778 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1779 rpInfo->pNext = &multiViewInfo;
1784#ifdef VK_VERSION_1_1
1791#ifdef VK_KHR_create_renderpass2
1795struct RenderPass2SetupHelper
1797 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1799 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1803 if (multiViewCount >= 2) {
1804 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1805 viewMask |= (1 << i);
1808 attDescs2.resize(rpInfo->attachmentCount);
1809 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1810 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1811 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1813 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1814 att2.flags = att.flags;
1815 att2.format = att.format;
1816 att2.samples = att.samples;
1817 att2.loadOp = att.loadOp;
1818 att2.storeOp = att.storeOp;
1819 att2.stencilLoadOp = att.stencilLoadOp;
1820 att2.stencilStoreOp = att.stencilStoreOp;
1821 att2.initialLayout = att.initialLayout;
1822 att2.finalLayout = att.finalLayout;
1827 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1828 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1829 subpass2.flags = subpassDesc.flags;
1830 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1831 if (multiViewCount >= 2)
1832 subpass2.viewMask = viewMask;
1835 qsizetype startIndex = attRefs2.count();
1836 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1837 attRefs2.append({});
1838 VkAttachmentReference2KHR &attref2(attRefs2.last());
1839 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1840 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1841 attref2.attachment = attref.attachment;
1842 attref2.layout = attref.layout;
1843 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1845 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1846 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1849 if (subpassDesc.pResolveAttachments) {
1850 startIndex = attRefs2.count();
1851 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1852 attRefs2.append({});
1853 VkAttachmentReference2KHR &attref2(attRefs2.last());
1854 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1855 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1856 attref2.attachment = attref.attachment;
1857 attref2.layout = attref.layout;
1858 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1860 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1864 if (subpassDesc.pDepthStencilAttachment) {
1865 startIndex = attRefs2.count();
1866 attRefs2.append({});
1867 VkAttachmentReference2KHR &attref2(attRefs2.last());
1868 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1869 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1870 attref2.attachment = attref.attachment;
1871 attref2.layout = attref.layout;
1872 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1873 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1877#ifdef VK_KHR_depth_stencil_resolve
1879 if (rpD->hasDepthStencilResolve) {
1880 startIndex = attRefs2.count();
1881 attRefs2.append({});
1882 VkAttachmentReference2KHR &attref2(attRefs2.last());
1883 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1884 attref2.attachment = rpD->dsResolveRef.attachment;
1885 attref2.layout = rpD->dsResolveRef.layout;
1886 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1887 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1888 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1889 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1890 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1891 addToChain(&subpass2, &dsResolveDesc);
1895#ifdef VK_KHR_fragment_shading_rate
1896 shadingRateAttInfo = {};
1897 if (rpD->hasShadingRateMap) {
1898 startIndex = attRefs2.count();
1899 attRefs2.append({});
1900 VkAttachmentReference2KHR &attref2(attRefs2.last());
1901 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1902 attref2.attachment = rpD->shadingRateRef.attachment;
1903 attref2.layout = rpD->shadingRateRef.layout;
1904 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1905 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1906 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1907 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1908 addToChain(&subpass2, &shadingRateAttInfo);
1914 subpassDeps2.clear();
1915 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1916 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1917 subpassDeps2.append({});
1918 VkSubpassDependency2 &dep2(subpassDeps2.last());
1919 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1920 dep2.srcSubpass = dep.srcSubpass;
1921 dep2.dstSubpass = dep.dstSubpass;
1922 dep2.srcStageMask = dep.srcStageMask;
1923 dep2.dstStageMask = dep.dstStageMask;
1924 dep2.srcAccessMask = dep.srcAccessMask;
1925 dep2.dstAccessMask = dep.dstAccessMask;
1926 dep2.dependencyFlags = dep.dependencyFlags;
1929 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1930 rpInfo2->pNext =
nullptr;
1931 rpInfo2->flags = rpInfo->flags;
1932 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1933 rpInfo2->pAttachments = attDescs2.constData();
1934 rpInfo2->subpassCount = 1;
1935 rpInfo2->pSubpasses = &subpass2;
1936 rpInfo2->dependencyCount = subpassDeps2.count();
1937 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1938 if (multiViewCount >= 2) {
1939 rpInfo2->correlatedViewMaskCount = 1;
1940 rpInfo2->pCorrelatedViewMasks = &viewMask;
1946 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1947 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1948 VkSubpassDescription2KHR subpass2;
1949 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1950#ifdef VK_KHR_depth_stencil_resolve
1951 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1953#ifdef VK_KHR_fragment_shading_rate
1954 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1961 VkSubpassDescription *subpassDesc,
1964 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1965 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1966 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1967 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1968 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1969 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1971 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1972 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1973 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1974 rpInfo->pAttachments = rpD->attDescs.constData();
1975 rpInfo->subpassCount = 1;
1976 rpInfo->pSubpasses = subpassDesc;
1977 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1978 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1982 bool hasDepthStencil,
1983 VkSampleCountFlagBits samples,
1984 VkFormat colorFormat,
1985 QRhiShadingRateMap *shadingRateMap)
1989 VkAttachmentDescription attDesc = {};
1990 attDesc.format = colorFormat;
1991 attDesc.samples = samples;
1992 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1993 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1994 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1995 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1996 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1997 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1998 rpD->attDescs.append(attDesc);
2000 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2005 rpD->multiViewCount = 0;
2007 if (hasDepthStencil) {
2011 attDesc.format = optimalDepthStencilFormat();
2012 attDesc.samples = samples;
2013 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2014 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2015 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2016 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2017 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2018 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2019 rpD->attDescs.append(attDesc);
2021 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2026 if (samples > VK_SAMPLE_COUNT_1_BIT) {
2028 attDesc.format = colorFormat;
2029 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2030 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2031 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2032 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2033 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2034 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2035 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2036 rpD->attDescs.append(attDesc);
2038 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2041 rpD->dsResolveRef = {};
2043 rpD->shadingRateRef = {};
2044#ifdef VK_KHR_fragment_shading_rate
2045 if (shadingRateMap) {
2047 attDesc.format = VK_FORMAT_R8_UINT;
2048 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2049 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2050 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2051 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2052 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2053 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2054 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2055 rpD->attDescs.append(attDesc);
2057 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2062 VkSubpassDependency subpassDep = {};
2063 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2064 subpassDep.dstSubpass = 0;
2065 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2066 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2067 subpassDep.srcAccessMask = 0;
2068 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2069 rpD->subpassDeps.append(subpassDep);
2070 if (hasDepthStencil) {
2071 memset(&subpassDep, 0,
sizeof(subpassDep));
2072 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2073 subpassDep.dstSubpass = 0;
2074 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2075 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2076 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2077 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2078 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2079 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2080 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2081 rpD->subpassDeps.append(subpassDep);
2084 VkRenderPassCreateInfo rpInfo;
2085 VkSubpassDescription subpassDesc;
2086 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2088#ifdef VK_KHR_create_renderpass2
2089 if (caps.renderPass2KHR) {
2091 VkRenderPassCreateInfo2KHR rpInfo2;
2092 RenderPass2SetupHelper rp2Helper(
this);
2093 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2095 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2096 if (err != VK_SUCCESS) {
2097 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2104 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2105 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2106 if (err != VK_SUCCESS) {
2107 qWarning(
"Failed to create renderpass: %d", err);
2116 const QRhiColorAttachment *colorAttachmentsBegin,
2117 const QRhiColorAttachment *colorAttachmentsEnd,
2121 QRhiRenderBuffer *depthStencilBuffer,
2122 QRhiTexture *depthTexture,
2123 QRhiTexture *depthResolveTexture,
2125 QRhiShadingRateMap *shadingRateMap)
2129 int multiViewCount = 0;
2130 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2133 Q_ASSERT(texD || rbD);
2134 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2135 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2137 VkAttachmentDescription attDesc = {};
2138 attDesc.format = vkformat;
2139 attDesc.samples = samples;
2140 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2141 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2142 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2143 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2145 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2146 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2147 rpD->attDescs.append(attDesc);
2149 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2150 rpD->colorRefs.append(ref);
2152 if (it->multiViewCount() >= 2) {
2153 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2154 qWarning(
"Inconsistent multiViewCount in color attachment set");
2156 multiViewCount = it->multiViewCount();
2157 }
else if (multiViewCount > 0) {
2158 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2161 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2162 rpD->multiViewCount = uint32_t(multiViewCount);
2166 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2167 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2168 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2169 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2170 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2171 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2172 VkAttachmentDescription attDesc = {};
2173 attDesc.format = dsFormat;
2174 attDesc.samples = samples;
2175 attDesc.loadOp = loadOp;
2176 attDesc.storeOp = storeOp;
2177 attDesc.stencilLoadOp = loadOp;
2178 attDesc.stencilStoreOp = storeOp;
2179 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2180 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2181 rpD->attDescs.append(attDesc);
2182 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2183 multiViewCount = depthTexture->arraySize();
2184 rpD->multiViewCount = multiViewCount;
2186 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2191 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2192 if (it->resolveTexture()) {
2194 const VkFormat dstFormat = rtexD->vkformat;
2195 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2196 qWarning(
"Resolving into a multisample texture is not supported");
2200 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2201 if (srcFormat != dstFormat) {
2205 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2206 int(srcFormat),
int(dstFormat));
2209 VkAttachmentDescription attDesc = {};
2210 attDesc.format = rtexD->viewFormat;
2211 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2212 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2213 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2214 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2215 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2216 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2217 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2218 rpD->attDescs.append(attDesc);
2220 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2221 rpD->resolveRefs.append(ref);
2223 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2224 rpD->resolveRefs.append(ref);
2227 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2232 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2233 qWarning(
"Resolving into a multisample depth texture is not supported");
2234 const VkFormat dstFormat = rtexD->vkformat;
2238 Q_ASSERT(texD || rbD);
2239 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2240 if (srcFormat != dstFormat) {
2241 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2242 int(srcFormat),
int(dstFormat));
2245 VkAttachmentDescription attDesc = {};
2246 attDesc.format = rtexD->viewFormat;
2247 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2248 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2249 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2250 attDesc.stencilLoadOp = attDesc.loadOp;
2251 attDesc.stencilStoreOp = attDesc.storeOp;
2252 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2253 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2254 rpD->attDescs.append(attDesc);
2255 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2257 rpD->dsResolveRef = {};
2261 rpD->shadingRateRef = {};
2262#ifdef VK_KHR_fragment_shading_rate
2263 if (shadingRateMap) {
2264 VkAttachmentDescription attDesc = {};
2265 attDesc.format = VK_FORMAT_R8_UINT;
2266 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2267 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2268 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2269 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2270 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2271 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2272 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2273 rpD->attDescs.append(attDesc);
2274 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2279 VkSubpassDependency selfDependency = {};
2280 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2281 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2282 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2283 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2284 selfDependency.srcSubpass = 0;
2285 selfDependency.dstSubpass = 0;
2286 selfDependency.srcStageMask = stageMask;
2287 selfDependency.dstStageMask = stageMask;
2288 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2289 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2290 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2291#ifdef VK_VERSION_1_1
2292 if (rpD->multiViewCount >= 2)
2293 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2295 selfDependency.dependencyFlags = depFlags;
2296 rpD->subpassDeps.append(selfDependency);
2303 VkRenderPassCreateInfo rpInfo;
2304 VkSubpassDescription subpassDesc;
2305 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2308 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2311#ifdef VK_KHR_create_renderpass2
2312 if (caps.renderPass2KHR) {
2314 VkRenderPassCreateInfo2KHR rpInfo2;
2315 RenderPass2SetupHelper rp2Helper(
this);
2316 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2319 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2320 if (err != VK_SUCCESS) {
2321 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2328 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2329 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2332 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2333 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2334 if (err != VK_SUCCESS) {
2335 qWarning(
"Failed to create renderpass: %d", err);
2346 if (swapChainD->pixelSize.isEmpty()) {
2347 qWarning(
"Surface size is 0, cannot create swapchain");
2352 df->vkQueueWaitIdle(gfxQueue);
2354 if (!vkCreateSwapchainKHR) {
2355 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2356 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2357 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2358 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2359 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2360 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2361 qWarning(
"Swapchain functions not available");
2366 VkSurfaceCapabilitiesKHR surfaceCaps;
2367 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2368 quint32 reqBufferCount;
2369 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2370 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2372 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2374 VkSurfaceTransformFlagBitsKHR preTransform =
2375 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2376 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2377 : surfaceCaps.currentTransform;
2403 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2404 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2405 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2406 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2408 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2409 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2410 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2411 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2412 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2413 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2414 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2415 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2416 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2417 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2420 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2421 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2422 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2423 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2425 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2426 && surfaceCaps.maxImageArrayLayers > 1;
2429 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2430 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2434 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2435 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2436 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2437 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2445 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2447 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2448 reuseExisting ?
"recycled" :
"new",
2449 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2451 VkSwapchainCreateInfoKHR swapChainInfo = {};
2452 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2453 swapChainInfo.surface = swapChainD->surface;
2454 swapChainInfo.minImageCount = reqBufferCount;
2455 swapChainInfo.imageFormat = swapChainD->colorFormat;
2456 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2457 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2458 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2459 swapChainInfo.imageUsage = usage;
2460 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2461 swapChainInfo.preTransform = preTransform;
2462 swapChainInfo.compositeAlpha = compositeAlpha;
2463 swapChainInfo.presentMode = presentMode;
2464 swapChainInfo.clipped =
true;
2465 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2467 VkSwapchainKHR newSwapChain;
2468 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2469 if (err != VK_SUCCESS) {
2470 qWarning(
"Failed to create swapchain: %d", err);
2473 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2478 swapChainD->sc = newSwapChain;
2479 swapChainD->lastConnectedSurface = swapChainD->surface;
2481 quint32 actualSwapChainBufferCount = 0;
2482 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2483 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2484 qWarning(
"Failed to get swapchain images: %d", err);
2488 if (actualSwapChainBufferCount != reqBufferCount)
2489 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2492 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2493 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2494 if (err != VK_SUCCESS) {
2495 qWarning(
"Failed to get swapchain images: %d", err);
2499 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2500 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2501 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2502 if (!createTransientImage(swapChainD->colorFormat,
2503 swapChainD->pixelSize,
2504 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2505 VK_IMAGE_ASPECT_COLOR_BIT,
2506 swapChainD->samples,
2507 &swapChainD->msaaImageMem,
2510 swapChainD->bufferCount))
2512 qWarning(
"Failed to create transient image for MSAA color buffer");
2517 VkFenceCreateInfo fenceInfo = {};
2518 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2519 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2522 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2526 image.image = swapChainImages[i];
2527 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2528 image.msaaImage = msaaImages[i];
2529 image.msaaImageView = msaaViews[i];
2532 VkImageViewCreateInfo imgViewInfo = {};
2533 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2534 imgViewInfo.image = swapChainImages[i];
2535 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2536 imgViewInfo.format = swapChainD->colorFormat;
2537 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2538 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2539 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2540 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2541 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2542 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2543 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2544 if (err != VK_SUCCESS) {
2545 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2551 VkSemaphoreCreateInfo semInfo = {};
2552 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2553 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2558 image.image = swapChainImages[i];
2559 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2560 image.msaaImage = msaaImages[i];
2561 image.msaaImageView = msaaViews[i];
2564 VkImageViewCreateInfo imgViewInfo = {};
2565 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2566 imgViewInfo.image = swapChainImages[i];
2567 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2568 imgViewInfo.format = swapChainD->colorFormat;
2569 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2570 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2571 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2572 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2573 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2574 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2575 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2576 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2577 if (err != VK_SUCCESS) {
2578 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2582 VkSemaphoreCreateInfo semInfo = {};
2583 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2584 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2590 swapChainD->currentImageIndex = 0;
2592 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2594 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2595 VkImageViewCreateInfo viewInfo = {};
2596 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2597 viewInfo.image = texD->image;
2598 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2599 viewInfo.format = texD->viewFormat;
2600 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2601 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2602 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2603 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2604 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2605 viewInfo.subresourceRange.baseMipLevel = 0;
2606 viewInfo.subresourceRange.levelCount = 1;
2607 viewInfo.subresourceRange.baseArrayLayer = 0;
2608 viewInfo.subresourceRange.layerCount = 1;
2609 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2610 if (err != VK_SUCCESS) {
2611 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2616 VkSemaphoreCreateInfo semInfo = {};
2617 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2625 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2627 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2628 if (err != VK_SUCCESS) {
2629 qWarning(
"Failed to create command buffer fence: %d", err);
2642 if (swapChainD->sc == VK_NULL_HANDLE)
2646 df->vkQueueWaitIdle(gfxQueue);
2650 if (frame.cmdFence) {
2652 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2653 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2654 frame.cmdFence = VK_NULL_HANDLE;
2657 if (frame.imageSem) {
2658 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2659 frame.imageSem = VK_NULL_HANDLE;
2666 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2667 image.fb = VK_NULL_HANDLE;
2669 if (image.imageView) {
2670 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2671 image.imageView = VK_NULL_HANDLE;
2673 if (image.msaaImageView) {
2674 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2675 image.msaaImageView = VK_NULL_HANDLE;
2677 if (image.msaaImage) {
2678 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2679 image.msaaImage = VK_NULL_HANDLE;
2681 if (image.drawSem) {
2682 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2683 image.drawSem = VK_NULL_HANDLE;
2687 if (swapChainD->msaaImageMem) {
2688 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2689 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2692 if (swapChainD->shadingRateMapView) {
2693 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2694 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2697 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2698 swapChainD->sc = VK_NULL_HANDLE;
2705 VkCommandPoolResetFlags flags = 0;
2710 if (releaseCachedResourcesCalledBeforeFrameStart)
2711 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2714 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2720 for (quint64 i = 0; i < timestampValidBits; i += 8)
2721 mask |= 0xFFULL << i;
2722 const quint64 ts0 = timestamp[0] & mask;
2723 const quint64 ts1 = timestamp[1] & mask;
2724 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2725 if (!qFuzzyIsNull(nsecsPerTick)) {
2726 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2727 const double elapsedSec = elapsedMs / 1000.0;
2738 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2741 inst->handle()->beginFrame(swapChainD->window);
2751 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2752 if (waitResult != QRhi::FrameOpSuccess)
2757 uint32_t imageIndex = 0;
2758 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2759 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2761 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2762 swapChainD->currentImageIndex = imageIndex;
2765 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2766 return QRhi::FrameOpSwapChainOutOfDate;
2768 if (err == VK_ERROR_DEVICE_LOST) {
2769 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2770 printExtraErrorInfo(err);
2772 return QRhi::FrameOpDeviceLost;
2774 qWarning(
"Failed to acquire next swapchain image: %d", err);
2775 return QRhi::FrameOpError;
2781 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2787 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2788 if (cbres != QRhi::FrameOpSuccess)
2791 swapChainD->cbWrapper.cb = frame.cmdBuf;
2794 swapChainD->rtWrapper.d.fb = image.fb;
2798 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2799 swapChainD->rtWrapperRight.d.fb = image.fb;
2806 quint64 timestamp[2] = { 0, 0 };
2807 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2808 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2809 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2810 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2812 if (err == VK_SUCCESS) {
2814 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2816 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2818 qWarning(
"Failed to query timestamp: %d", err);
2823 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2824 int timestampQueryIdx = -1;
2825 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2826 if (!timestampQueryPoolMap.testBit(i)) {
2827 timestampQueryPoolMap.setBit(i);
2828 timestampQueryIdx = i * 2;
2832 if (timestampQueryIdx >= 0) {
2833 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2835 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2836 timestampQueryPool, uint32_t(timestampQueryIdx));
2841 return QRhi::FrameOpSuccess;
2849 auto cleanup = qScopeGuard([
this, swapChainD] {
2850 inst->handle()->endFrame(swapChainD->window);
2855 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2860 VkImageMemoryBarrier presTrans = {};
2861 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2862 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2863 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2864 presTrans.image = image.image;
2865 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2866 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2870 presTrans.srcAccessMask = 0;
2871 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2872 df->vkCmdPipelineBarrier(frame.cmdBuf,
2873 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2874 0, 0,
nullptr, 0,
nullptr,
2878 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2879 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2880 df->vkCmdPipelineBarrier(frame.cmdBuf,
2881 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2882 0, 0,
nullptr, 0,
nullptr,
2890 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2896 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2897 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2899 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2900 needsPresent ? &image.drawSem :
nullptr);
2901 if (submitres != QRhi::FrameOpSuccess)
2909 VkPresentInfoKHR presInfo = {};
2910 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2911 presInfo.swapchainCount = 1;
2912 presInfo.pSwapchains = &swapChainD->sc;
2913 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2914 waitSemaphoresForPresent.append(image.drawSem);
2915 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2916 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2920 inst->presentAboutToBeQueued(swapChainD->window);
2922 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2923 waitSemaphoresForPresent.clear();
2924 if (err != VK_SUCCESS) {
2925 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2926 return QRhi::FrameOpSwapChainOutOfDate;
2927 }
else if (err != VK_SUBOPTIMAL_KHR) {
2928 if (err == VK_ERROR_DEVICE_LOST) {
2929 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2930 printExtraErrorInfo(err);
2932 return QRhi::FrameOpDeviceLost;
2934 qWarning(
"Failed to present: %d", err);
2935 return QRhi::FrameOpError;
2941 inst->presentQueued(swapChainD->window);
2946 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
2951 return QRhi::FrameOpSuccess;
2965 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2975 VkCommandBufferAllocateInfo cmdBufInfo = {};
2976 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2977 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2978 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2979 cmdBufInfo.commandBufferCount = 1;
2981 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2982 if (err != VK_SUCCESS) {
2983 if (err == VK_ERROR_DEVICE_LOST) {
2984 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2985 printExtraErrorInfo(err);
2987 return QRhi::FrameOpDeviceLost;
2989 qWarning(
"Failed to allocate frame command buffer: %d", err);
2990 return QRhi::FrameOpError;
2994 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2995 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2997 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2998 if (err != VK_SUCCESS) {
2999 if (err == VK_ERROR_DEVICE_LOST) {
3000 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
3001 printExtraErrorInfo(err);
3003 return QRhi::FrameOpDeviceLost;
3005 qWarning(
"Failed to begin frame command buffer: %d", err);
3006 return QRhi::FrameOpError;
3009 return QRhi::FrameOpSuccess;
3013 VkSemaphore *waitSem, VkSemaphore *signalSem)
3015 VkResult err =
df->vkEndCommandBuffer(cb);
3016 if (err != VK_SUCCESS) {
3017 if (err == VK_ERROR_DEVICE_LOST) {
3018 qWarning(
"Device loss detected in vkEndCommandBuffer()");
3019 printExtraErrorInfo(err);
3021 return QRhi::FrameOpDeviceLost;
3023 qWarning(
"Failed to end frame command buffer: %d", err);
3024 return QRhi::FrameOpError;
3027 VkSubmitInfo submitInfo = {};
3028 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
3029 submitInfo.commandBufferCount = 1;
3030 submitInfo.pCommandBuffers = &cb;
3033 waitSemaphoresForQueueSubmit.append(*waitSem);
3035 signalSemaphoresForQueueSubmit.append(*signalSem);
3037 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
3038 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
3039 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
3040 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3041 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
3043 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3044 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3045 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3048 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3050 waitSemaphoresForQueueSubmit.clear();
3051 signalSemaphoresForQueueSubmit.clear();
3053 if (err != VK_SUCCESS) {
3054 if (err == VK_ERROR_DEVICE_LOST) {
3055 qWarning(
"Device loss detected in vkQueueSubmit()");
3056 printExtraErrorInfo(err);
3058 return QRhi::FrameOpDeviceLost;
3060 qWarning(
"Failed to submit to graphics queue: %d", err);
3061 return QRhi::FrameOpError;
3064 return QRhi::FrameOpSuccess;
3069 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3070 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3071 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3072 if (frame.cmdFenceWaitable) {
3073 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3075 if (err != VK_SUCCESS) {
3076 if (err == VK_ERROR_DEVICE_LOST) {
3077 qWarning(
"Device loss detected in vkWaitForFences()");
3078 printExtraErrorInfo(err);
3080 return QRhi::FrameOpDeviceLost;
3082 qWarning(
"Failed to wait for fence: %d", err);
3083 return QRhi::FrameOpError;
3086 df->vkResetFences(dev, 1, &frame.cmdFence);
3087 frame.cmdFenceWaitable =
false;
3091 if (ofr.cmdFenceWaitable[frameSlot]) {
3092 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3093 if (err != VK_SUCCESS) {
3094 if (err == VK_ERROR_DEVICE_LOST) {
3095 qWarning(
"Device loss detected in vkWaitForFences()");
3096 printExtraErrorInfo(err);
3098 return QRhi::FrameOpDeviceLost;
3100 qWarning(
"Failed to wait for offscreen fence: %d", err);
3101 return QRhi::FrameOpError;
3103 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3104 ofr.cmdFenceWaitable[frameSlot] =
false;
3107 return QRhi::FrameOpSuccess;
3112 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3113 if (waitResult != QRhi::FrameOpSuccess)
3119 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3120 if (cbres != QRhi::FrameOpSuccess)
3126 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3127 quint64 timestamp[2] = { 0, 0 };
3128 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3129 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3130 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3131 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3132 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3133 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3134 if (err == VK_SUCCESS) {
3136 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3140 qWarning(
"Failed to query timestamp: %d", err);
3144 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3145 int timestampQueryIdx = -1;
3146 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3147 if (!timestampQueryPoolMap.testBit(i)) {
3148 timestampQueryPoolMap.setBit(i);
3149 timestampQueryIdx = i * 2;
3153 if (timestampQueryIdx >= 0) {
3154 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3156 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3157 timestampQueryPool, uint32_t(timestampQueryIdx));
3158 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3163 return QRhi::FrameOpSuccess;
3169 Q_ASSERT(ofr.active);
3175 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3179 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3180 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3181 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3184 if (!ofr.cmdFence[currentFrameSlot]) {
3185 VkFenceCreateInfo fenceInfo = {};
3186 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3187 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3188 if (err != VK_SUCCESS) {
3189 qWarning(
"Failed to create command buffer fence: %d", err);
3190 return QRhi::FrameOpError;
3194 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3195 if (submitres != QRhi::FrameOpSuccess)
3198 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3201 if (readbacksPending) {
3202 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3203 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3204 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3211 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3213 return QRhi::FrameOpSuccess;
3235 swapChainD->cbWrapper.resetCommands();
3236 cb = swapChainD->cbWrapper.cb;
3238 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3239 if (submitres != QRhi::FrameOpSuccess)
3243 df->vkQueueWaitIdle(gfxQueue);
3250 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3253 startPrimaryCommandBuffer(&frame.cmdBuf);
3254 swapChainD->cbWrapper.cb = frame.cmdBuf;
3261 return QRhi::FrameOpSuccess;
3268 u
.access =
int(bufUsage.access);
3269 u
.stage =
int(bufUsage.stage);
3277 u
.access =
int(texUsage.access);
3278 u
.stage =
int(texUsage.stage);
3284 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3287 rtD->lastActiveFrameSlot = currentFrameSlot;
3288 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3290 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3298 texD->lastActiveFrameSlot = currentFrameSlot;
3303 rbD->lastActiveFrameSlot = currentFrameSlot;
3309 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3312 if (rtD->m_desc.depthStencilBuffer()) {
3314 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3321 rbD->lastActiveFrameSlot = currentFrameSlot;
3323 if (rtD->m_desc.depthTexture()) {
3328 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3330 if (rtD->m_desc.depthResolveTexture()) {
3335 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3337 if (rtD->m_desc.shadingRateMap()) {
3342 texD->lastActiveFrameSlot = currentFrameSlot;
3356 VkCommandBuffer secondaryCb;
3358 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3359 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3360 freeSecondaryCbs[currentFrameSlot].removeLast();
3362 VkCommandBufferAllocateInfo cmdBufInfo = {};
3363 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3364 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3365 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3366 cmdBufInfo.commandBufferCount = 1;
3368 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3369 if (err != VK_SUCCESS) {
3370 qWarning(
"Failed to create secondary command buffer: %d", err);
3371 return VK_NULL_HANDLE;
3375 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3376 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3377 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3378 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3379 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3380 cmdBufInheritInfo.subpass = 0;
3382 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3383 cmdBufInheritInfo.framebuffer = rtD->fb;
3385 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3387 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3388 if (err != VK_SUCCESS) {
3389 qWarning(
"Failed to begin secondary command buffer: %d", err);
3390 return VK_NULL_HANDLE;
3398 VkResult err =
df->vkEndCommandBuffer(cb);
3399 if (err != VK_SUCCESS)
3400 qWarning(
"Failed to end secondary command buffer: %d", err);
3404 cmd.args.executeSecondary.cb = cb;
3408 e.lastActiveFrameSlot = currentFrameSlot;
3409 e.secondaryCommandBuffer.cb = cb;
3410 releaseQueue.append(e);
3414 QRhiRenderTarget *rt,
3415 const QColor &colorClearValue,
3416 const QRhiDepthStencilClearValue &depthStencilClearValue,
3417 QRhiResourceUpdateBatch *resourceUpdates,
3418 QRhiCommandBuffer::BeginPassFlags flags)
3423 if (resourceUpdates)
3433 switch (rt->resourceType()) {
3434 case QRhiResource::SwapChainRenderTarget:
3436 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3446 texD->lastActiveFrameSlot = currentFrameSlot;
3449 case QRhiResource::TextureRenderTarget:
3463 cbD->currentTarget = rt;
3468 VkRenderPassBeginInfo rpBeginInfo = {};
3469 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3470 rpBeginInfo.renderPass = rtD
->rp->rp;
3471 rpBeginInfo.framebuffer = rtD->fb;
3472 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3473 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3475 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3476 [](
const VkAttachmentDescription &attDesc) {
3477 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3478 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3481 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3482 if (rpHasAnyClearOp) {
3484 VkClearValue cv = {};
3485 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3486 colorClearValue.alphaF() } };
3490 VkClearValue cv = {};
3491 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3495 VkClearValue cv = {};
3496 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3497 colorClearValue.alphaF() } };
3501 VkClearValue cv = {};
3502 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3506 VkClearValue cv = {};
3507 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3511 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3512 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3516 cmd.args.beginRenderPass.desc = rpBeginInfo;
3517 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3519 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3522 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3527 rateCmd.args.setShadingRate.w = 1;
3528 rateCmd.args.setShadingRate.h = 1;
3540 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3541 cbD->activeSecondaryCbStack.removeLast();
3542 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3549 cbD->currentTarget =
nullptr;
3551 if (resourceUpdates)
3556 QRhiResourceUpdateBatch *resourceUpdates,
3557 QRhiCommandBuffer::BeginPassFlags flags)
3562 if (resourceUpdates)
3570 cbD->computePassState.reset();
3573 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3584 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3585 cbD->activeSecondaryCbStack.removeLast();
3586 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3591 if (resourceUpdates)
3598 Q_ASSERT(psD->pipeline);
3602 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3604 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3608 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3609 cmd.args.bindPipeline.pipeline = psD->pipeline;
3612 cbD->currentGraphicsPipeline =
nullptr;
3613 cbD->currentComputePipeline = ps;
3614 cbD->currentPipelineGeneration = psD->generation;
3617 psD->lastActiveFrameSlot = currentFrameSlot;
3622 QRhiShaderResourceBinding::Type bindingType,
3623 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3625 VkAccessFlags access = 0;
3626 if (bindingType == loadTypeVal) {
3627 access = VK_ACCESS_SHADER_READ_BIT;
3629 access = VK_ACCESS_SHADER_WRITE_BIT;
3630 if (bindingType == loadStoreTypeVal)
3631 access |= VK_ACCESS_SHADER_READ_BIT;
3633 auto it = writtenResources->find(resource);
3634 if (it != writtenResources->end())
3635 it->second.accessFlags |= access;
3636 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3637 writtenResources->insert(resource, { access,
true });
3642 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3643 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3644 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3645 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3646 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3647 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3653 QVarLengthArray<VkImageMemoryBarrier, 8> *imageBarriers,
3654 QVarLengthArray<VkBufferMemoryBarrier, 8> *bufferBarriers)
3656 if (!cbD->currentComputeSrb)
3662 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3663 accessAndIsNewFlag = { 0,
false };
3666 for (
auto &binding : srbD->m_bindings) {
3667 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3669 case QRhiShaderResourceBinding::ImageLoad:
3670 case QRhiShaderResourceBinding::ImageStore:
3671 case QRhiShaderResourceBinding::ImageLoadStore:
3672 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3675 QRhiShaderResourceBinding::ImageLoad,
3676 QRhiShaderResourceBinding::ImageStore,
3677 QRhiShaderResourceBinding::ImageLoadStore);
3679 case QRhiShaderResourceBinding::BufferLoad:
3680 case QRhiShaderResourceBinding::BufferStore:
3681 case QRhiShaderResourceBinding::BufferLoadStore:
3682 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3685 QRhiShaderResourceBinding::BufferLoad,
3686 QRhiShaderResourceBinding::BufferStore,
3687 QRhiShaderResourceBinding::BufferLoadStore);
3694 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3695 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3696 const bool isNewInThisDispatch = it->second.isNew;
3697 if (accessInThisDispatch && !isNewInThisDispatch) {
3698 if (it.key()->resourceType() == QRhiResource::Texture) {
3700 VkImageMemoryBarrier barrier = {};
3701 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3702 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3704 barrier.subresourceRange.baseMipLevel = 0;
3705 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3706 barrier.subresourceRange.baseArrayLayer = 0;
3707 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3708 barrier.oldLayout = texD->usageState.layout;
3709 barrier.newLayout = texD->usageState.layout;
3710 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3711 barrier.dstAccessMask = accessInThisDispatch;
3712 barrier.image = texD->image;
3713 imageBarriers->append(barrier);
3716 VkBufferMemoryBarrier barrier = {};
3717 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3718 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3719 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3720 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3721 barrier.dstAccessMask = accessInThisDispatch;
3722 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3723 barrier.size = VK_WHOLE_SIZE;
3724 bufferBarriers->append(barrier);
3730 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3731 it = cbD->computePassState.writtenResources.erase(it);
3742 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3743 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3744 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
3747 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3748 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3749 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3751 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3752 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3754 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3756 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3759 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3760 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3761 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3762 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3763 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3764 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3765 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3766 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3770 cmd.args.dispatch.x = x;
3771 cmd.args.dispatch.y = y;
3772 cmd.args.dispatch.z = z;
3777 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3778 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3779 quint32 maxDrawCount, quint32 stride)
3781 if (!caps.drawIndirectCount) {
3782 qWarning(
"drawIndirectCount called but the DrawIndirectCount feature is not supported");
3791 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3792 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3794 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3798 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3801 countBufD->lastActiveFrameSlot = currentFrameSlot;
3802 if (countBufD->m_type == QRhiBuffer::Dynamic)
3804 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3808 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3811#ifdef VK_VERSION_1_2
3812 vkCmdDrawIndirectCount(cbD->activeSecondaryCbStack.last(),
3813 indirectBufVk, indirectBufferOffset,
3814 countBufVk, countBufferOffset,
3815 maxDrawCount, stride);
3820 cmd.args.drawIndirectCount.indirectBuffer = indirectBufVk;
3821 cmd.args.drawIndirectCount.indirectBufferOffset = indirectBufferOffset;
3822 cmd.args.drawIndirectCount.countBuffer = countBufVk;
3823 cmd.args.drawIndirectCount.countBufferOffset = countBufferOffset;
3824 cmd.args.drawIndirectCount.maxDrawCount = maxDrawCount;
3825 cmd.args.drawIndirectCount.stride = stride;
3830 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3831 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3832 quint32 maxDrawCount, quint32 stride)
3834 if (!caps.drawIndirectCount) {
3835 qWarning(
"drawIndexedIndirectCount called but the DrawIndirectCount feature is not supported");
3844 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3845 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3847 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3851 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3854 countBufD->lastActiveFrameSlot = currentFrameSlot;
3855 if (countBufD->m_type == QRhiBuffer::Dynamic)
3857 const int countBufSlot = countBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3861 VkBuffer countBufVk = countBufD->buffers[countBufSlot];
3864#ifdef VK_VERSION_1_2
3865 vkCmdDrawIndexedIndirectCount(cbD->activeSecondaryCbStack.last(),
3866 indirectBufVk, indirectBufferOffset,
3867 countBufVk, countBufferOffset,
3868 maxDrawCount, stride);
3873 cmd.args.drawIndexedIndirectCount.indirectBuffer = indirectBufVk;
3874 cmd.args.drawIndexedIndirectCount.indirectBufferOffset = indirectBufferOffset;
3875 cmd.args.drawIndexedIndirectCount.countBuffer = countBufVk;
3876 cmd.args.drawIndexedIndirectCount.countBufferOffset = countBufferOffset;
3877 cmd.args.drawIndexedIndirectCount.maxDrawCount = maxDrawCount;
3878 cmd.args.drawIndexedIndirectCount.stride = stride;
3883 quint32 indirectBufferOffset)
3890 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
3891 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
3893 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
3894 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
3899 VkAccessFlags indirectSrcAccess = 0;
3900 VkPipelineStageFlags indirectSrcStage = 0;
3905 if (cbD->computePassState.writtenResources.contains(indirectBufD)) {
3906 indirectSrcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
3907 indirectSrcStage |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3915 const auto trackedIt = passResTracker.buffers().find(indirectBufD);
3916 if (trackedIt != passResTracker.buffers().cend()
3919 indirectSrcAccess |= VkAccessFlags(trackedIt->second.stateAtPassBegin.access);
3920 indirectSrcStage |= VkPipelineStageFlags(trackedIt->second.stateAtPassBegin.stage);
3923 u.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
3924 u.stage |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
3931 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3932 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3933 collectComputeBarriers(cbD, &imageBarriers, &bufferBarriers);
3935 VkBufferMemoryBarrier indirectBarrier = {};
3936 const bool needsIndirectBarrier = indirectSrcStage != 0 && accessIsWrite(indirectSrcAccess);
3937 if (needsIndirectBarrier) {
3938 indirectBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3939 indirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3940 indirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3941 indirectBarrier.srcAccessMask = indirectSrcAccess;
3942 indirectBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
3943 indirectBarrier.buffer = indirectBufVk;
3944 indirectBarrier.size = VK_WHOLE_SIZE;
3948 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3949 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3950 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3952 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3953 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3955 if (needsIndirectBarrier) {
3956 df->vkCmdPipelineBarrier(secondaryCb, indirectSrcStage, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
3958 1, &indirectBarrier,
3961 df->vkCmdDispatchIndirect(secondaryCb, indirectBufVk, VkDeviceSize(indirectBufferOffset));
3963 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3966 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3967 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3968 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3969 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3970 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3971 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3972 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3973 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3975 if (needsIndirectBarrier) {
3978 cmd.args.bufferBarrier.srcStageMask = indirectSrcStage;
3979 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
3980 cmd.args.bufferBarrier.count = 1;
3981 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3982 cbD->pools.bufferBarrier.append(indirectBarrier);
3986 cmd.args.dispatchIndirect.indirectBuffer = indirectBufVk;
3987 cmd.args.dispatchIndirect.indirectBufferOffset = VkDeviceSize(indirectBufferOffset);
3993 VkShaderModuleCreateInfo shaderInfo = {};
3994 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3995 shaderInfo.codeSize = size_t(spirv.size());
3996 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3997 VkShaderModule shaderModule;
3998 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3999 if (err != VK_SUCCESS) {
4000 qWarning(
"Failed to create shader module: %d", err);
4001 return VK_NULL_HANDLE;
4003 return shaderModule;
4011 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
4012 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
4013 pipelineCacheInfo.initialDataSize = initialDataSize;
4014 pipelineCacheInfo.pInitialData = initialData;
4015 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
4016 if (err != VK_SUCCESS) {
4017 qWarning(
"Failed to create pipeline cache: %d", err);
4027 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
4028 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
4029 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
4030 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
4031 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
4033 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
4034 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
4037 VkWriteDescriptorSet writeInfo = {};
4038 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
4039 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
4040 writeInfo.dstBinding = uint32_t(b->binding);
4041 writeInfo.descriptorCount = 1;
4043 int bufferInfoIndex = -1;
4044 int imageInfoIndex = -1;
4047 case QRhiShaderResourceBinding::UniformBuffer:
4049 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
4050 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
4051 QRhiBuffer *buf = b->u.ubuf.buf;
4053 bd.ubuf.id = bufD->m_id;
4054 bd.ubuf.generation = bufD->generation;
4055 VkDescriptorBufferInfo bufInfo = {};
4056 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4057 bufInfo.offset = b->u.ubuf.offset;
4058 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
4060 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
4061 bufferInfoIndex = bufferInfos.size();
4062 bufferInfos.append(bufInfo);
4065 case QRhiShaderResourceBinding::SampledTexture:
4067 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
4068 writeInfo.descriptorCount = data->count;
4069 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
4070 ArrayOfImageDesc imageInfo(data->count);
4071 for (
int elem = 0; elem < data->count; ++elem) {
4074 bd.stex.d[elem].texId = texD->m_id;
4075 bd.stex.d[elem].texGeneration = texD->generation;
4076 bd.stex.d[elem].samplerId = samplerD->m_id;
4077 bd.stex.d[elem].samplerGeneration = samplerD->generation;
4078 imageInfo[elem].sampler = samplerD->sampler;
4079 imageInfo[elem].imageView = texD->imageView;
4080 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4082 bd.stex.count = data->count;
4083 imageInfoIndex = imageInfos.size();
4084 imageInfos.append(imageInfo);
4087 case QRhiShaderResourceBinding::Texture:
4089 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
4090 writeInfo.descriptorCount = data->count;
4091 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
4092 ArrayOfImageDesc imageInfo(data->count);
4093 for (
int elem = 0; elem < data->count; ++elem) {
4095 bd.stex.d[elem].texId = texD->m_id;
4096 bd.stex.d[elem].texGeneration = texD->generation;
4097 bd.stex.d[elem].samplerId = 0;
4098 bd.stex.d[elem].samplerGeneration = 0;
4099 imageInfo[elem].sampler = VK_NULL_HANDLE;
4100 imageInfo[elem].imageView = texD->imageView;
4101 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4103 bd.stex.count = data->count;
4104 imageInfoIndex = imageInfos.size();
4105 imageInfos.append(imageInfo);
4108 case QRhiShaderResourceBinding::Sampler:
4111 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
4112 bd.stex.d[0].texId = 0;
4113 bd.stex.d[0].texGeneration = 0;
4114 bd.stex.d[0].samplerId = samplerD->m_id;
4115 bd.stex.d[0].samplerGeneration = samplerD->generation;
4116 ArrayOfImageDesc imageInfo(1);
4117 imageInfo[0].sampler = samplerD->sampler;
4118 imageInfo[0].imageView = VK_NULL_HANDLE;
4119 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4120 imageInfoIndex = imageInfos.size();
4121 imageInfos.append(imageInfo);
4124 case QRhiShaderResourceBinding::ImageLoad:
4125 case QRhiShaderResourceBinding::ImageStore:
4126 case QRhiShaderResourceBinding::ImageLoadStore:
4129 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
4131 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
4132 bd.simage.id = texD->m_id;
4133 bd.simage.generation = texD->generation;
4134 ArrayOfImageDesc imageInfo(1);
4135 imageInfo[0].sampler = VK_NULL_HANDLE;
4136 imageInfo[0].imageView = view;
4137 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
4138 imageInfoIndex = imageInfos.size();
4139 imageInfos.append(imageInfo);
4143 case QRhiShaderResourceBinding::BufferLoad:
4144 case QRhiShaderResourceBinding::BufferStore:
4145 case QRhiShaderResourceBinding::BufferLoadStore:
4148 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
4149 bd.sbuf.id = bufD->m_id;
4150 bd.sbuf.generation = bufD->generation;
4151 VkDescriptorBufferInfo bufInfo = {};
4152 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
4153 bufInfo.offset = b->u.sbuf.offset;
4154 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
4155 bufferInfoIndex = bufferInfos.size();
4156 bufferInfos.append(bufInfo);
4163 writeInfos.append(writeInfo);
4164 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
4167 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
4168 const int bufferInfoIndex = infoIndices[i].first;
4169 const int imageInfoIndex = infoIndices[i].second;
4170 if (bufferInfoIndex >= 0)
4171 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
4172 else if (imageInfoIndex >= 0)
4173 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
4176 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
4180 VkAccessFlags access, VkPipelineStageFlags stage)
4183 Q_ASSERT(access && stage);
4191 if (s.access == access && s.stage == stage) {
4194 if (!accessIsWrite(access))
4198 VkBufferMemoryBarrier bufMemBarrier = {};
4199 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4200 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4201 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4202 bufMemBarrier.srcAccessMask = s.access;
4203 bufMemBarrier.dstAccessMask = access;
4204 bufMemBarrier.buffer = bufD->buffers[slot];
4205 bufMemBarrier.size = VK_WHOLE_SIZE;
4209 cmd.args.bufferBarrier.srcStageMask = s.stage;
4210 cmd.args.bufferBarrier.dstStageMask = stage;
4211 cmd.args.bufferBarrier.count = 1;
4212 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
4213 cbD->pools.bufferBarrier.append(bufMemBarrier);
4220 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
4223 Q_ASSERT(layout && access && stage);
4225 if (s.access == access && s.stage == stage && s.layout == layout) {
4226 if (!accessIsWrite(access))
4230 VkImageMemoryBarrier barrier = {};
4231 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4232 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
4233 barrier.subresourceRange.baseMipLevel = 0;
4234 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4235 barrier.subresourceRange.baseArrayLayer = 0;
4236 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4237 barrier.oldLayout = s.layout;
4238 barrier.newLayout = layout;
4239 barrier.srcAccessMask = s.access;
4240 barrier.dstAccessMask = access;
4241 barrier.image = texD->image;
4243 VkPipelineStageFlags srcStage = s.stage;
4246 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4250 cmd.args.imageBarrier.srcStageMask = srcStage;
4251 cmd.args.imageBarrier.dstStageMask = stage;
4252 cmd.args.imageBarrier.count = 1;
4253 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4254 cbD->pools.imageBarrier.append(barrier);
4265 VkImageMemoryBarrier barrier = {};
4266 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4267 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4268 barrier.subresourceRange.baseMipLevel = 0;
4269 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4270 barrier.subresourceRange.baseArrayLayer = 0;
4271 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4272 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4273 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4274 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4275 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4276 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4277 barrier.image = rbD->image;
4279 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4280 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4284 cmd.args.imageBarrier.srcStageMask = stages;
4285 cmd.args.imageBarrier.dstStageMask = stages;
4286 cmd.args.imageBarrier.count = 1;
4287 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4288 cbD->pools.imageBarrier.append(barrier);
4292 VkImageLayout oldLayout, VkImageLayout newLayout,
4293 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4294 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4295 int startLayer,
int layerCount,
4296 int startLevel,
int levelCount)
4299 VkImageMemoryBarrier barrier = {};
4300 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4301 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4302 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4303 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4304 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4305 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4306 barrier.oldLayout = oldLayout;
4307 barrier.newLayout = newLayout;
4308 barrier.srcAccessMask = srcAccess;
4309 barrier.dstAccessMask = dstAccess;
4310 barrier.image = image;
4314 cmd.args.imageBarrier.srcStageMask = srcStage;
4315 cmd.args.imageBarrier.dstStageMask = dstStage;
4316 cmd.args.imageBarrier.count = 1;
4317 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4318 cbD->pools.imageBarrier.append(barrier);
4323 VkDeviceSize size = 0;
4324 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4325 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4326 if (imageSizeBytes > 0)
4327 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4332 const QRhiTextureSubresourceUploadDescription &subresDesc,
4333 size_t *curOfs,
void *mp,
4334 BufferImageCopyList *copyInfos)
4336 qsizetype copySizeBytes = 0;
4337 qsizetype imageSizeBytes = 0;
4338 const void *src =
nullptr;
4339 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4340 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4342 VkBufferImageCopy copyInfo = {};
4343 copyInfo.bufferOffset = *curOfs;
4344 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4345 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4346 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4347 copyInfo.imageSubresource.layerCount = 1;
4348 copyInfo.imageExtent.depth = 1;
4350 copyInfo.imageOffset.z = uint32_t(layer);
4352 copyInfo.imageOffset.y = uint32_t(layer);
4354 const QByteArray rawData = subresDesc.data();
4355 const QPoint dp = subresDesc.destinationTopLeft();
4356 QImage image = subresDesc.image();
4357 if (!image.isNull()) {
4358 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4359 QSize size = image.size();
4360 src = image.constBits();
4363 int bpc = qMax(1, image.depth() / 8);
4365 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4366 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4367 const int sx = subresDesc.sourceTopLeft().x();
4368 const int sy = subresDesc.sourceTopLeft().y();
4369 if (!subresDesc.sourceSize().isEmpty())
4370 size = subresDesc.sourceSize();
4371 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4372 if (size.width() == image.width()) {
4375 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4376 copySizeBytes = size.height() * image.bytesPerLine();
4378 image = image.copy(sx, sy, size.width(), size.height());
4379 src = image.constBits();
4382 copySizeBytes = image.sizeInBytes();
4383 bpc = qMax(1, image.depth() / 8);
4384 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4387 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4389 copyInfo.imageOffset.x = dp.x();
4390 copyInfo.imageOffset.y = dp.y();
4391 copyInfo.imageExtent.width = uint32_t(size.width());
4392 copyInfo.imageExtent.height = uint32_t(size.height());
4393 copyInfos->append(copyInfo);
4394 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4395 copySizeBytes = imageSizeBytes = rawData.size();
4396 src = rawData.constData();
4397 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4398 const int subresw = size.width();
4399 const int subresh = size.height();
4400 if (!subresDesc.sourceSize().isEmpty())
4401 size = subresDesc.sourceSize();
4402 const int w = size.width();
4403 const int h = size.height();
4405 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4407 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4408 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4411 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4412 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4413 copyInfos->append(copyInfo);
4414 }
else if (!rawData.isEmpty()) {
4415 copySizeBytes = imageSizeBytes = rawData.size();
4416 src = rawData.constData();
4417 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4418 if (!subresDesc.sourceSize().isEmpty())
4419 size = subresDesc.sourceSize();
4420 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4422 quint32 bytesPerPixel = 0;
4423 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4424 if (subresDesc.dataStride() && bytesPerPixel)
4425 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4427 size = clampedSubResourceUploadSizeForSourceData(size, subresDesc.dataStride(),
4428 bytesPerPixel, rawData.size());
4430 if (!size.isEmpty()) {
4431 copyInfo.imageOffset.x = dp.x();
4432 copyInfo.imageOffset.y = dp.y();
4433 copyInfo.imageExtent.width = uint32_t(size.width());
4434 copyInfo.imageExtent.height = uint32_t(size.height());
4435 copyInfos->append(copyInfo);
4438 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4442 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4443 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4449 if (err == VK_ERROR_DEVICE_LOST)
4450 printDeviceLossErrorInfo();
4451 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4452 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4457#ifdef VK_EXT_device_fault
4458 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4461 VkDeviceFaultCountsEXT faultCounts{};
4462 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4463 faultCounts.pNext =
nullptr;
4465 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4466 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4467 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4470 faultCounts.vendorBinarySize = 0;
4472 const auto numAddressInfos = faultCounts.addressInfoCount;
4473 const auto addressInfos
4474 = q20::make_unique_for_overwrite<VkDeviceFaultAddressInfoEXT[]>(numAddressInfos);
4476 const auto numVendorInfos = faultCounts.vendorInfoCount;
4477 const auto vendorInfos
4478 = q20::make_unique_for_overwrite<VkDeviceFaultVendorInfoEXT[]>(numVendorInfos);
4480 VkDeviceFaultInfoEXT info{};
4481 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4482 info.pNext =
nullptr;
4483 info.pAddressInfos = numAddressInfos ? addressInfos.get() :
nullptr;
4484 info.pVendorInfos = numVendorInfos ? vendorInfos.get() :
nullptr;
4485 info.pVendorBinaryData =
nullptr;
4487 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4488 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4489 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4493 const char *desc = info.description[0] ? info.description :
"n/a";
4494 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4495 faultCounts.addressInfoCount,
4496 faultCounts.vendorInfoCount,
4497 (
unsigned long long)faultCounts.vendorBinarySize,
4500 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4501 const auto &a = addressInfos[i];
4502 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4504 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4505 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4506 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4507 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4508 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4509 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4510 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4511 default:
return "UNKNOWN";
4514 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4516 addressTypeString(a.addressType),
4517 (
unsigned long long)a.reportedAddress,
4518 (
unsigned long long)a.addressPrecision);
4521 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4522 const auto &v = vendorInfos[i];
4523 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4525 (
unsigned long long)v.vendorFaultCode,
4526 (
unsigned long long)v.vendorFaultData,
4540 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4542 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4543 bufD->pendingDynamicUpdates[i].clear();
4544 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4548 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4549 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4551 if (!bufD->stagingBuffers[currentFrameSlot]) {
4552 VkBufferCreateInfo bufferInfo = {};
4553 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4556 bufferInfo.size = bufD->m_size;
4557 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4559 VmaAllocationCreateInfo allocInfo = {};
4560 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4562 VmaAllocation allocation;
4563 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4564 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4565 if (err == VK_SUCCESS) {
4566 bufD->stagingAllocations[currentFrameSlot] = allocation;
4567 setAllocationName(allocation, bufD->name());
4569 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4570 printExtraErrorInfo(err);
4575 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4576 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4577 u.offset, u
.data.size());
4578 if (err != VK_SUCCESS) {
4579 qWarning(
"Failed to copy memory to buffer: %d", err);
4583 trackedBufferBarrier(cbD, bufD, 0,
4584 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4586 VkBufferCopy copyInfo = {};
4587 copyInfo.srcOffset = u.offset;
4588 copyInfo.dstOffset = u.offset;
4589 copyInfo.size = u
.data.size();
4593 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4594 cmd.args.copyBuffer.dst = bufD->buffers[0];
4595 cmd.args.copyBuffer.desc = copyInfo;
4604 bufD->lastActiveFrameSlot = currentFrameSlot;
4606 if (bufD->m_type == QRhiBuffer::Immutable) {
4609 e.lastActiveFrameSlot = currentFrameSlot;
4610 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4611 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4612 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4613 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4614 releaseQueue.append(e);
4618 if (bufD->m_type == QRhiBuffer::Dynamic) {
4620 u.result->data.resizeForOverwrite(u.readSize);
4621 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4622 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4623 u.offset, u.result->data.data(), u.readSize);
4624 if (err != VK_SUCCESS) {
4625 qWarning(
"Failed to copy memory from buffer: %d", err);
4626 u.result->data.clear();
4628 if (u.result->completed)
4629 u.result->completed();
4638 readback.activeFrameSlot = currentFrameSlot;
4639 readback.result = u.result;
4640 readback.byteSize = u.readSize;
4642 VkBufferCreateInfo bufferInfo = {};
4643 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4644 bufferInfo.size = readback.byteSize;
4645 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4647 VmaAllocationCreateInfo allocInfo = {};
4648 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4650 VmaAllocation allocation;
4651 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4652 if (err == VK_SUCCESS) {
4654 setAllocationName(allocation, bufD->name());
4656 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4657 printExtraErrorInfo(err);
4661 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4663 VkBufferCopy copyInfo = {};
4664 copyInfo.srcOffset = u.offset;
4665 copyInfo.size = u.readSize;
4669 cmd.args.copyBuffer.src = bufD->buffers[0];
4670 cmd.args.copyBuffer.dst = readback.stagingBuf;
4671 cmd.args.copyBuffer.desc = copyInfo;
4673 bufD->lastActiveFrameSlot = currentFrameSlot;
4675 activeBufferReadbacks.append(readback);
4685 VkDeviceSize stagingSize = 0;
4686 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4687 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4688 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4689 stagingSize += subresUploadByteSize(subresDesc);
4693 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4694 VkBufferCreateInfo bufferInfo = {};
4695 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4696 bufferInfo.size = stagingSize;
4697 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4699 VmaAllocationCreateInfo allocInfo = {};
4700 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4702 VmaAllocation allocation;
4703 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4704 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4705 if (err != VK_SUCCESS) {
4706 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4707 printExtraErrorInfo(err);
4710 utexD->stagingAllocations[currentFrameSlot] = allocation;
4711 setAllocationName(allocation, utexD->name());
4713 BufferImageCopyList copyInfos;
4716 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4717 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4718 if (err != VK_SUCCESS) {
4719 qWarning(
"Failed to map image data: %d", err);
4720 vmaDestroyBuffer(toVmaAllocator(allocator), utexD->stagingBuffers[currentFrameSlot], a);
4721 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4722 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4726 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4727 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4728 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4731 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4732 prepareUploadSubres(utexD, layer, level,
4733 subresDesc, &curOfs, mp, ©Infos);
4737 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4738 vmaUnmapMemory(toVmaAllocator(allocator), a);
4740 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4741 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4743 if (!copyInfos.isEmpty()) {
4746 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4747 cmd.args.copyBufferToImage.dst = utexD->image;
4748 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4749 cmd.args.copyBufferToImage.count = copyInfos.size();
4750 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4751 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4757 e.lastActiveFrameSlot = currentFrameSlot;
4758 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4759 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4760 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4761 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4762 releaseQueue.append(e);
4767 utexD->lastActiveFrameSlot = currentFrameSlot;
4771 qWarning(
"Texture copy with matching source and destination is not supported");
4776 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4777 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4779 VkImageCopy region = {};
4780 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4781 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4782 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4783 region.srcSubresource.layerCount = 1;
4785 region.srcOffset.x = u.desc.sourceTopLeft().x();
4786 region.srcOffset.y = u.desc.sourceTopLeft().y();
4788 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4790 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4791 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4792 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4793 region.dstSubresource.layerCount = 1;
4795 region.dstOffset.x = u.desc.destinationTopLeft().x();
4796 region.dstOffset.y = u.desc.destinationTopLeft().y();
4798 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4800 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4801 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4802 region.extent.width = uint32_t(copySize.width());
4803 region.extent.height = uint32_t(copySize.height());
4804 region.extent.depth = 1;
4806 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4807 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4808 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4809 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4813 cmd.args.copyImage.src = srcD->image;
4814 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4815 cmd.args.copyImage.dst = dstD->image;
4816 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4817 cmd.args.copyImage.desc = region;
4819 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4822 readback.activeFrameSlot = currentFrameSlot;
4823 readback.desc = u.rb;
4824 readback.result = u.result;
4830 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4831 qWarning(
"Multisample texture cannot be read back");
4834 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4835 if (u.rb.rect().isValid())
4836 readback.rect = u.rb.rect();
4838 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4839 readback.format = texD->m_format;
4840 texD->lastActiveFrameSlot = currentFrameSlot;
4845 qWarning(
"Swapchain does not support readback");
4848 if (u.rb.rect().isValid())
4849 readback.rect = u.rb.rect();
4851 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4852 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4853 if (readback.format == QRhiTexture::UnknownFormat)
4859 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4862 VkBufferCreateInfo bufferInfo = {};
4863 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4864 bufferInfo.size = readback.byteSize;
4865 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4867 VmaAllocationCreateInfo allocInfo = {};
4868 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4870 VmaAllocation allocation;
4871 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4872 if (err == VK_SUCCESS) {
4874 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4876 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4877 printExtraErrorInfo(err);
4882 VkBufferImageCopy copyDesc = {};
4883 copyDesc.bufferOffset = 0;
4884 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4885 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4886 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4887 copyDesc.imageSubresource.layerCount = 1;
4888 copyDesc.imageOffset.x = readback.rect.x();
4889 copyDesc.imageOffset.y = readback.rect.y();
4891 copyDesc.imageOffset.z = u.rb.layer();
4892 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4893 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4894 copyDesc.imageExtent.depth = 1;
4897 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4898 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4901 cmd.args.copyImageToBuffer.src = texD->image;
4902 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4903 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4904 cmd.args.copyImageToBuffer.desc = copyDesc;
4908 VkImage image = imageRes.image;
4911 qWarning(
"Attempted to read back undefined swapchain image content, "
4912 "results are undefined. (do a render pass first)");
4914 subresourceBarrier(cbD, image,
4915 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4916 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4917 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4925 cmd.args.copyImageToBuffer.src = image;
4926 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4927 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4928 cmd.args.copyImageToBuffer.desc = copyDesc;
4931 activeTextureReadbacks.append(readback);
4934 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4935 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4936 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4937 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4939 VkImageLayout origLayout = utexD->usageState.layout;
4940 VkAccessFlags origAccess = utexD->usageState.access;
4941 VkPipelineStageFlags origStage = utexD->usageState.stage;
4943 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4945 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4946 int w = utexD->m_pixelSize.width();
4947 int h = utexD->m_pixelSize.height();
4948 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4949 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4951 subresourceBarrier(cbD, utexD->image,
4952 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4953 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4954 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4958 subresourceBarrier(cbD, utexD->image,
4959 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4960 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4961 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4966 subresourceBarrier(cbD, utexD->image,
4967 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4968 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4969 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4973 VkImageBlit region = {};
4974 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4975 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4976 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4977 region.srcSubresource.layerCount = 1;
4979 region.srcOffsets[1].x = qMax(1, w);
4980 region.srcOffsets[1].y = qMax(1, h);
4981 region.srcOffsets[1].z = qMax(1, depth);
4983 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4984 region.dstSubresource.mipLevel = uint32_t(level);
4985 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4986 region.dstSubresource.layerCount = 1;
4988 region.dstOffsets[1].x = qMax(1, w >> 1);
4989 region.dstOffsets[1].y = qMax(1, h >> 1);
4990 region.dstOffsets[1].z = qMax(1, depth >> 1);
4994 cmd.args.blitImage.src = utexD->image;
4995 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4996 cmd.args.blitImage.dst = utexD->image;
4997 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4998 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4999 cmd.args.blitImage.desc = region;
5006 if (utexD->mipLevelCount > 1) {
5007 subresourceBarrier(cbD, utexD->image,
5008 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
5009 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
5010 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5012 0,
int(utexD->mipLevelCount) - 1);
5013 subresourceBarrier(cbD, utexD->image,
5014 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
5015 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
5016 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
5018 int(utexD->mipLevelCount) - 1, 1);
5021 utexD->lastActiveFrameSlot = currentFrameSlot;
5030 if (bufD->pendingDynamicUpdates[slot].isEmpty())
5033 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
5035 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
5039 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
5040 if (err != VK_SUCCESS) {
5041 qWarning(
"Failed to map buffer: %d", err);
5044 quint32 changeBegin = UINT32_MAX;
5045 quint32 changeEnd = 0;
5046 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
5047 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
5048 if (u.offset < changeBegin)
5049 changeBegin = u.offset;
5050 if (u.offset + u.data.size() > changeEnd)
5051 changeEnd = u.offset + u.data.size();
5053 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
5054 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
5055 vmaUnmapMemory(toVmaAllocator(allocator), a);
5057 bufD->pendingDynamicUpdates[slot].clear();
5063 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
5064 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
5070 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
5071 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
5072 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
5077 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
5078 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
5080 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
5081 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
5082 if (e.texture.extraImageViews[i])
5083 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
5089 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
5094 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
5096 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
5099 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
5100 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
5103 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
5104 if (e.shaderResourceBindings.poolIndex >= 0) {
5105 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
5106 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
5113 qrhivk_releaseRenderBuffer(e, dev,
df);
5119 qrhivk_releaseSampler(e, dev,
df);
5122 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
5124 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
5125 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
5127 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
5128 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
5129 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
5132 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
5135 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
5137 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
5138 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
5144 releaseQueue.removeAt(i);
5151 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5153 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
5155 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5156 readback.result->format = readback.format;
5157 readback.result->pixelSize = readback.rect.size();
5158 readback.result->data.resizeForOverwrite(readback.byteSize);
5159 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5160 toVmaAllocation(readback.stagingAlloc),
5161 0, readback.result->data.data(), readback.byteSize);
5162 if (err != VK_SUCCESS) {
5163 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
5164 readback.result->data.clear();
5167 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5169 if (readback.result->completed)
5170 completedCallbacks.append(readback.result->completed);
5172 activeTextureReadbacks.remove(i);
5176 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
5178 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
5179 readback.result->data.resizeForOverwrite(readback.byteSize);
5180 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
5181 toVmaAllocation(readback.stagingAlloc),
5182 0, readback.result->data.data(), readback.byteSize);
5183 if (err != VK_SUCCESS) {
5184 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
5185 readback.result->data.clear();
5188 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
5190 if (readback.result->completed)
5191 completedCallbacks.append(readback.result->completed);
5193 activeBufferReadbacks.remove(i);
5197 for (
const auto &f : completedCallbacks)
5204} qvk_sampleCounts[] = {
5206 { VK_SAMPLE_COUNT_1_BIT, 1 },
5207 { VK_SAMPLE_COUNT_2_BIT, 2 },
5208 { VK_SAMPLE_COUNT_4_BIT, 4 },
5209 { VK_SAMPLE_COUNT_8_BIT, 8 },
5210 { VK_SAMPLE_COUNT_16_BIT, 16 },
5211 { VK_SAMPLE_COUNT_32_BIT, 32 },
5212 { VK_SAMPLE_COUNT_64_BIT, 64 }
5217 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
5218 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
5219 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
5220 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
5223 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5224 if ((color & qvk_sampleCount.mask)
5225 && (depth & qvk_sampleCount.mask)
5226 && (stencil & qvk_sampleCount.mask))
5228 result.append(qvk_sampleCount.count);
5237 const int s = effectiveSampleCount(sampleCount);
5239 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5240 if (qvk_sampleCount.count == s)
5241 return qvk_sampleCount.mask;
5244 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
5249 QList<QSize> result;
5250#ifdef VK_KHR_fragment_shading_rate
5251 sampleCount = qMax(1, sampleCount);
5252 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
5253 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5254 if (qvk_sampleCount.count == sampleCount) {
5255 mask = qvk_sampleCount.mask;
5259 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
5260 if (s.sampleCounts & mask)
5261 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
5264 Q_UNUSED(sampleCount);
5265 result.append(QSize(1, 1));
5272 cbD->passResTrackers.emplace_back();
5277 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5284 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5288 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5289 1, &cmd.args.copyBuffer.desc);
5292 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5293 cmd.args.copyBufferToImage.dstLayout,
5294 uint32_t(cmd.args.copyBufferToImage.count),
5295 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5298 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5299 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5300 1, &cmd.args.copyImage.desc);
5303 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5304 cmd.args.copyImageToBuffer.dst,
5305 1, &cmd.args.copyImageToBuffer.desc);
5308 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5309 0, 0,
nullptr, 0,
nullptr,
5310 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5313 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5315 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5319 const auto &barrier = cmd.args.imageAndBufferBarrier;
5320 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5321 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5322 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5323 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5324 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5326 barrier.bufferCount, bufferBarrierData,
5327 barrier.imageCount, imageBarrierData);
5330 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5331 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5332 1, &cmd.args.blitImage.desc,
5333 cmd.args.blitImage.filter);
5336 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5337 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5338 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5339 : VK_SUBPASS_CONTENTS_INLINE);
5342 VkMemoryBarrier barrier = {};
5343 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5344 barrier.pNext =
nullptr;
5345 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5346 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5347 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5353 df->vkCmdEndRenderPass(cbD->cb);
5356 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5360 const uint32_t *offsets =
nullptr;
5361 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5362 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5363 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5364 cmd.args.bindDescriptorSet.pipelineLayout,
5365 0, 1, &cmd.args.bindDescriptorSet.descSet,
5366 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5371 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5372 uint32_t(cmd.args.bindVertexBuffer.count),
5373 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5374 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5377 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5378 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5381 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5384 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5387 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5390 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5393 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5394 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5397 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5398 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5399 cmd.args.drawIndexed.firstInstance);
5402 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5403 cmd.args.drawIndirect.indirectBufferOffset,
5404 cmd.args.drawIndirect.drawCount,
5405 cmd.args.drawIndirect.stride);
5408 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5409 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5410 cmd.args.drawIndexedIndirect.drawCount,
5411 cmd.args.drawIndexedIndirect.stride);
5413#ifdef VK_VERSION_1_2
5414 case QVkCommandBuffer::Command::DrawIndirectCount:
5415 vkCmdDrawIndirectCount(cbD->cb,
5416 cmd.args.drawIndirectCount.indirectBuffer,
5417 cmd.args.drawIndirectCount.indirectBufferOffset,
5418 cmd.args.drawIndirectCount.countBuffer,
5419 cmd.args.drawIndirectCount.countBufferOffset,
5420 cmd.args.drawIndirectCount.maxDrawCount,
5421 cmd.args.drawIndirectCount.stride);
5423 case QVkCommandBuffer::Command::DrawIndexedIndirectCount:
5424 vkCmdDrawIndexedIndirectCount(cbD->cb,
5425 cmd.args.drawIndexedIndirectCount.indirectBuffer,
5426 cmd.args.drawIndexedIndirectCount.indirectBufferOffset,
5427 cmd.args.drawIndexedIndirectCount.countBuffer,
5428 cmd.args.drawIndexedIndirectCount.countBufferOffset,
5429 cmd.args.drawIndexedIndirectCount.maxDrawCount,
5430 cmd.args.drawIndexedIndirectCount.stride);
5434#ifdef VK_EXT_debug_utils
5435 cmd.args.debugMarkerBegin.label.pLabelName =
5436 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5437 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5441#ifdef VK_EXT_debug_utils
5442 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5446#ifdef VK_EXT_debug_utils
5447 cmd.args.debugMarkerInsert.label.pLabelName =
5448 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5449 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5456 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5459 df->vkCmdDispatchIndirect(cbD->cb,
5460 cmd.args.dispatchIndirect.indirectBuffer,
5461 cmd.args.dispatchIndirect.indirectBufferOffset);
5464 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5468#ifdef VK_KHR_fragment_shading_rate
5469 VkFragmentShadingRateCombinerOpKHR op[2] = {
5470 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5471 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5473 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5474 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5487 case QRhiPassResourceTracker::BufIndirectDraw:
5488 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5489 case QRhiPassResourceTracker::BufVertexInput:
5490 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5491 case QRhiPassResourceTracker::BufIndexRead:
5492 return VK_ACCESS_INDEX_READ_BIT;
5493 case QRhiPassResourceTracker::BufUniformRead:
5494 return VK_ACCESS_UNIFORM_READ_BIT;
5495 case QRhiPassResourceTracker::BufStorageLoad:
5496 return VK_ACCESS_SHADER_READ_BIT;
5497 case QRhiPassResourceTracker::BufStorageStore:
5498 return VK_ACCESS_SHADER_WRITE_BIT;
5499 case QRhiPassResourceTracker::BufStorageLoadStore:
5500 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5511 case QRhiPassResourceTracker::BufIndirectDrawStage:
5512 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5513 case QRhiPassResourceTracker::BufVertexInputStage:
5514 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5515 case QRhiPassResourceTracker::BufVertexStage:
5516 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5517 case QRhiPassResourceTracker::BufTCStage:
5518 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5519 case QRhiPassResourceTracker::BufTEStage:
5520 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5521 case QRhiPassResourceTracker::BufFragmentStage:
5522 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5523 case QRhiPassResourceTracker::BufComputeStage:
5524 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5525 case QRhiPassResourceTracker::BufGeometryStage:
5526 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5537 u.access = VkAccessFlags(usage
.access);
5538 u.stage = VkPipelineStageFlags(usage
.stage);
5545 case QRhiPassResourceTracker::TexSample:
5546 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5547 case QRhiPassResourceTracker::TexColorOutput:
5548 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5549 case QRhiPassResourceTracker::TexDepthOutput:
5550 case QRhiPassResourceTracker::TexDepthResolveOutput:
5551 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5552 case QRhiPassResourceTracker::TexStorageLoad:
5553 case QRhiPassResourceTracker::TexStorageStore:
5554 case QRhiPassResourceTracker::TexStorageLoadStore:
5555 return VK_IMAGE_LAYOUT_GENERAL;
5556 case QRhiPassResourceTracker::TexShadingRate:
5557#ifdef VK_KHR_fragment_shading_rate
5558 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5560 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5566 return VK_IMAGE_LAYOUT_GENERAL;
5572 case QRhiPassResourceTracker::TexSample:
5573 return VK_ACCESS_SHADER_READ_BIT;
5574 case QRhiPassResourceTracker::TexColorOutput:
5575 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5576 case QRhiPassResourceTracker::TexDepthOutput:
5577 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5578 case QRhiPassResourceTracker::TexDepthResolveOutput:
5581 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5582 case QRhiPassResourceTracker::TexStorageLoad:
5583 return VK_ACCESS_SHADER_READ_BIT;
5584 case QRhiPassResourceTracker::TexStorageStore:
5585 return VK_ACCESS_SHADER_WRITE_BIT;
5586 case QRhiPassResourceTracker::TexStorageLoadStore:
5587 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5600 case QRhiPassResourceTracker::TexVertexStage:
5601 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5602 case QRhiPassResourceTracker::TexTCStage:
5603 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5604 case QRhiPassResourceTracker::TexTEStage:
5605 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5606 case QRhiPassResourceTracker::TexFragmentStage:
5607 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5608 case QRhiPassResourceTracker::TexColorOutputStage:
5609 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5610 case QRhiPassResourceTracker::TexDepthOutputStage:
5611 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5612 case QRhiPassResourceTracker::TexComputeStage:
5613 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5614 case QRhiPassResourceTracker::TexGeometryStage:
5615 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5626 u.layout = VkImageLayout(usage
.layout);
5627 u.access = VkAccessFlags(usage
.access);
5628 u.stage = VkPipelineStageFlags(usage
.stage);
5639 const VkAccessFlags newAccess = toVkAccess(access);
5640 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5641 if (u.access == newAccess && u.stage == newStage) {
5642 if (!accessIsWrite(newAccess))
5646 u.access = newAccess;
5656 const VkAccessFlags newAccess = toVkAccess(access);
5657 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5658 const VkImageLayout newLayout = toVkLayout(access);
5659 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5660 if (!accessIsWrite(newAccess))
5664 u.layout = newLayout;
5665 u.access = newAccess;
5674 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5675 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5676 VkAccessFlags access = toVkAccess(trackedB.access);
5677 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5678 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5681 if (s.access == access && s.stage == stage) {
5682 if (!accessIsWrite(access))
5685 VkBufferMemoryBarrier bufMemBarrier = {};
5686 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5687 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5688 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5689 bufMemBarrier.srcAccessMask = s.access;
5690 bufMemBarrier.dstAccessMask = access;
5691 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5692 bufMemBarrier.size = VK_WHOLE_SIZE;
5693 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5699 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5700 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5701 VkImageLayout layout = toVkLayout(trackedT.access);
5702 VkAccessFlags access = toVkAccess(trackedT.access);
5703 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5704 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5705 if (s.access == access && s.stage == stage && s.layout == layout) {
5706 if (!accessIsWrite(access))
5709 VkImageMemoryBarrier barrier = {};
5710 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5711 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5712 barrier.subresourceRange.baseMipLevel = 0;
5713 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5714 barrier.subresourceRange.baseArrayLayer = 0;
5715 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5716 barrier.oldLayout = s.layout;
5717 barrier.newLayout = layout;
5718 barrier.srcAccessMask = s.access;
5719 barrier.dstAccessMask = access;
5720 barrier.image = texD->image;
5721 VkPipelineStageFlags srcStage = s.stage;
5724 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5725 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5734 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5735 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5736 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5738 qWarning(
"Physical device surface queries not available");
5742 return new QVkSwapChain(
this);
5745QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5747 return new QVkBuffer(
this, type, usage, size);
5752 return int(ubufAlign);
5775 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
5776 0.0f, -1.0f, 0.0f, 0.0f,
5777 0.0f, 0.0f, 0.5f, 0.5f,
5778 0.0f, 0.0f, 0.0f, 1.0f);
5787 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5788 if (!physDevFeatures.textureCompressionBC)
5792 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5793 if (!physDevFeatures.textureCompressionETC2)
5797 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5798 if (!physDevFeatures.textureCompressionASTC_LDR)
5802 VkFormat vkformat = toVkTextureFormat(format, flags);
5803 VkFormatProperties props;
5804 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5805 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5811 case QRhi::MultisampleTexture:
5813 case QRhi::MultisampleRenderBuffer:
5815 case QRhi::DebugMarkers:
5816 return caps.debugUtils;
5817 case QRhi::Timestamps:
5818 return timestampValidBits != 0;
5819 case QRhi::Instancing:
5821 case QRhi::CustomInstanceStepRate:
5822 return caps.vertexAttribDivisor;
5823 case QRhi::PrimitiveRestart:
5825 case QRhi::NonDynamicUniformBuffers:
5827 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5829 case QRhi::NPOTTextureRepeat:
5831 case QRhi::RedOrAlpha8IsRed:
5833 case QRhi::ElementIndexUint:
5836 return caps.compute;
5837 case QRhi::WideLines:
5838 return caps.wideLines;
5839 case QRhi::VertexShaderPointSize:
5841 case QRhi::BaseVertex:
5843 case QRhi::BaseInstance:
5845 case QRhi::TriangleFanTopology:
5847 case QRhi::ReadBackNonUniformBuffer:
5849 case QRhi::ReadBackNonBaseMipLevel:
5851 case QRhi::TexelFetch:
5853 case QRhi::RenderToNonBaseMipLevel:
5855 case QRhi::IntAttributes:
5857 case QRhi::ScreenSpaceDerivatives:
5859 case QRhi::ReadBackAnyTextureFormat:
5861 case QRhi::PipelineCacheDataLoadSave:
5863 case QRhi::ImageDataStride:
5865 case QRhi::RenderBufferImport:
5867 case QRhi::ThreeDimensionalTextures:
5869 case QRhi::RenderTo3DTextureSlice:
5870 return caps.texture3DSliceAs2D;
5871 case QRhi::TextureArrays:
5873 case QRhi::Tessellation:
5874 return caps.tessellation;
5875 case QRhi::GeometryShader:
5876 return caps.geometryShader;
5877 case QRhi::TextureArrayRange:
5879 case QRhi::NonFillPolygonMode:
5880 return caps.nonFillPolygonMode;
5881 case QRhi::OneDimensionalTextures:
5883 case QRhi::OneDimensionalTextureMipmaps:
5885 case QRhi::HalfAttributes:
5887 case QRhi::RenderToOneDimensionalTexture:
5889 case QRhi::ThreeDimensionalTextureMipmaps:
5891 case QRhi::MultiView:
5892 return caps.multiView;
5893 case QRhi::TextureViewFormat:
5895 case QRhi::ResolveDepthStencil:
5896 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5897 case QRhi::VariableRateShading:
5898 return caps.renderPass2KHR && caps.perDrawShadingRate;
5899 case QRhi::VariableRateShadingMap:
5900 case QRhi::VariableRateShadingMapWithTexture:
5901 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5902 case QRhi::PerRenderTargetBlending:
5903 case QRhi::SampleVariables:
5905 case QRhi::InstanceIndexIncludesBaseInstance:
5907 case QRhi::DepthClamp:
5908 return caps.depthClamp;
5909 case QRhi::DrawIndirect:
5911 case QRhi::DrawIndirectMulti:
5912 return caps.drawIndirectMulti;
5913 case QRhi::ShaderDrawParameters:
5914 return caps.shaderDrawParameters;
5915 case QRhi::DispatchIndirect:
5917 case QRhi::DrawIndirectCount:
5918 return caps.drawIndirectCount;
5920 Q_UNREACHABLE_RETURN(
false);
5927 case QRhi::TextureSizeMin:
5929 case QRhi::TextureSizeMax:
5930 return int(physDevProperties.limits.maxImageDimension2D);
5931 case QRhi::MaxColorAttachments:
5932 return int(physDevProperties.limits.maxColorAttachments);
5933 case QRhi::FramesInFlight:
5935 case QRhi::MaxAsyncReadbackFrames:
5937 case QRhi::MaxThreadGroupsPerDimension:
5938 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5939 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5940 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5941 case QRhi::MaxThreadsPerThreadGroup:
5942 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5943 case QRhi::MaxThreadGroupX:
5944 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5945 case QRhi::MaxThreadGroupY:
5946 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5947 case QRhi::MaxThreadGroupZ:
5948 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5949 case QRhi::TextureArraySizeMax:
5950 return int(physDevProperties.limits.maxImageArrayLayers);
5951 case QRhi::MaxUniformBufferRange:
5952 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5953 case QRhi::MaxVertexInputs:
5954 return physDevProperties.limits.maxVertexInputAttributes;
5955 case QRhi::MaxVertexOutputs:
5956 return physDevProperties.limits.maxVertexOutputComponents / 4;
5957 case QRhi::MaxVertexStorageBuffers:
5958 case QRhi::MaxFragmentStorageBuffers:
5959 return int(physDevProperties.limits.maxPerStageDescriptorStorageBuffers);
5960 case QRhi::ShadingRateImageTileSize:
5961 return caps.imageBasedShadingRateTileSize;
5963 Q_UNREACHABLE_RETURN(0);
5969 return &nativeHandlesStruct;
5974 return driverInfoStruct;
5980 result.totalPipelineCreationTime = totalPipelineCreationTime();
5982 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5983 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5985 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5986 for (uint32_t i = 0; i < count; ++i) {
5987 const VmaStatistics &stats(budgets[i].statistics);
5988 result.blockCount += stats.blockCount;
5989 result.allocCount += stats.allocationCount;
5990 result.usedBytes += stats.allocationBytes;
5991 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
6005 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
6009 waitSemaphoresForQueueSubmit.clear();
6010 if (sp->waitSemaphoreCount)
6011 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
6013 signalSemaphoresForQueueSubmit.clear();
6014 if (sp->signalSemaphoreCount)
6015 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
6017 waitSemaphoresForPresent.clear();
6018 if (sp->presentWaitSemaphoreCount)
6019 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
6049 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
6052 size_t dataSize = 0;
6053 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
6054 if (err != VK_SUCCESS) {
6055 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
6056 return QByteArray();
6059 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6060 data.resize(dataOffset + dataSize);
6061 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
6062 if (err != VK_SUCCESS) {
6063 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
6064 return QByteArray();
6068 header.rhiId = pipelineCacheRhiId();
6069 header.arch = quint32(
sizeof(
void*));
6070 header.driverVersion = physDevProperties.driverVersion;
6071 header.vendorId = physDevProperties.vendorID;
6072 header.deviceId = physDevProperties.deviceID;
6073 header.dataSize = quint32(dataSize);
6074 header.uuidSize = VK_UUID_SIZE;
6075 header.reserved = 0;
6076 memcpy(data.data(), &header, headerSize);
6077 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
6088 if (data.size() < qsizetype(headerSize)) {
6089 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
6093 memcpy(&header, data.constData(), headerSize);
6095 const quint32 rhiId = pipelineCacheRhiId();
6096 if (header.rhiId != rhiId) {
6097 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
6098 rhiId, header.rhiId);
6101 const quint32 arch = quint32(
sizeof(
void*));
6102 if (header.arch != arch) {
6103 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
6107 if (header.driverVersion != physDevProperties.driverVersion) {
6108 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
6109 physDevProperties.driverVersion, header.driverVersion);
6112 if (header.vendorId != physDevProperties.vendorID) {
6113 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
6114 physDevProperties.vendorID, header.vendorId);
6117 if (header.deviceId != physDevProperties.deviceID) {
6118 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
6119 physDevProperties.deviceID, header.deviceId);
6122 if (header.uuidSize != VK_UUID_SIZE) {
6123 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
6124 quint32(VK_UUID_SIZE), header.uuidSize);
6128 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
6129 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
6132 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
6133 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
6137 const size_t dataOffset = headerSize + VK_UUID_SIZE;
6138 if (quint64(data.size()) < quint64(dataOffset) + header.dataSize) {
6139 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
6143 if (pipelineCache) {
6144 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
6145 pipelineCache = VK_NULL_HANDLE;
6148 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
6149 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
6150 int(header.dataSize));
6152 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
6156QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
6157 int sampleCount, QRhiRenderBuffer::Flags flags,
6158 QRhiTexture::Format backingFormatHint)
6160 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
6164 const QSize &pixelSize,
int depth,
int arraySize,
6165 int sampleCount, QRhiTexture::Flags flags)
6167 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
6171 QRhiSampler::Filter mipmapMode,
6172 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
6174 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
6179 return new QVkShadingRateMap(
this);
6183 QRhiTextureRenderTarget::Flags flags)
6190 return new QVkGraphicsPipeline(
this);
6195 return new QVkComputePipeline(
this);
6200 return new QVkShaderResourceBindings(
this);
6206 Q_ASSERT(psD->pipeline);
6210 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
6212 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
6216 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
6217 cmd.args.bindPipeline.pipeline = psD->pipeline;
6220 cbD->currentGraphicsPipeline = ps;
6221 cbD->currentComputePipeline =
nullptr;
6222 cbD->currentPipelineGeneration = psD->generation;
6228 psD->lastActiveFrameSlot = currentFrameSlot;
6232 int dynamicOffsetCount,
6233 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
6243 srb = gfxPsD->m_shaderResourceBindings;
6245 srb = compPsD->m_shaderResourceBindings;
6249 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
6250 bool rewriteDescSet =
false;
6251 bool addWriteBarrier =
false;
6252 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
6253 VkPipelineStageFlags writeBarrierDstStageMask = 0;
6257 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
6258 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
6261 case QRhiShaderResourceBinding::UniformBuffer:
6264 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
6265 sanityCheckResourceOwnership(bufD);
6267 if (bufD->m_type == QRhiBuffer::Dynamic)
6270 bufD->lastActiveFrameSlot = currentFrameSlot;
6271 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6273 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
6279 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
6280 rewriteDescSet =
true;
6281 bd.ubuf.id = bufD->m_id;
6282 bd.ubuf.generation = bufD->generation;
6286 case QRhiShaderResourceBinding::SampledTexture:
6287 case QRhiShaderResourceBinding::Texture:
6288 case QRhiShaderResourceBinding::Sampler:
6290 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
6291 if (bd.stex.count != data->count) {
6292 bd.stex.count = data->count;
6293 rewriteDescSet =
true;
6295 for (
int elem = 0; elem < data->count; ++elem) {
6301 Q_ASSERT(texD || samplerD);
6302 sanityCheckResourceOwnership(texD);
6303 sanityCheckResourceOwnership(samplerD);
6305 texD->lastActiveFrameSlot = currentFrameSlot;
6311 samplerD->lastActiveFrameSlot = currentFrameSlot;
6312 const quint64 texId = texD ? texD->m_id : 0;
6313 const uint texGen = texD ? texD->generation : 0;
6314 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6315 const uint samplerGen = samplerD ? samplerD->generation : 0;
6316 if (texGen != bd.stex.d[elem].texGeneration
6317 || texId != bd.stex.d[elem].texId
6318 || samplerGen != bd.stex.d[elem].samplerGeneration
6319 || samplerId != bd.stex.d[elem].samplerId)
6321 rewriteDescSet =
true;
6322 bd.stex.d[elem].texId = texId;
6323 bd.stex.d[elem].texGeneration = texGen;
6324 bd.stex.d[elem].samplerId = samplerId;
6325 bd.stex.d[elem].samplerGeneration = samplerGen;
6330 case QRhiShaderResourceBinding::ImageLoad:
6331 case QRhiShaderResourceBinding::ImageStore:
6332 case QRhiShaderResourceBinding::ImageLoadStore:
6335 sanityCheckResourceOwnership(texD);
6336 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6337 texD->lastActiveFrameSlot = currentFrameSlot;
6339 if (b->type == QRhiShaderResourceBinding::ImageLoad)
6341 else if (b->type == QRhiShaderResourceBinding::ImageStore)
6346 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6347 const auto prevAccess = passResTracker.textures().find(texD);
6348 if (prevAccess != passResTracker.textures().end()) {
6352 addWriteBarrier =
true;
6353 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6354 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6362 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6363 rewriteDescSet =
true;
6364 bd.simage.id = texD->m_id;
6365 bd.simage.generation = texD->generation;
6369 case QRhiShaderResourceBinding::BufferLoad:
6370 case QRhiShaderResourceBinding::BufferStore:
6371 case QRhiShaderResourceBinding::BufferLoadStore:
6374 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6375 sanityCheckResourceOwnership(bufD);
6377 if (bufD->m_type == QRhiBuffer::Dynamic)
6380 bufD->lastActiveFrameSlot = currentFrameSlot;
6382 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6384 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6389 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6390 const auto prevAccess = passResTracker.buffers().find(bufD);
6391 if (prevAccess != passResTracker.buffers().end()) {
6395 addWriteBarrier =
true;
6396 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6397 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6400 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6404 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6405 rewriteDescSet =
true;
6406 bd.sbuf.id = bufD->m_id;
6407 bd.sbuf.generation = bufD->generation;
6417 if (addWriteBarrier) {
6419 VkMemoryBarrier barrier = {};
6420 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6421 barrier.pNext =
nullptr;
6422 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6423 barrier.srcAccessMask = barrier.dstAccessMask;
6424 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6431 cmd.args.memoryBarrier.dependencyFlags = 0;
6432 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6433 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6434 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6435 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6441 updateShaderResourceBindings(srb);
6445 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6446 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6448 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6450 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6451 QVarLengthArray<uint32_t, 4> dynOfs;
6456 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6457 uint32_t offset = 0;
6458 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6459 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6460 if (bindingOffsetPair.first == bindingNumber) {
6461 offset = bindingOffsetPair.second;
6465 dynOfs.append(offset);
6469 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6470 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6471 gfxPsD ? gfxPsD->layout : compPsD->layout,
6472 0, 1, &srbD->descSets[currentFrameSlot],
6473 uint32_t(dynOfs.size()),
6474 dynOfs.size() ? dynOfs.constData() :
nullptr);
6478 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6479 : VK_PIPELINE_BIND_POINT_COMPUTE;
6480 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6481 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6482 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6483 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6484 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6488 cbD->currentGraphicsSrb = srb;
6489 cbD->currentComputeSrb =
nullptr;
6491 cbD->currentGraphicsSrb =
nullptr;
6492 cbD->currentComputeSrb = srb;
6494 cbD->currentSrbGeneration = srbD->generation;
6495 cbD->currentDescSetSlot = currentFrameSlot;
6498 srbD->lastActiveFrameSlot = currentFrameSlot;
6502 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6503 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6509 bool needsBindVBuf =
false;
6510 for (
int i = 0; i < bindingCount; ++i) {
6511 const int inputSlot = startBinding + i;
6513 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6514 bufD->lastActiveFrameSlot = currentFrameSlot;
6515 if (bufD->m_type == QRhiBuffer::Dynamic)
6518 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6519 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6520 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6522 needsBindVBuf =
true;
6523 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6524 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6528 if (needsBindVBuf) {
6529 QVarLengthArray<VkBuffer, 4> bufs;
6530 QVarLengthArray<VkDeviceSize, 4> ofs;
6531 for (
int i = 0; i < bindingCount; ++i) {
6533 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6534 bufs.append(bufD->buffers[slot]);
6535 ofs.append(bindings[i].second);
6542 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6543 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6547 cmd.args.bindVertexBuffer.startBinding = startBinding;
6548 cmd.args.bindVertexBuffer.count = bufs.size();
6549 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6550 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6551 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6552 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6558 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6559 ibufD->lastActiveFrameSlot = currentFrameSlot;
6560 if (ibufD->m_type == QRhiBuffer::Dynamic)
6563 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6564 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6565 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6566 : VK_INDEX_TYPE_UINT32;
6568 if (cbD->currentIndexBuffer != vkindexbuf
6569 || cbD->currentIndexOffset != indexOffset
6570 || cbD->currentIndexFormat != type)
6572 cbD->currentIndexBuffer = vkindexbuf;
6573 cbD->currentIndexOffset = indexOffset;
6574 cbD->currentIndexFormat = type;
6577 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6581 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6582 cmd.args.bindIndexBuffer.ofs = indexOffset;
6583 cmd.args.bindIndexBuffer.type = type;
6597 const QSize outputSize = cbD->currentTarget->pixelSize();
6598 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6599 float x = 0, y = 0, w = 0, h = 0;
6601 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6604 w = outputSize.width();
6605 h = outputSize.height();
6608 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6612 VkRect2D *s = &cmd.args.setScissor.scissor;
6613 s->offset.x = int32_t(x);
6614 s->offset.y = int32_t(y);
6615 s->extent.width = uint32_t(w);
6616 s->extent.height = uint32_t(h);
6619 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6620 cbD->commands.unget();
6630 const QSize outputSize = cbD->currentTarget->pixelSize();
6634 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6638 VkViewport *vp = &cmd.args.setViewport.viewport;
6643 vp->minDepth = viewport.minDepth();
6644 vp->maxDepth = viewport.maxDepth();
6647 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6648 cbD->commands.unget();
6653 cbD->currentViewport = viewport;
6654 if (cbD->currentGraphicsPipeline
6655 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6665 Q_ASSERT(!cbD->currentGraphicsPipeline
6667 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6668 const QSize outputSize = cbD->currentTarget->pixelSize();
6672 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6676 VkRect2D *s = &cmd.args.setScissor.scissor;
6679 s->extent.width = uint32_t(w);
6680 s->extent.height = uint32_t(h);
6683 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6684 cbD->commands.unget();
6698 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6699 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6703 cmd.args.setBlendConstants.c[0] = c.redF();
6704 cmd.args.setBlendConstants.c[1] = c.greenF();
6705 cmd.args.setBlendConstants.c[2] = c.blueF();
6706 cmd.args.setBlendConstants.c[3] = c.alphaF();
6716 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6720 cmd.args.setStencilRef.ref = refValue;
6726#ifdef VK_KHR_fragment_shading_rate
6727 if (!vkCmdSetFragmentShadingRateKHR)
6730 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6731 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6732 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6734 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6735 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6736 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6738 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6739 if (cbD->passUsesSecondaryCb) {
6740 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6742 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6743 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6744 cmd.args.setShadingRate.w = size.width;
6745 cmd.args.setShadingRate.h = size.height;
6747 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6748 cbD->hasShadingRateSet =
true;
6751 Q_UNUSED(coarsePixelSize);
6756 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6762 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6766 cmd.args.draw.vertexCount = vertexCount;
6767 cmd.args.draw.instanceCount = instanceCount;
6768 cmd.args.draw.firstVertex = firstVertex;
6769 cmd.args.draw.firstInstance = firstInstance;
6774 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6780 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6781 firstIndex, vertexOffset, firstInstance);
6785 cmd.args.drawIndexed.indexCount = indexCount;
6786 cmd.args.drawIndexed.instanceCount = instanceCount;
6787 cmd.args.drawIndexed.firstIndex = firstIndex;
6788 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6789 cmd.args.drawIndexed.firstInstance = firstInstance;
6794 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6801 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6802 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6804 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6808 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6811 if (caps.drawIndirectMulti) {
6812 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6813 indirectBufVk, indirectBufferOffset,
6816 VkDeviceSize offset = indirectBufferOffset;
6817 for (quint32 i = 0; i < drawCount; ++i) {
6818 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6819 indirectBufVk, offset,
6825 if (caps.drawIndirectMulti) {
6828 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6829 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6830 cmd.args.drawIndirect.drawCount = drawCount;
6831 cmd.args.drawIndirect.stride = stride;
6833 VkDeviceSize offset = indirectBufferOffset;
6834 for (quint32 i = 0; i < drawCount; ++i) {
6837 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6838 cmd.args.drawIndirect.indirectBufferOffset = offset;
6839 cmd.args.drawIndirect.drawCount = 1;
6840 cmd.args.drawIndirect.stride = stride;
6848 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6855 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6856 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6858 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6862 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6865 if (caps.drawIndirectMulti) {
6866 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6867 indirectBufVk, indirectBufferOffset,
6870 VkDeviceSize offset = indirectBufferOffset;
6871 for (quint32 i = 0; i < drawCount; ++i) {
6872 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6873 indirectBufVk, offset,
6879 if (caps.drawIndirectMulti) {
6882 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6883 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
6884 cmd.args.drawIndexedIndirect.drawCount = drawCount;
6885 cmd.args.drawIndexedIndirect.stride = stride;
6887 VkDeviceSize offset = indirectBufferOffset;
6888 for (quint32 i = 0; i < drawCount; ++i) {
6891 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6892 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
6893 cmd.args.drawIndexedIndirect.drawCount = 1;
6894 cmd.args.drawIndexedIndirect.stride = stride;
6903#ifdef VK_EXT_debug_utils
6904 if (!debugMarkers || !caps.debugUtils)
6907 VkDebugUtilsLabelEXT label = {};
6908 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6910 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6911 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6912 label.pLabelName = name.constData();
6913 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6915 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6916 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6917 cmd.args.debugMarkerBegin.label = label;
6918 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6919 cbD->pools.debugMarkerData.append(name);
6929#ifdef VK_EXT_debug_utils
6930 if (!debugMarkers || !caps.debugUtils)
6933 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6934 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6935 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6937 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6938 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6947#ifdef VK_EXT_debug_utils
6948 if (!debugMarkers || !caps.debugUtils)
6951 VkDebugUtilsLabelEXT label = {};
6952 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6954 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6955 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6956 label.pLabelName = msg.constData();
6957 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6959 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6960 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6961 cmd.args.debugMarkerInsert.label = label;
6962 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6963 cbD->pools.debugMarkerData.append(msg);
6973 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6978 Q_ASSERT(cbD->currentTarget);
6981 switch (cbD->currentTarget->resourceType()) {
6982 case QRhiResource::SwapChainRenderTarget:
6985 case QRhiResource::TextureRenderTarget:
7017 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
7018 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
7022 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
7023 cbD->activeSecondaryCbStack.removeLast();
7024 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
7026 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
7028 cbD->activeSecondaryCbStack.append(extCb);
7040 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
7041 cbD->activeSecondaryCbStack.removeLast();
7042 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
7043 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
7057 if (!debugMarkers || name.isEmpty())
7060 QByteArray decoratedName = name;
7062 decoratedName +=
'/';
7063 decoratedName += QByteArray::number(slot);
7065 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
7070#ifdef VK_EXT_debug_utils
7071 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
7074 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
7075 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
7076 nameInfo.objectType = type;
7077 nameInfo.objectHandle = object;
7078 QByteArray decoratedName = name;
7080 decoratedName +=
'/';
7081 decoratedName += QByteArray::number(slot);
7083 nameInfo.pObjectName = decoratedName.constData();
7084 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
7096 if (usage.testFlag(QRhiBuffer::VertexBuffer))
7097 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
7098 if (usage.testFlag(QRhiBuffer::IndexBuffer))
7099 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
7100 if (usage.testFlag(QRhiBuffer::UniformBuffer))
7101 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
7102 if (usage.testFlag(QRhiBuffer::StorageBuffer))
7103 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
7104 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
7105 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
7106 return VkBufferUsageFlagBits(u);
7112 case QRhiSampler::Nearest:
7113 return VK_FILTER_NEAREST;
7114 case QRhiSampler::Linear:
7115 return VK_FILTER_LINEAR;
7117 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
7124 case QRhiSampler::None:
7125 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7126 case QRhiSampler::Nearest:
7127 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
7128 case QRhiSampler::Linear:
7129 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
7131 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
7138 case QRhiSampler::Repeat:
7139 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
7140 case QRhiSampler::ClampToEdge:
7141 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
7142 case QRhiSampler::Mirror:
7143 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
7145 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
7152 case QRhiShaderStage::Vertex:
7153 return VK_SHADER_STAGE_VERTEX_BIT;
7154 case QRhiShaderStage::TessellationControl:
7155 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7156 case QRhiShaderStage::TessellationEvaluation:
7157 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7158 case QRhiShaderStage::Fragment:
7159 return VK_SHADER_STAGE_FRAGMENT_BIT;
7160 case QRhiShaderStage::Compute:
7161 return VK_SHADER_STAGE_COMPUTE_BIT;
7162 case QRhiShaderStage::Geometry:
7163 return VK_SHADER_STAGE_GEOMETRY_BIT;
7165 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
7172 case QRhiVertexInputAttribute::Float4:
7173 return VK_FORMAT_R32G32B32A32_SFLOAT;
7174 case QRhiVertexInputAttribute::Float3:
7175 return VK_FORMAT_R32G32B32_SFLOAT;
7176 case QRhiVertexInputAttribute::Float2:
7177 return VK_FORMAT_R32G32_SFLOAT;
7178 case QRhiVertexInputAttribute::Float:
7179 return VK_FORMAT_R32_SFLOAT;
7180 case QRhiVertexInputAttribute::UNormByte4:
7181 return VK_FORMAT_R8G8B8A8_UNORM;
7182 case QRhiVertexInputAttribute::UNormByte2:
7183 return VK_FORMAT_R8G8_UNORM;
7184 case QRhiVertexInputAttribute::UNormByte:
7185 return VK_FORMAT_R8_UNORM;
7186 case QRhiVertexInputAttribute::UInt4:
7187 return VK_FORMAT_R32G32B32A32_UINT;
7188 case QRhiVertexInputAttribute::UInt3:
7189 return VK_FORMAT_R32G32B32_UINT;
7190 case QRhiVertexInputAttribute::UInt2:
7191 return VK_FORMAT_R32G32_UINT;
7192 case QRhiVertexInputAttribute::UInt:
7193 return VK_FORMAT_R32_UINT;
7194 case QRhiVertexInputAttribute::SInt4:
7195 return VK_FORMAT_R32G32B32A32_SINT;
7196 case QRhiVertexInputAttribute::SInt3:
7197 return VK_FORMAT_R32G32B32_SINT;
7198 case QRhiVertexInputAttribute::SInt2:
7199 return VK_FORMAT_R32G32_SINT;
7200 case QRhiVertexInputAttribute::SInt:
7201 return VK_FORMAT_R32_SINT;
7202 case QRhiVertexInputAttribute::Half4:
7203 return VK_FORMAT_R16G16B16A16_SFLOAT;
7204 case QRhiVertexInputAttribute::Half3:
7205 return VK_FORMAT_R16G16B16_SFLOAT;
7206 case QRhiVertexInputAttribute::Half2:
7207 return VK_FORMAT_R16G16_SFLOAT;
7208 case QRhiVertexInputAttribute::Half:
7209 return VK_FORMAT_R16_SFLOAT;
7210 case QRhiVertexInputAttribute::UShort4:
7211 return VK_FORMAT_R16G16B16A16_UINT;
7212 case QRhiVertexInputAttribute::UShort3:
7213 return VK_FORMAT_R16G16B16_UINT;
7214 case QRhiVertexInputAttribute::UShort2:
7215 return VK_FORMAT_R16G16_UINT;
7216 case QRhiVertexInputAttribute::UShort:
7217 return VK_FORMAT_R16_UINT;
7218 case QRhiVertexInputAttribute::SShort4:
7219 return VK_FORMAT_R16G16B16A16_SINT;
7220 case QRhiVertexInputAttribute::SShort3:
7221 return VK_FORMAT_R16G16B16_SINT;
7222 case QRhiVertexInputAttribute::SShort2:
7223 return VK_FORMAT_R16G16_SINT;
7224 case QRhiVertexInputAttribute::SShort:
7225 return VK_FORMAT_R16_SINT;
7227 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
7234 case QRhiGraphicsPipeline::Triangles:
7235 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
7236 case QRhiGraphicsPipeline::TriangleStrip:
7237 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
7238 case QRhiGraphicsPipeline::TriangleFan:
7239 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
7240 case QRhiGraphicsPipeline::Lines:
7241 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
7242 case QRhiGraphicsPipeline::LineStrip:
7243 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7244 case QRhiGraphicsPipeline::Points:
7245 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
7246 case QRhiGraphicsPipeline::Patches:
7247 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7249 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
7256 case QRhiGraphicsPipeline::None:
7257 return VK_CULL_MODE_NONE;
7258 case QRhiGraphicsPipeline::Front:
7259 return VK_CULL_MODE_FRONT_BIT;
7260 case QRhiGraphicsPipeline::Back:
7261 return VK_CULL_MODE_BACK_BIT;
7263 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
7270 case QRhiGraphicsPipeline::CCW:
7271 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
7272 case QRhiGraphicsPipeline::CW:
7273 return VK_FRONT_FACE_CLOCKWISE;
7275 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
7282 if (c.testFlag(QRhiGraphicsPipeline::R))
7283 f |= VK_COLOR_COMPONENT_R_BIT;
7284 if (c.testFlag(QRhiGraphicsPipeline::G))
7285 f |= VK_COLOR_COMPONENT_G_BIT;
7286 if (c.testFlag(QRhiGraphicsPipeline::B))
7287 f |= VK_COLOR_COMPONENT_B_BIT;
7288 if (c.testFlag(QRhiGraphicsPipeline::A))
7289 f |= VK_COLOR_COMPONENT_A_BIT;
7290 return VkColorComponentFlags(f);
7296 case QRhiGraphicsPipeline::Zero:
7297 return VK_BLEND_FACTOR_ZERO;
7298 case QRhiGraphicsPipeline::One:
7299 return VK_BLEND_FACTOR_ONE;
7300 case QRhiGraphicsPipeline::SrcColor:
7301 return VK_BLEND_FACTOR_SRC_COLOR;
7302 case QRhiGraphicsPipeline::OneMinusSrcColor:
7303 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
7304 case QRhiGraphicsPipeline::DstColor:
7305 return VK_BLEND_FACTOR_DST_COLOR;
7306 case QRhiGraphicsPipeline::OneMinusDstColor:
7307 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
7308 case QRhiGraphicsPipeline::SrcAlpha:
7309 return VK_BLEND_FACTOR_SRC_ALPHA;
7310 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7311 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
7312 case QRhiGraphicsPipeline::DstAlpha:
7313 return VK_BLEND_FACTOR_DST_ALPHA;
7314 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7315 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7316 case QRhiGraphicsPipeline::ConstantColor:
7317 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7318 case QRhiGraphicsPipeline::OneMinusConstantColor:
7319 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7320 case QRhiGraphicsPipeline::ConstantAlpha:
7321 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7322 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7323 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7324 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7325 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7326 case QRhiGraphicsPipeline::Src1Color:
7327 return VK_BLEND_FACTOR_SRC1_COLOR;
7328 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7329 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7330 case QRhiGraphicsPipeline::Src1Alpha:
7331 return VK_BLEND_FACTOR_SRC1_ALPHA;
7332 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7333 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7335 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7342 case QRhiGraphicsPipeline::Add:
7343 return VK_BLEND_OP_ADD;
7344 case QRhiGraphicsPipeline::Subtract:
7345 return VK_BLEND_OP_SUBTRACT;
7346 case QRhiGraphicsPipeline::ReverseSubtract:
7347 return VK_BLEND_OP_REVERSE_SUBTRACT;
7348 case QRhiGraphicsPipeline::Min:
7349 return VK_BLEND_OP_MIN;
7350 case QRhiGraphicsPipeline::Max:
7351 return VK_BLEND_OP_MAX;
7353 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7360 case QRhiGraphicsPipeline::Never:
7361 return VK_COMPARE_OP_NEVER;
7362 case QRhiGraphicsPipeline::Less:
7363 return VK_COMPARE_OP_LESS;
7364 case QRhiGraphicsPipeline::Equal:
7365 return VK_COMPARE_OP_EQUAL;
7366 case QRhiGraphicsPipeline::LessOrEqual:
7367 return VK_COMPARE_OP_LESS_OR_EQUAL;
7368 case QRhiGraphicsPipeline::Greater:
7369 return VK_COMPARE_OP_GREATER;
7370 case QRhiGraphicsPipeline::NotEqual:
7371 return VK_COMPARE_OP_NOT_EQUAL;
7372 case QRhiGraphicsPipeline::GreaterOrEqual:
7373 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7374 case QRhiGraphicsPipeline::Always:
7375 return VK_COMPARE_OP_ALWAYS;
7377 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7384 case QRhiGraphicsPipeline::StencilZero:
7385 return VK_STENCIL_OP_ZERO;
7386 case QRhiGraphicsPipeline::Keep:
7387 return VK_STENCIL_OP_KEEP;
7388 case QRhiGraphicsPipeline::Replace:
7389 return VK_STENCIL_OP_REPLACE;
7390 case QRhiGraphicsPipeline::IncrementAndClamp:
7391 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7392 case QRhiGraphicsPipeline::DecrementAndClamp:
7393 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7394 case QRhiGraphicsPipeline::Invert:
7395 return VK_STENCIL_OP_INVERT;
7396 case QRhiGraphicsPipeline::IncrementAndWrap:
7397 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7398 case QRhiGraphicsPipeline::DecrementAndWrap:
7399 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7401 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7408 case QRhiGraphicsPipeline::Fill:
7409 return VK_POLYGON_MODE_FILL;
7410 case QRhiGraphicsPipeline::Line:
7411 return VK_POLYGON_MODE_LINE;
7413 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7419 dst->failOp = toVkStencilOp(src.failOp);
7420 dst->passOp = toVkStencilOp(src.passOp);
7421 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7422 dst->compareOp = toVkCompareOp(src.compareOp);
7428 case QRhiShaderResourceBinding::UniformBuffer:
7429 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7430 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7432 case QRhiShaderResourceBinding::SampledTexture:
7433 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7435 case QRhiShaderResourceBinding::Texture:
7436 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7438 case QRhiShaderResourceBinding::Sampler:
7439 return VK_DESCRIPTOR_TYPE_SAMPLER;
7441 case QRhiShaderResourceBinding::ImageLoad:
7442 case QRhiShaderResourceBinding::ImageStore:
7443 case QRhiShaderResourceBinding::ImageLoadStore:
7444 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7446 case QRhiShaderResourceBinding::BufferLoad:
7447 case QRhiShaderResourceBinding::BufferStore:
7448 case QRhiShaderResourceBinding::BufferLoadStore:
7449 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7452 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7459 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7460 s |= VK_SHADER_STAGE_VERTEX_BIT;
7461 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7462 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7463 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7464 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7465 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7466 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7467 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7468 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7469 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7470 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7471 return VkShaderStageFlags(s);
7477 case QRhiSampler::Never:
7478 return VK_COMPARE_OP_NEVER;
7479 case QRhiSampler::Less:
7480 return VK_COMPARE_OP_LESS;
7481 case QRhiSampler::Equal:
7482 return VK_COMPARE_OP_EQUAL;
7483 case QRhiSampler::LessOrEqual:
7484 return VK_COMPARE_OP_LESS_OR_EQUAL;
7485 case QRhiSampler::Greater:
7486 return VK_COMPARE_OP_GREATER;
7487 case QRhiSampler::NotEqual:
7488 return VK_COMPARE_OP_NOT_EQUAL;
7489 case QRhiSampler::GreaterOrEqual:
7490 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7491 case QRhiSampler::Always:
7492 return VK_COMPARE_OP_ALWAYS;
7494 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7502 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7522 e.buffer.buffers[i] = buffers[i];
7524 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7527 buffers[i] = VK_NULL_HANDLE;
7529 stagingBuffers[i] = VK_NULL_HANDLE;
7531 pendingDynamicUpdates[i].clear();
7539 rhiD->releaseQueue.append(e);
7540 rhiD->unregisterResource(
this);
7549 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7550 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7554 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7556 VkBufferCreateInfo bufferInfo = {};
7557 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7558 bufferInfo.size = nonZeroSize;
7559 bufferInfo.usage = toVkBufferUsage(m_usage);
7561 VmaAllocationCreateInfo allocInfo = {};
7563 if (m_type == Dynamic) {
7568 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7571 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7573 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7574 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7578 VkResult err = VK_SUCCESS;
7580 buffers[i] = VK_NULL_HANDLE;
7582 usageState[i].access = usageState[i].stage = 0;
7583 if (i == 0 || m_type == Dynamic) {
7584 VmaAllocation allocation;
7585 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7586 if (err != VK_SUCCESS)
7589 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7590 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7591 m_type == Dynamic ? i : -1);
7595 if (err != VK_SUCCESS) {
7596 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7597 rhiD->printExtraErrorInfo(err);
7603 rhiD->registerResource(
this);
7609 if (m_type == Dynamic) {
7615 b.objects[i] = &buffers[i];
7620 return { { &buffers[0] }, 1 };
7630 Q_ASSERT(m_type == Dynamic);
7632 Q_ASSERT(rhiD->inFrame);
7633 const int slot = rhiD->currentFrameSlot;
7635 VmaAllocation a = toVmaAllocation(allocations[slot]);
7636 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7637 if (err != VK_SUCCESS) {
7638 qWarning(
"Failed to map buffer: %d", err);
7641 return static_cast<
char *>(p);
7647 const int slot = rhiD->currentFrameSlot;
7648 VmaAllocation a = toVmaAllocation(allocations[slot]);
7649 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7650 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7654 int sampleCount, Flags flags,
7655 QRhiTexture::Format backingFormatHint)
7668 if (!memory && !backingTexture)
7675 e.renderBuffer.memory = memory;
7676 e.renderBuffer.image = image;
7677 e.renderBuffer.imageView = imageView;
7679 memory = VK_NULL_HANDLE;
7680 image = VK_NULL_HANDLE;
7681 imageView = VK_NULL_HANDLE;
7691 rhiD->releaseQueue.append(e);
7692 rhiD->unregisterResource(
this);
7698 if (memory || backingTexture)
7701 if (m_pixelSize.isEmpty())
7705 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7708 case QRhiRenderBuffer::Color:
7716 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7724 vkformat = backingTexture->vkformat;
7727 case QRhiRenderBuffer::DepthStencil:
7728 vkformat = rhiD->optimalDepthStencilFormat();
7729 if (!rhiD->createTransientImage(vkformat,
7731 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7732 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7741 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7750 rhiD->registerResource(
this);
7756 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7757 return m_backingFormatHint;
7759 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7763 int arraySize,
int sampleCount, Flags flags)
7767 stagingBuffers[i] = VK_NULL_HANDLE;
7770 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7771 perLevelImageViews[i] = VK_NULL_HANDLE;
7788 e.texture.image = owns ? image : VK_NULL_HANDLE;
7789 e.texture.imageView = imageView;
7793 e.texture.stagingBuffers[i] = stagingBuffers[i];
7796 stagingBuffers[i] = VK_NULL_HANDLE;
7800 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7801 e.texture.extraImageViews[i] = perLevelImageViews[i];
7802 perLevelImageViews[i] = VK_NULL_HANDLE;
7805 image = VK_NULL_HANDLE;
7806 imageView = VK_NULL_HANDLE;
7811 rhiD->releaseQueue.append(e);
7812 rhiD->unregisterResource(
this);
7822 vkformat = toVkTextureFormat(m_format, m_flags);
7823 if (m_writeViewFormat.format != UnknownFormat)
7824 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7826 viewFormat = vkformat;
7827 if (m_readViewFormat.format != UnknownFormat)
7828 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7830 viewFormatForSampling = vkformat;
7832 VkFormatProperties props;
7833 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7834 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7835 if (!canSampleOptimal) {
7836 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7840 const bool isCube = m_flags.testFlag(CubeMap);
7841 const bool isArray = m_flags.testFlag(TextureArray);
7842 const bool is3D = m_flags.testFlag(ThreeDimensional);
7843 const bool is1D = m_flags.testFlag(OneDimensional);
7844 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7846 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7847 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7849 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7850 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7851 if (mipLevelCount > maxLevels) {
7852 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7853 mipLevelCount = maxLevels;
7855 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7856 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7858 qWarning(
"Cubemap texture cannot be multisample");
7862 qWarning(
"3D texture cannot be multisample");
7866 qWarning(
"Multisample texture cannot have mipmaps");
7870 if (isCube && is3D) {
7871 qWarning(
"Texture cannot be both cube and 3D");
7874 if (isArray && is3D) {
7875 qWarning(
"Texture cannot be both array and 3D");
7878 if (isCube && is1D) {
7879 qWarning(
"Texture cannot be both cube and 1D");
7883 qWarning(
"Texture cannot be both 1D and 3D");
7886 if (m_depth > 1 && !is3D) {
7887 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7890 if (m_arraySize > 0 && !isArray) {
7891 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7894 if (m_arraySize < 1 && isArray) {
7895 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7899 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7900 usageState.access = 0;
7901 usageState.stage = 0;
7903 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
7907 *adjustedSize = size;
7916 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7917 const bool isCube = m_flags.testFlag(CubeMap);
7918 const bool isArray = m_flags.testFlag(TextureArray);
7919 const bool is3D = m_flags.testFlag(ThreeDimensional);
7920 const bool is1D = m_flags.testFlag(OneDimensional);
7922 VkImageViewCreateInfo viewInfo = {};
7923 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7924 viewInfo.image = image;
7925 viewInfo.viewType = isCube
7926 ? VK_IMAGE_VIEW_TYPE_CUBE
7927 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7928 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7929 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7930 viewInfo.format = viewFormatForSampling;
7931 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7932 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7933 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7934 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7935 viewInfo.subresourceRange.aspectMask = aspectMask;
7938 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7939 viewInfo.subresourceRange.levelCount = mipLevelCount;
7940 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7941 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7942 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7944 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7947 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7948 if (err != VK_SUCCESS) {
7949 qWarning(
"Failed to create image view: %d", err);
7962 if (!prepareCreate(&size))
7966 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7967 const bool isDepth = isDepthTextureFormat(m_format);
7968 const bool isCube = m_flags.testFlag(CubeMap);
7969 const bool isArray = m_flags.testFlag(TextureArray);
7970 const bool is3D = m_flags.testFlag(ThreeDimensional);
7971 const bool is1D = m_flags.testFlag(OneDimensional);
7973 VkImageCreateInfo imageInfo = {};
7974 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7975 imageInfo.flags = 0;
7977 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7979 if (is3D && isRenderTarget) {
7985 if (!rhiD->caps.texture3DSliceAs2D)
7986 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7987#ifdef VK_VERSION_1_1
7988 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7990 imageInfo.flags |= 0x00000020;
7994 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7995 imageInfo.format = vkformat;
7996 imageInfo.extent.width = uint32_t(size.width());
7997 imageInfo.extent.height = uint32_t(size.height());
7998 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7999 imageInfo.mipLevels = mipLevelCount;
8000 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8001 imageInfo.samples = samples;
8002 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
8003 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
8005 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
8006 if (isRenderTarget) {
8008 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
8010 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
8012 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
8013 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8014 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
8015 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
8016 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
8017 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
8018#ifdef VK_KHR_fragment_shading_rate
8019 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
8020 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
8023 VmaAllocationCreateInfo allocInfo = {};
8024 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
8026 VmaAllocation allocation;
8027 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
8028 if (err != VK_SUCCESS) {
8029 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
8030 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
8031 int(imageInfo.format),
8032 imageInfo.mipLevels,
8033 imageInfo.arrayLayers,
8034 int(imageInfo.samples),
8036 rhiD->printExtraErrorInfo(err);
8040 rhiD->setAllocationName(allocation, m_objectName);
8045 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
8048 rhiD->registerResource(
this);
8054 VkImage img = VkImage(src.object);
8058 if (!prepareCreate())
8066 usageState.layout = VkImageLayout(src.layout);
8070 rhiD->registerResource(
this);
8076 return {quint64(image), usageState.layout};
8081 usageState.layout = VkImageLayout(layout);
8086 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
8087 if (perLevelImageViews[level] != VK_NULL_HANDLE)
8088 return perLevelImageViews[level];
8090 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
8091 const bool isCube = m_flags.testFlag(CubeMap);
8092 const bool isArray = m_flags.testFlag(TextureArray);
8093 const bool is3D = m_flags.testFlag(ThreeDimensional);
8094 const bool is1D = m_flags.testFlag(OneDimensional);
8096 VkImageViewCreateInfo viewInfo = {};
8097 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8098 viewInfo.image = image;
8099 viewInfo.viewType = isCube
8100 ? VK_IMAGE_VIEW_TYPE_CUBE
8101 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
8102 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
8103 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
8104 viewInfo.format = viewFormat;
8105 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8106 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8107 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8108 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8109 viewInfo.subresourceRange.aspectMask = aspectMask;
8110 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
8111 viewInfo.subresourceRange.levelCount = 1;
8112 viewInfo.subresourceRange.baseArrayLayer = 0;
8113 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
8115 VkImageView v = VK_NULL_HANDLE;
8117 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
8118 if (err != VK_SUCCESS) {
8119 qWarning(
"Failed to create image view: %d", err);
8120 return VK_NULL_HANDLE;
8123 perLevelImageViews[level] = v;
8128 AddressMode u, AddressMode v, AddressMode w)
8147 e.sampler.sampler = sampler;
8148 sampler = VK_NULL_HANDLE;
8152 rhiD->releaseQueue.append(e);
8153 rhiD->unregisterResource(
this);
8162 VkSamplerCreateInfo samplerInfo = {};
8163 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
8164 samplerInfo.magFilter = toVkFilter(m_magFilter);
8165 samplerInfo.minFilter = toVkFilter(m_minFilter);
8166 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
8167 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
8168 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
8169 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
8170 samplerInfo.maxAnisotropy = 1.0f;
8171 samplerInfo.compareEnable = m_compareOp != Never;
8172 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
8173 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
8176 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
8177 if (err != VK_SUCCESS) {
8178 qWarning(
"Failed to create sampler: %d", err);
8184 rhiD->registerResource(
this);
8191 serializedFormatData.reserve(64);
8205 rp = VK_NULL_HANDLE;
8213 e.renderPass.rp = rp;
8215 rp = VK_NULL_HANDLE;
8219 rhiD->releaseQueue.append(e);
8220 rhiD->unregisterResource(
this);
8226 return a.format == b.format
8227 && a.samples == b.samples
8228 && a.loadOp == b.loadOp
8229 && a.storeOp == b.storeOp
8230 && a.stencilLoadOp == b.stencilLoadOp
8231 && a.stencilStoreOp == b.stencilStoreOp
8232 && a.initialLayout == b.initialLayout
8233 && a.finalLayout == b.finalLayout;
8246 if (attDescs.size() != o->attDescs.size())
8248 if (colorRefs.size() != o->colorRefs.size())
8250 if (resolveRefs.size() != o->resolveRefs.size())
8256 if (multiViewCount != o->multiViewCount)
8261 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8262 const uint32_t attIdx = colorRefs[i].attachment;
8263 if (attIdx != o->colorRefs[i].attachment)
8265 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8270 const uint32_t attIdx = dsRef.attachment;
8271 if (attIdx != o->dsRef.attachment)
8273 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8277 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8278 const uint32_t attIdx = resolveRefs[i].attachment;
8279 if (attIdx != o->resolveRefs[i].attachment)
8281 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8286 const uint32_t attIdx = dsResolveRef.attachment;
8287 if (attIdx != o->dsResolveRef.attachment)
8289 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8294 const uint32_t attIdx = shadingRateRef.attachment;
8295 if (attIdx != o->shadingRateRef.attachment)
8297 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8308 serializedFormatData.clear();
8309 auto p =
std::back_inserter(serializedFormatData);
8311 *p++ = attDescs.size();
8312 *p++ = colorRefs.size();
8313 *p++ = resolveRefs.size();
8317 *p++ = multiViewCount;
8319 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8320 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8321 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8322 *p++ = used ? a->format : 0;
8323 *p++ = used ? a->samples : 0;
8324 *p++ = used ? a->loadOp : 0;
8325 *p++ = used ? a->storeOp : 0;
8326 *p++ = used ? a->stencilLoadOp : 0;
8327 *p++ = used ? a->stencilStoreOp : 0;
8328 *p++ = used ? a->initialLayout : 0;
8329 *p++ = used ? a->finalLayout : 0;
8332 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8333 const uint32_t attIdx = colorRefs[i].attachment;
8335 serializeAttachmentData(attIdx);
8339 const uint32_t attIdx = dsRef.attachment;
8341 serializeAttachmentData(attIdx);
8344 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8345 const uint32_t attIdx = resolveRefs[i].attachment;
8347 serializeAttachmentData(attIdx);
8351 const uint32_t attIdx = dsResolveRef.attachment;
8353 serializeAttachmentData(attIdx);
8357 const uint32_t attIdx = shadingRateRef.attachment;
8359 serializeAttachmentData(attIdx);
8368 rpD->attDescs = attDescs;
8369 rpD->colorRefs = colorRefs;
8370 rpD->resolveRefs = resolveRefs;
8371 rpD->subpassDeps = subpassDeps;
8375 rpD->multiViewCount = multiViewCount;
8377 rpD->dsResolveRef = dsResolveRef;
8378 rpD->shadingRateRef = shadingRateRef;
8380 VkRenderPassCreateInfo rpInfo;
8381 VkSubpassDescription subpassDesc;
8382 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8386 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8391#ifdef VK_KHR_create_renderpass2
8392 if (rhiD->caps.renderPass2KHR) {
8394 VkRenderPassCreateInfo2KHR rpInfo2;
8395 RenderPass2SetupHelper rp2Helper(rhiD);
8396 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8400 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8401 if (err != VK_SUCCESS) {
8402 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8409 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8410 if (err != VK_SUCCESS) {
8411 qWarning(
"Failed to create renderpass: %d", err);
8418 rhiD->registerResource(rpD);
8424 return serializedFormatData;
8429 nativeHandlesStruct.renderPass = rp;
8430 return &nativeHandlesStruct;
8456 texture =
QRHI_RES(QVkTexture, src);
8488 return d.sampleCount;
8492 const QRhiTextureRenderTargetDescription &desc,
8497 rtv[att] = VK_NULL_HANDLE;
8498 resrtv[att] = VK_NULL_HANDLE;
8516 e.textureRenderTarget.fb = d.fb;
8517 d.fb = VK_NULL_HANDLE;
8520 e.textureRenderTarget.rtv[att] = rtv[att];
8521 e.textureRenderTarget.resrtv[att] = resrtv[att];
8522 rtv[att] = VK_NULL_HANDLE;
8523 resrtv[att] = VK_NULL_HANDLE;
8526 e.textureRenderTarget.dsv = dsv;
8527 dsv = VK_NULL_HANDLE;
8528 e.textureRenderTarget.resdsv = resdsv;
8529 resdsv = VK_NULL_HANDLE;
8531 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8532 shadingRateMapView = VK_NULL_HANDLE;
8536 rhiD->releaseQueue.append(e);
8537 rhiD->unregisterResource(
this);
8547 if (!rhiD->createOffscreenRenderPass(rp,
8548 m_desc.cbeginColorAttachments(),
8549 m_desc.cendColorAttachments(),
8550 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8551 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8552 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8553 m_desc.depthStencilBuffer(),
8554 m_desc.depthTexture(),
8555 m_desc.depthResolveTexture(),
8556 m_desc.depthLayer(),
8557 m_desc.shadingRateMap()))
8565 rhiD->registerResource(rp);
8574 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8575 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8576 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8579 QVarLengthArray<VkImageView, 8> views;
8580 d.multiViewCount = 0;
8582 d.colorAttCount = 0;
8584 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8585 d.colorAttCount += 1;
8588 Q_ASSERT(texD || rbD);
8590 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8591 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8592 const bool isMultiView = it->multiViewCount() >= 2;
8593 if (isMultiView && d.multiViewCount == 0)
8594 d.multiViewCount = it->multiViewCount();
8595 VkImageViewCreateInfo viewInfo = {};
8596 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8597 viewInfo.image = texD->image;
8598 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8599 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8600 : VK_IMAGE_VIEW_TYPE_2D);
8601 viewInfo.format = texD->viewFormat;
8602 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8603 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8604 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8605 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8606 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8607 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8608 viewInfo.subresourceRange.levelCount = 1;
8609 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8610 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8611 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8612 if (err != VK_SUCCESS) {
8613 qWarning(
"Failed to create render target image view: %d", err);
8616 views.append(rtv[attIndex]);
8617 if (attIndex == 0) {
8618 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8619 d.sampleCount = texD->samples;
8624 if (attIndex == 0) {
8625 d.pixelSize = rbD->pixelSize();
8626 d.sampleCount = rbD->samples;
8632 if (hasDepthStencil) {
8633 if (m_desc.depthTexture()) {
8636 VkImageViewCreateInfo viewInfo = {};
8637 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8638 viewInfo.image = depthTexD->image;
8639 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8640 viewInfo.format = depthTexD->viewFormat;
8641 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8642 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8643 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8644 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8645 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8646 viewInfo.subresourceRange.levelCount = 1;
8647 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8648 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8649 viewInfo.subresourceRange.layerCount = 1;
8652 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8653 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8654 if (err != VK_SUCCESS) {
8655 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8659 if (d.colorAttCount == 0) {
8660 d.pixelSize = depthTexD->pixelSize();
8661 d.sampleCount = depthTexD->samples;
8665 views.append(depthRbD->imageView);
8666 if (d.colorAttCount == 0) {
8667 d.pixelSize = depthRbD->pixelSize();
8668 d.sampleCount = depthRbD->samples;
8676 d.resolveAttCount = 0;
8678 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8679 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8680 if (it->resolveTexture()) {
8682 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8683 d.resolveAttCount += 1;
8685 VkImageViewCreateInfo viewInfo = {};
8686 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8687 viewInfo.image = resTexD->image;
8688 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8689 : VK_IMAGE_VIEW_TYPE_2D;
8690 viewInfo.format = resTexD->viewFormat;
8691 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8692 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8693 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8694 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8695 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8696 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8697 viewInfo.subresourceRange.levelCount = 1;
8698 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8699 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8700 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8701 if (err != VK_SUCCESS) {
8702 qWarning(
"Failed to create render target resolve image view: %d", err);
8705 views.append(resrtv[attIndex]);
8709 if (m_desc.depthResolveTexture()) {
8711 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8713 VkImageViewCreateInfo viewInfo = {};
8714 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8715 viewInfo.image = resTexD->image;
8716 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8717 : VK_IMAGE_VIEW_TYPE_2D;
8718 viewInfo.format = resTexD->viewFormat;
8719 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8720 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8721 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8722 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8723 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8724 viewInfo.subresourceRange.baseMipLevel = 0;
8725 viewInfo.subresourceRange.levelCount = 1;
8726 viewInfo.subresourceRange.baseArrayLayer = 0;
8727 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8728 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8729 if (err != VK_SUCCESS) {
8730 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8733 views.append(resdsv);
8734 d.dsResolveAttCount = 1;
8736 d.dsResolveAttCount = 0;
8739 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8741 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8743 VkImageViewCreateInfo viewInfo = {};
8744 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8745 viewInfo.image = texD->image;
8746 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8747 : VK_IMAGE_VIEW_TYPE_2D;
8748 viewInfo.format = texD->viewFormat;
8749 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8750 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8751 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8752 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8753 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8754 viewInfo.subresourceRange.baseMipLevel = 0;
8755 viewInfo.subresourceRange.levelCount = 1;
8756 viewInfo.subresourceRange.baseArrayLayer = 0;
8757 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8758 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8759 if (err != VK_SUCCESS) {
8760 qWarning(
"Failed to create render target shading rate map view: %d", err);
8763 views.append(shadingRateMapView);
8764 d.shadingRateAttCount = 1;
8766 d.shadingRateAttCount = 0;
8769 if (!m_renderPassDesc)
8770 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8772 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8773 Q_ASSERT(d.rp && d.rp->rp);
8775 VkFramebufferCreateInfo fbInfo = {};
8776 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8777 fbInfo.renderPass = d.rp->rp;
8778 fbInfo.attachmentCount = uint32_t(views.count());
8779 fbInfo.pAttachments = views.constData();
8780 fbInfo.width = uint32_t(d.pixelSize.width());
8781 fbInfo.height = uint32_t(d.pixelSize.height());
8784 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8785 if (err != VK_SUCCESS) {
8786 qWarning(
"Failed to create framebuffer: %d", err);
8790 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8793 rhiD->registerResource(
this);
8799 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8812 return d.sampleCount;
8830 sortedBindings.clear();
8831 sortedDynamicOffsetBindingNumbers.clear();
8837 e.shaderResourceBindings.poolIndex =
poolIndex;
8838 e.shaderResourceBindings.layout = layout;
8841 layout = VK_NULL_HANDLE;
8842 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8843 descSets[i] = VK_NULL_HANDLE;
8847 rhiD->releaseQueue.append(e);
8848 rhiD->unregisterResource(
this);
8858 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8861 rhiD->updateLayoutDesc(
this);
8863 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8864 descSets[i] = VK_NULL_HANDLE;
8866 sortedBindings.clear();
8867 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8868 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8870 sortedDynamicOffsetBindingNumbers.clear();
8871 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8872 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8873 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8874 if (b->u.ubuf.hasDynamicOffset)
8875 sortedDynamicOffsetBindingNumbers.append(b->binding);
8879 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
8880 vkbindings.reserve(sortedBindings.size());
8881 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8882 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8883 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
8884 vkbinding.binding = uint32_t(b->binding);
8885 vkbinding.descriptorType = toVkDescriptorType(b);
8886 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8887 vkbinding.descriptorCount = b->u.stex.count;
8889 vkbinding.descriptorCount = 1;
8890 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8893 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8894 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8895 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8896 layoutInfo.pBindings = vkbindings.constData();
8898 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8899 if (err != VK_SUCCESS) {
8900 qWarning(
"Failed to create descriptor set layout: %d", err);
8903 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
8905 VkDescriptorSetAllocateInfo allocInfo = {};
8906 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8909 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8910 layouts[i] = layout;
8911 allocInfo.pSetLayouts = layouts;
8912 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8916 boundResourceData[i].resize(sortedBindings.size());
8917 for (BoundResourceData &bd : boundResourceData[i])
8918 memset(&bd, 0,
sizeof(BoundResourceData));
8922 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
8926 rhiD->registerResource(
this);
8932 sortedBindings.clear();
8933 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8934 if (!flags.testFlag(BindingsAreSorted))
8935 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8937 sortedDynamicOffsetBindingNumbers.clear();
8938 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8939 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8940 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8941 if (b->u.ubuf.hasDynamicOffset)
8942 sortedDynamicOffsetBindingNumbers.append(b->binding);
8956 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8957 for (BoundResourceData &bd : boundResourceData[i])
8958 memset(&bd, 0,
sizeof(BoundResourceData));
8976 if (!pipeline && !layout)
8983 e.pipelineState.pipeline = pipeline;
8984 e.pipelineState.layout = layout;
8986 pipeline = VK_NULL_HANDLE;
8987 layout = VK_NULL_HANDLE;
8991 rhiD->releaseQueue.append(e);
8992 rhiD->unregisterResource(
this);
8998 if (pipeline || layout)
9002 rhiD->pipelineCreationStart();
9003 if (!rhiD->sanityCheckGraphicsPipeline(
this))
9006 if (!rhiD->ensurePipelineCache())
9009 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9010 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9011 pipelineLayoutInfo.setLayoutCount = 1;
9013 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9014 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9015 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9016 if (err != VK_SUCCESS) {
9017 qWarning(
"Failed to create pipeline layout: %d", err);
9020 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9021 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9022 layout = VK_NULL_HANDLE;
9025 VkGraphicsPipelineCreateInfo pipelineInfo = {};
9026 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
9028 QVarLengthArray<VkShaderModule, 4> shaders;
9029 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
9030 for (VkShaderModule shader : shaders)
9031 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9033 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
9034 QVarLengthArray<QByteArray, 4> entryPointNames;
9035 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
9036 const QShader bakedShader = shaderStage.shader();
9037 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
9038 if (spirv.shader().isEmpty()) {
9039 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9042 VkShaderModule shader = rhiD->createShader(spirv.shader());
9044 shaders.append(shader);
9045 VkPipelineShaderStageCreateInfo shaderInfo = {};
9046 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9047 shaderInfo.stage = toVkShaderStage(shaderStage.type());
9048 shaderInfo.module = shader;
9049 entryPointNames.append(spirv.entryPoint());
9050 shaderInfo.pName =
nullptr;
9051 shaderStageCreateInfos.append(shaderInfo);
9056 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
9057 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
9059 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
9060 pipelineInfo.pStages = shaderStageCreateInfos.constData();
9062 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
9063#ifdef VK_EXT_vertex_attribute_divisor
9064 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
9066 int bindingIndex = 0;
9067 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
9068 it != itEnd; ++it, ++bindingIndex)
9070 VkVertexInputBindingDescription bindingInfo = {
9071 uint32_t(bindingIndex),
9073 it->classification() == QRhiVertexInputBinding::PerVertex
9074 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
9076 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
9077#ifdef VK_EXT_vertex_attribute_divisor
9078 if (rhiD->caps.vertexAttribDivisor) {
9079 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
9083 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
9084 "VK_EXT_vertex_attribute_divisor on the device and "
9085 "VK_KHR_get_physical_device_properties2 on the instance");
9088 vertexBindings.append(bindingInfo);
9090 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
9091 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
9094 VkVertexInputAttributeDescription attributeInfo = {
9095 uint32_t(it->location()),
9096 uint32_t(it->binding()),
9097 toVkAttributeFormat(it->format()),
9100 vertexAttributes.append(attributeInfo);
9102 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
9103 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
9104 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
9105 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
9106 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
9107 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
9108#ifdef VK_EXT_vertex_attribute_divisor
9109 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
9110 if (!nonOneStepRates.isEmpty()) {
9111 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
9112 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
9113 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
9114 vertexInputInfo.pNext = &divisorInfo;
9117 pipelineInfo.pVertexInputState = &vertexInputInfo;
9119 QVarLengthArray<VkDynamicState, 8> dynEnable;
9120 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
9121 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
9122 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
9123 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
9124 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
9125 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
9126#ifdef VK_KHR_fragment_shading_rate
9127 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
9128 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
9131 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
9132 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
9133 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
9134 dynamicInfo.pDynamicStates = dynEnable.constData();
9135 pipelineInfo.pDynamicState = &dynamicInfo;
9137 VkPipelineViewportStateCreateInfo viewportInfo = {};
9138 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
9139 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
9140 pipelineInfo.pViewportState = &viewportInfo;
9142 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
9143 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
9144 inputAsmInfo.topology = toVkTopology(m_topology);
9145 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
9146 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
9148 VkPipelineTessellationStateCreateInfo tessInfo = {};
9149#ifdef VK_VERSION_1_1
9150 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
9152 if (m_topology == Patches) {
9153 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
9154 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
9161#ifdef VK_VERSION_1_1
9162 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
9163 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
9164 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
9165 tessInfo.pNext = &originInfo;
9167 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
9170 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
9173 pipelineInfo.pTessellationState = &tessInfo;
9176 VkPipelineRasterizationStateCreateInfo rastInfo = {};
9177 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
9178 if (m_depthClamp && rhiD->caps.depthClamp)
9179 rastInfo.depthClampEnable = m_depthClamp;
9180 rastInfo.cullMode = toVkCullMode(m_cullMode);
9181 rastInfo.frontFace = toVkFrontFace(m_frontFace);
9182 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
9183 rastInfo.depthBiasEnable =
true;
9184 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
9185 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
9187 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
9188 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
9189 pipelineInfo.pRasterizationState = &rastInfo;
9191 VkPipelineMultisampleStateCreateInfo msInfo = {};
9192 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
9193 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
9194 pipelineInfo.pMultisampleState = &msInfo;
9196 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
9197 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
9198 dsInfo.depthTestEnable = m_depthTest;
9199 dsInfo.depthWriteEnable = m_depthWrite;
9200 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
9201 dsInfo.stencilTestEnable = m_stencilTest;
9202 if (m_stencilTest) {
9203 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
9204 dsInfo.front.compareMask = m_stencilReadMask;
9205 dsInfo.front.writeMask = m_stencilWriteMask;
9206 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
9207 dsInfo.back.compareMask = m_stencilReadMask;
9208 dsInfo.back.writeMask = m_stencilWriteMask;
9210 pipelineInfo.pDepthStencilState = &dsInfo;
9212 VkPipelineColorBlendStateCreateInfo blendInfo = {};
9213 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
9214 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
9215 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
9216 VkPipelineColorBlendAttachmentState blend = {};
9217 blend.blendEnable = b.enable;
9218 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
9219 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
9220 blend.colorBlendOp = toVkBlendOp(b.opColor);
9221 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
9222 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
9223 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
9224 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
9225 vktargetBlends.append(blend);
9227 if (vktargetBlends.isEmpty()) {
9228 VkPipelineColorBlendAttachmentState blend = {};
9229 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
9230 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
9231 vktargetBlends.append(blend);
9233 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
9234 blendInfo.pAttachments = vktargetBlends.constData();
9235 pipelineInfo.pColorBlendState = &blendInfo;
9237 pipelineInfo.layout = layout;
9239 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
9240 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
9242 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9244 if (err != VK_SUCCESS) {
9245 qWarning(
"Failed to create graphics pipeline: %d", err);
9248 pipelineLayoutCleanup.dismiss();
9250 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9252 rhiD->pipelineCreationEnd();
9255 rhiD->registerResource(
this);
9271 if (!pipeline && !layout)
9278 e.pipelineState.pipeline = pipeline;
9279 e.pipelineState.layout = layout;
9281 pipeline = VK_NULL_HANDLE;
9282 layout = VK_NULL_HANDLE;
9286 rhiD->releaseQueue.append(e);
9287 rhiD->unregisterResource(
this);
9293 if (pipeline || layout)
9297 rhiD->pipelineCreationStart();
9298 if (!rhiD->ensurePipelineCache())
9301 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9302 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9303 pipelineLayoutInfo.setLayoutCount = 1;
9305 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9306 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9307 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9308 if (err != VK_SUCCESS) {
9309 qWarning(
"Failed to create pipeline layout: %d", err);
9312 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9313 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9314 layout = VK_NULL_HANDLE;
9317 VkComputePipelineCreateInfo pipelineInfo = {};
9318 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9319 pipelineInfo.layout = layout;
9321 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9322 qWarning(
"Compute pipeline requires a compute shader stage");
9325 const QShader bakedShader = m_shaderStage.shader();
9326 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9327 if (spirv.shader().isEmpty()) {
9328 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9331 if (bakedShader.stage() != QShader::ComputeStage) {
9332 qWarning() << bakedShader <<
"is not a compute shader";
9335 VkShaderModule shader = rhiD->createShader(spirv.shader());
9338 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9339 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9341 VkPipelineShaderStageCreateInfo shaderInfo = {};
9342 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9343 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9344 shaderInfo.module = shader;
9345 const QByteArray entryPointName = spirv.entryPoint();
9346 shaderInfo.pName = entryPointName.constData();
9347 pipelineInfo.stage = shaderInfo;
9349 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9350 if (err != VK_SUCCESS) {
9351 qWarning(
"Failed to create graphics pipeline: %d", err);
9354 pipelineLayoutCleanup.dismiss();
9356 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9358 rhiD->pipelineCreationEnd();
9361 rhiD->registerResource(
this);
9390 nativeHandlesStruct.commandBuffer = cb;
9392 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9393 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9395 nativeHandlesStruct.commandBuffer = cb;
9398 return &nativeHandlesStruct;
9416 if (sc == VK_NULL_HANDLE)
9421 rhiD->swapchains.remove(
this);
9427 frame.cmdBuf = VK_NULL_HANDLE;
9431 surface = lastConnectedSurface = VK_NULL_HANDLE;
9434 rhiD->unregisterResource(
this);
9449 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9459 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9461 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9462 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9463 if (bufferSize.width == uint32_t(-1)) {
9464 Q_ASSERT(bufferSize.height == uint32_t(-1));
9465 return m_window->size() * m_window->devicePixelRatio();
9467 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9473 case QRhiSwapChain::HDRExtendedSrgbLinear:
9474 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9475 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9476 case QRhiSwapChain::HDR10:
9477 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9478 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9479 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9480 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9481 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9494 qWarning(
"Attempted to call isFormatSupported() without a window set");
9499 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9502 uint32_t formatCount = 0;
9503 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9504 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9506 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9507 for (uint32_t i = 0; i < formatCount; ++i) {
9508 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9520 QRHI_RES_RHI(QRhiVulkan);
9522 if (m_window && rhiD->adapterLuidValid)
9523 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9537 if (!rhiD->createDefaultRenderPass(rp,
9538 m_depthStencil !=
nullptr,
9549 rhiD->registerResource(rp);
9556 case VK_FORMAT_R8_SRGB:
9557 case VK_FORMAT_R8G8_SRGB:
9558 case VK_FORMAT_R8G8B8_SRGB:
9559 case VK_FORMAT_B8G8R8_SRGB:
9560 case VK_FORMAT_R8G8B8A8_SRGB:
9561 case VK_FORMAT_B8G8R8A8_SRGB:
9562 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9577 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9579 qWarning(
"Failed to get surface for window");
9582 if (surface == surf)
9588 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9589 qWarning(
"Presenting not supported on this window");
9593 quint32 formatCount = 0;
9594 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9595 QList<VkSurfaceFormatKHR> formats(formatCount);
9596 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9600 colorFormat = formats.constFirst().format;
9601 colorSpace = formats.constFirst().colorSpace;
9604 const bool srgbRequested = m_flags.testFlag(sRGB);
9605 bool foundBestFormat =
false;
9606 if (m_format == SDR) {
9607 for (
int i = 0; i <
int(formatCount); ++i) {
9609 if (srgbRequested) {
9610 ok = defaultSrgbColorFormat == formats[i].format;
9612 ok = defaultColorFormat == formats[i].format;
9615 foundBestFormat =
true;
9616 colorFormat = formats[i].format;
9617 colorSpace = formats[i].colorSpace;
9624 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9625 for (
int i = 0; i <
int(formatCount); ++i) {
9627 if (m_format != SDR) {
9628 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9629 }
else if (srgbRequested) {
9630 ok = isSrgbFormat(formats[i].format);
9633 colorFormat = formats[i].format;
9634 colorSpace = formats[i].colorSpace;
9641 if (m_format != SDR) {
9642 VkSurfaceFormatKHR format{};
9643 format.format = colorFormat;
9644 format.colorSpace = colorSpace;
9645 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9646 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9650 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9651 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9656#if QT_CONFIG(wayland)
9661 const bool hasPassThrough =
9662 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9663 return fmt.format == colorFormat
9664 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9666 if (hasPassThrough) {
9667 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9671 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9673 quint32 presModeCount = 0;
9674 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9675 supportedPresentationModes.resize(presModeCount);
9676 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9677 supportedPresentationModes.data());
9685 const bool needsRegistration = !window || window != m_window;
9692 if (window && window != m_window)
9696 m_currentPixelSize = surfacePixelSize();
9697 pixelSize = m_currentPixelSize;
9700 qWarning(
"Failed to create new swapchain");
9704 if (needsRegistration || !rhiD->swapchains.contains(
this))
9705 rhiD->swapchains.insert(
this);
9707 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9708 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9709 m_depthStencil->sampleCount(), m_sampleCount);
9711 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9712 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9713 m_depthStencil->setPixelSize(pixelSize);
9714 if (!m_depthStencil->create())
9715 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9716 pixelSize.width(), pixelSize.height());
9718 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9719 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9720 pixelSize.width(), pixelSize.height());
9724 if (!m_renderPassDesc)
9725 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9727 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9728 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9729 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9731 rtWrapper.d.pixelSize = pixelSize;
9732 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9733 rtWrapper.d.sampleCount = samples;
9734 rtWrapper.d.colorAttCount = 1;
9735 if (m_depthStencil) {
9736 rtWrapper.d.dsAttCount = 1;
9737 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9739 rtWrapper.d.dsAttCount = 0;
9742 rtWrapper.d.dsResolveAttCount = 0;
9743 if (samples > VK_SAMPLE_COUNT_1_BIT)
9744 rtWrapper.d.resolveAttCount = 1;
9746 rtWrapper.d.resolveAttCount = 0;
9748 if (shadingRateMapView)
9749 rtWrapper.d.shadingRateAttCount = 1;
9751 rtWrapper.d.shadingRateAttCount = 0;
9756 QVarLengthArray<VkImageView, 4> views;
9757 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9759 views.append(
ds->imageView);
9760 if (samples > VK_SAMPLE_COUNT_1_BIT)
9761 views.append(image.imageView);
9762 if (shadingRateMapView)
9763 views.append(shadingRateMapView);
9765 VkFramebufferCreateInfo fbInfo = {};
9766 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9767 fbInfo.renderPass = rtWrapper.d.rp->rp;
9768 fbInfo.attachmentCount = uint32_t(views.count());
9769 fbInfo.pAttachments = views.constData();
9770 fbInfo.width = uint32_t(pixelSize.width());
9771 fbInfo.height = uint32_t(pixelSize.height());
9774 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9775 if (err != VK_SUCCESS) {
9776 qWarning(
"Failed to create framebuffer: %d", err);
9782 rtWrapperRight.setRenderPassDescriptor(
9784 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9785 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9787 rtWrapperRight.d.pixelSize = pixelSize;
9788 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9789 rtWrapperRight.d.sampleCount = samples;
9790 rtWrapperRight.d.colorAttCount = 1;
9791 if (m_depthStencil) {
9792 rtWrapperRight.d.dsAttCount = 1;
9793 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9795 rtWrapperRight.d.dsAttCount = 0;
9798 rtWrapperRight.d.dsResolveAttCount = 0;
9799 if (samples > VK_SAMPLE_COUNT_1_BIT)
9800 rtWrapperRight.d.resolveAttCount = 1;
9802 rtWrapperRight.d.resolveAttCount = 0;
9807 QVarLengthArray<VkImageView, 4> views;
9808 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9810 views.append(
ds->imageView);
9811 if (samples > VK_SAMPLE_COUNT_1_BIT)
9812 views.append(image.imageView);
9813 if (shadingRateMapView)
9814 views.append(shadingRateMapView);
9816 VkFramebufferCreateInfo fbInfo = {};
9817 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9818 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9819 fbInfo.attachmentCount = uint32_t(views.count());
9820 fbInfo.pAttachments = views.constData();
9821 fbInfo.width = uint32_t(pixelSize.width());
9822 fbInfo.height = uint32_t(pixelSize.height());
9825 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9826 if (err != VK_SUCCESS) {
9827 qWarning(
"Failed to create framebuffer: %d", err);
9835 if (needsRegistration)
9836 rhiD->registerResource(
this);
const char * constData() 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)
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 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 bool isSrgbFormat(VkFormat format)
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 bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, const VkSurfaceFormatKHR &s)
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
\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
QVkCommandBuffer(QRhiImplementation *rhi)
const QRhiNativeHandles * nativeHandles()
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
int currentPassResTrackerIndex
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkComputePipeline(QRhiImplementation *rhi)
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
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QRhiRenderTarget * currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override
bool isFormatSupported(Format f) override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
QVkSwapChain(QRhiImplementation *rhi)
QSize surfacePixelSize() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderTarget * currentFrameRenderTarget() override
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::limitsType
QRhiCommandBuffer * currentFrameCommandBuffer() override
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)