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 *> devLayers;
820 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
821 devLayers.append(
"VK_LAYER_KHRONOS_validation");
823 QList<
const char *> requestedDevExts;
824 requestedDevExts.append(
"VK_KHR_swapchain");
826 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
828 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
829 if (hasPhysDevProp2) {
830 requestedDevExts.append(
"VK_KHR_portability_subset");
832 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
833 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
838#ifdef VK_EXT_vertex_attribute_divisor
839 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
840 if (hasPhysDevProp2) {
841 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
842 caps.vertexAttribDivisor =
true;
847#ifdef VK_KHR_create_renderpass2
848 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
849 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
850 caps.renderPass2KHR =
true;
854#ifdef VK_KHR_depth_stencil_resolve
855 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
856 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
857 caps.depthStencilResolveKHR =
true;
861#ifdef VK_KHR_fragment_shading_rate
862 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
863 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
866#ifdef VK_EXT_device_fault
867 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
868 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
869 caps.deviceFault =
true;
873 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
874 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
875 if (devExts.contains(ext)) {
876 requestedDevExts.append(ext.constData());
878 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
884 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
885 for (
const QByteArray &ext : envExtList) {
886 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
887 if (devExts.contains(ext)) {
888 requestedDevExts.append(ext.constData());
890 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
896 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
897 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
898 for (
const char *ext : std::as_const(requestedDevExts))
899 qCDebug(QRHI_LOG_INFO,
" %s", ext);
902 VkDeviceCreateInfo devInfo = {};
903 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
904 devInfo.queueCreateInfoCount = 1;
905 devInfo.pQueueCreateInfos = &queueInfo;
906 devInfo.enabledLayerCount = uint32_t(devLayers.size());
907 devInfo.ppEnabledLayerNames = devLayers.constData();
908 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
909 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
925 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
928 physDevFeatures13.robustImageAccess = VK_FALSE;
932 if (caps.apiVersion >= QVersionNumber(1, 1)) {
939 devInfo.pNext = &physDevFeaturesChainable;
943 physDevFeatures.robustBufferAccess = VK_FALSE;
944 devInfo.pEnabledFeatures = &physDevFeatures;
947 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
948 if (err != VK_SUCCESS) {
949 qWarning(
"Failed to create device: %d", err);
953 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
958 caps.deviceFault =
true;
959 caps.vertexAttribDivisor =
true;
960 caps.renderPass2KHR =
true;
961 caps.depthStencilResolveKHR =
true;
964 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
965 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
966 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
967 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
968 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
969 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
971 df = inst->deviceFunctions(dev);
973 VkCommandPoolCreateInfo poolInfo = {};
974 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
975 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
977 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
978 if (err != VK_SUCCESS) {
979 qWarning(
"Failed to create command pool: %d", err);
984 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
985 gfxQueueFamilyIdx, gfxQueueIdx);
988 if (gfxQueueFlags && caps.apiVersion >= QVersionNumber(1, 1)) {
989 VkDeviceQueueInfo2 queueInfo = {};
990 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
991 queueInfo.flags = gfxQueueFlags;
992 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
993 queueInfo.queueIndex = gfxQueueIdx;
994 df->vkGetDeviceQueue2(dev, &queueInfo, &gfxQueue);
997 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
999 if (queueFamilyProps.isEmpty())
1000 queryQueueFamilyProps();
1002 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
1003 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
1005 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
1008 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
1010 caps.depthClamp = physDevFeatures.depthClamp;
1012 caps.wideLines = physDevFeatures.wideLines;
1014 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
1016 caps.tessellation = physDevFeatures.tessellationShader;
1017 caps.geometryShader = physDevFeatures.geometryShader;
1019 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
1021 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
1023#ifdef VK_VERSION_1_2
1024 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1025 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1026 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
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;
1086 adapterLuidValid =
false;
1088#ifdef VK_VERSION_1_2
1089 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1090 VkPhysicalDeviceVulkan11Properties v11props = {};
1091 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1092 VkPhysicalDeviceProperties2 props2 = {};
1093 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1094 props2.pNext = &v11props;
1095 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1096 if (v11props.deviceLUIDValid) {
1097 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1098 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1099 adapterLuidValid =
true;
1100 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1101 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1102 adapterLuid.LowPart, adapterLuid.HighPart);
1109 VmaVulkanFunctions funcs = {};
1110 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1111 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1113 VmaAllocatorCreateInfo allocatorInfo = {};
1116 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1117 allocatorInfo.physicalDevice = physDev;
1118 allocatorInfo.device = dev;
1119 allocatorInfo.pVulkanFunctions = &funcs;
1120 allocatorInfo.instance = inst->vkInstance();
1128#ifdef VK_VERSION_1_4
1129 if (caps.apiVersion >= QVersionNumber(1, 4))
1130 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1133#ifdef VK_VERSION_1_3
1134 if (caps.apiVersion >= QVersionNumber(1, 3))
1135 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1138#ifdef VK_VERSION_1_2
1139 if (caps.apiVersion >= QVersionNumber(1, 2))
1140 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1143#ifdef VK_VERSION_1_1
1144 if (caps.apiVersion >= QVersionNumber(1, 1))
1145 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1148#ifdef VK_VERSION_1_0
1149 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1152 VmaAllocator vmaallocator;
1153 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1154 if (err != VK_SUCCESS) {
1155 qWarning(
"Failed to create allocator: %d", err);
1161 inst->installDebugOutputFilter(qvk_debug_filter);
1163 VkDescriptorPool pool;
1164 VkResult err = createDescriptorPool(&pool);
1165 if (err == VK_SUCCESS)
1166 descriptorPools.append(pool);
1168 qWarning(
"Failed to create initial descriptor pool: %d", err);
1170 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1171 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1172 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1174 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1175 if (err != VK_SUCCESS) {
1176 qWarning(
"Failed to create timestamp query pool: %d", err);
1179 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1180 timestampQueryPoolMap.fill(
false);
1182#ifdef VK_EXT_debug_utils
1183 if (caps.debugUtils) {
1184 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1185 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1186 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1187 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1191#ifdef VK_EXT_device_fault
1192 if (caps.deviceFault) {
1193 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1199 nativeHandlesStruct.physDev = physDev;
1200 nativeHandlesStruct.dev = dev;
1201 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1202 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1203 nativeHandlesStruct.gfxQueueFlags = gfxQueueFlags;
1204 nativeHandlesStruct.gfxQueue = gfxQueue;
1205 nativeHandlesStruct.vmemAllocator = allocator;
1206 nativeHandlesStruct.inst = inst;
1217 df->vkDeviceWaitIdle(dev);
1224 dxgiHdrInfo =
nullptr;
1228 if (ofr.cmdFence[i]) {
1229 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1230 ofr.cmdFence[i] = VK_NULL_HANDLE;
1232 ofr.cmdFenceWaitable[i] =
false;
1235 if (pipelineCache) {
1236 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1237 pipelineCache = VK_NULL_HANDLE;
1240 for (
const DescriptorPoolData &pool : descriptorPools)
1241 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1243 descriptorPools.clear();
1245 if (timestampQueryPool) {
1246 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1247 timestampQueryPool = VK_NULL_HANDLE;
1251 vmaDestroyAllocator(toVmaAllocator(allocator));
1257 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1258 cmdPool[i] = VK_NULL_HANDLE;
1260 freeSecondaryCbs[i].clear();
1261 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1264 if (!importedDevice && dev) {
1265 df->vkDestroyDevice(dev,
nullptr);
1266 inst->resetDeviceFunctions(dev);
1267 dev = VK_NULL_HANDLE;
1277QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1279 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1280 if (nativeHandles) {
1281 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1282 requestedPhysDev = h->physDev;
1285 QRhi::AdapterList list;
1286 QVulkanFunctions *f = inst->functions();
1287 uint32_t physDevCount = 0;
1288 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1292 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1293 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1294 if (err != VK_SUCCESS || !physDevCount)
1297 VkPhysicalDeviceProperties physDevProperties = {};
1298 for (uint32_t i = 0; i < physDevCount; ++i) {
1299 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1302 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1303 QVulkanAdapter *a =
new QVulkanAdapter;
1304 a->physDev = physDevs[i];
1305 fillDriverInfo(&a->adapterInfo, physDevProperties);
1319 VkDescriptorPoolSize descPoolSizes[] = {
1320 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1321 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1322 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1323 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1324 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1325 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1326 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1328 VkDescriptorPoolCreateInfo descPoolInfo = {};
1329 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1333 descPoolInfo.flags = 0;
1335 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1336 descPoolInfo.pPoolSizes = descPoolSizes;
1337 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1342 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1343 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1344 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1345 if (r == VK_SUCCESS)
1346 descriptorPools[poolIndex].refCount += 1;
1350 int lastPoolIdx = descriptorPools.size() - 1;
1351 for (
int i = lastPoolIdx; i >= 0; --i) {
1352 if (descriptorPools[i].refCount == 0) {
1353 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1354 descriptorPools[i].allocedDescSets = 0;
1356 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1357 VkResult err = tryAllocate(i);
1358 if (err == VK_SUCCESS) {
1359 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1360 *resultPoolIndex = i;
1366 VkDescriptorPool newPool;
1367 VkResult poolErr = createDescriptorPool(&newPool);
1368 if (poolErr == VK_SUCCESS) {
1369 descriptorPools.append(newPool);
1370 lastPoolIdx = descriptorPools.size() - 1;
1371 VkResult err = tryAllocate(lastPoolIdx);
1372 if (err != VK_SUCCESS) {
1373 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1376 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1377 *resultPoolIndex = lastPoolIdx;
1380 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1387 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1389 case QRhiTexture::RGBA8:
1390 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1391 case QRhiTexture::BGRA8:
1392 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1393 case QRhiTexture::R8:
1394 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1395 case QRhiTexture::RG8:
1396 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1397 case QRhiTexture::R16:
1398 return VK_FORMAT_R16_UNORM;
1399 case QRhiTexture::RG16:
1400 return VK_FORMAT_R16G16_UNORM;
1401 case QRhiTexture::RED_OR_ALPHA8:
1402 return VK_FORMAT_R8_UNORM;
1404 case QRhiTexture::RGBA16F:
1405 return VK_FORMAT_R16G16B16A16_SFLOAT;
1406 case QRhiTexture::RGBA32F:
1407 return VK_FORMAT_R32G32B32A32_SFLOAT;
1408 case QRhiTexture::R16F:
1409 return VK_FORMAT_R16_SFLOAT;
1410 case QRhiTexture::R32F:
1411 return VK_FORMAT_R32_SFLOAT;
1413 case QRhiTexture::RGB10A2:
1415 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1417 case QRhiTexture::R8SI:
1418 return VK_FORMAT_R8_SINT;
1419 case QRhiTexture::R32SI:
1420 return VK_FORMAT_R32_SINT;
1421 case QRhiTexture::RG32SI:
1422 return VK_FORMAT_R32G32_SINT;
1423 case QRhiTexture::RGBA32SI:
1424 return VK_FORMAT_R32G32B32A32_SINT;
1426 case QRhiTexture::R8UI:
1427 return VK_FORMAT_R8_UINT;
1428 case QRhiTexture::R32UI:
1429 return VK_FORMAT_R32_UINT;
1430 case QRhiTexture::RG32UI:
1431 return VK_FORMAT_R32G32_UINT;
1432 case QRhiTexture::RGBA32UI:
1433 return VK_FORMAT_R32G32B32A32_UINT;
1435 case QRhiTexture::D16:
1436 return VK_FORMAT_D16_UNORM;
1437 case QRhiTexture::D24:
1438 return VK_FORMAT_X8_D24_UNORM_PACK32;
1439 case QRhiTexture::D24S8:
1440 return VK_FORMAT_D24_UNORM_S8_UINT;
1441 case QRhiTexture::D32F:
1442 return VK_FORMAT_D32_SFLOAT;
1443 case QRhiTexture::D32FS8:
1444 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1446 case QRhiTexture::BC1:
1447 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1448 case QRhiTexture::BC2:
1449 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1450 case QRhiTexture::BC3:
1451 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1452 case QRhiTexture::BC4:
1453 return VK_FORMAT_BC4_UNORM_BLOCK;
1454 case QRhiTexture::BC5:
1455 return VK_FORMAT_BC5_UNORM_BLOCK;
1456 case QRhiTexture::BC6H:
1457 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1458 case QRhiTexture::BC7:
1459 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1461 case QRhiTexture::ETC2_RGB8:
1462 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1463 case QRhiTexture::ETC2_RGB8A1:
1464 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1465 case QRhiTexture::ETC2_RGBA8:
1466 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1468 case QRhiTexture::ASTC_4x4:
1469 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1470 case QRhiTexture::ASTC_5x4:
1471 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1472 case QRhiTexture::ASTC_5x5:
1473 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1474 case QRhiTexture::ASTC_6x5:
1475 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1476 case QRhiTexture::ASTC_6x6:
1477 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1478 case QRhiTexture::ASTC_8x5:
1479 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1480 case QRhiTexture::ASTC_8x6:
1481 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1482 case QRhiTexture::ASTC_8x8:
1483 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1484 case QRhiTexture::ASTC_10x5:
1485 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1486 case QRhiTexture::ASTC_10x6:
1487 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1488 case QRhiTexture::ASTC_10x8:
1489 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1490 case QRhiTexture::ASTC_10x10:
1491 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1492 case QRhiTexture::ASTC_12x10:
1493 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1494 case QRhiTexture::ASTC_12x12:
1495 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1498 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1505 case VK_FORMAT_R8G8B8A8_UNORM:
1506 return QRhiTexture::RGBA8;
1507 case VK_FORMAT_R8G8B8A8_SRGB:
1509 (*flags) |= QRhiTexture::sRGB;
1510 return QRhiTexture::RGBA8;
1511 case VK_FORMAT_B8G8R8A8_UNORM:
1512 return QRhiTexture::BGRA8;
1513 case VK_FORMAT_B8G8R8A8_SRGB:
1515 (*flags) |= QRhiTexture::sRGB;
1516 return QRhiTexture::BGRA8;
1517 case VK_FORMAT_R16G16B16A16_SFLOAT:
1518 return QRhiTexture::RGBA16F;
1519 case VK_FORMAT_R32G32B32A32_SFLOAT:
1520 return QRhiTexture::RGBA32F;
1521 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1522 return QRhiTexture::RGB10A2;
1524 qWarning(
"VkFormat %d cannot be read back", format);
1527 return QRhiTexture::UnknownFormat;
1533 case QRhiTexture::Format::D16:
1534 case QRhiTexture::Format::D24:
1535 case QRhiTexture::Format::D24S8:
1536 case QRhiTexture::Format::D32F:
1537 case QRhiTexture::Format::D32FS8:
1548 case QRhiTexture::Format::D24S8:
1549 case QRhiTexture::Format::D32FS8:
1559 if (isDepthTextureFormat(format)) {
1560 if (isStencilTextureFormat(format))
1561 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1563 return VK_IMAGE_ASPECT_DEPTH_BIT;
1565 return VK_IMAGE_ASPECT_COLOR_BIT;
1576 VkPhysicalDeviceMemoryProperties physDevMemProps;
1577 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1579 VkMemoryRequirements memReq;
1580 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1581 uint32_t memTypeIndex = uint32_t(-1);
1583 if (memReq.memoryTypeBits) {
1585 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1586 bool foundDevLocal =
false;
1587 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1588 if (memReq.memoryTypeBits & (1 << i)) {
1589 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1590 if (!foundDevLocal) {
1591 foundDevLocal =
true;
1594 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1603 return memTypeIndex;
1607 const QSize &pixelSize,
1608 VkImageUsageFlags usage,
1609 VkImageAspectFlags aspectMask,
1610 VkSampleCountFlagBits samples,
1611 VkDeviceMemory *mem,
1616 VkMemoryRequirements memReq;
1619 *mem = VK_NULL_HANDLE;
1620 for (
int i = 0; i < count; ++i) {
1621 images[i] = VK_NULL_HANDLE;
1622 views[i] = VK_NULL_HANDLE;
1625 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1626 for (
int i = 0; i < count; ++i) {
1628 df->vkDestroyImageView(dev, views[i],
nullptr);
1629 views[i] = VK_NULL_HANDLE;
1632 df->vkDestroyImage(dev, images[i],
nullptr);
1633 images[i] = VK_NULL_HANDLE;
1637 df->vkFreeMemory(dev, *mem,
nullptr);
1638 *mem = VK_NULL_HANDLE;
1642 for (
int i = 0; i < count; ++i) {
1643 VkImageCreateInfo imgInfo = {};
1644 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1645 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1646 imgInfo.format = format;
1647 imgInfo.extent.width = uint32_t(pixelSize.width());
1648 imgInfo.extent.height = uint32_t(pixelSize.height());
1649 imgInfo.extent.depth = 1;
1650 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1651 imgInfo.samples = samples;
1652 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1653 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1654 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1656 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1657 if (err != VK_SUCCESS) {
1658 qWarning(
"Failed to create image: %d", err);
1665 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1668 VkMemoryAllocateInfo memInfo = {};
1669 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1670 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1672 uint32_t startIndex = 0;
1674 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1675 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1676 qWarning(
"No suitable memory type found");
1679 startIndex = memInfo.memoryTypeIndex + 1;
1680 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1681 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1682 qWarning(
"Failed to allocate image memory: %d", err);
1685 }
while (err != VK_SUCCESS);
1687 VkDeviceSize ofs = 0;
1688 for (
int i = 0; i < count; ++i) {
1689 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1690 if (err != VK_SUCCESS) {
1691 qWarning(
"Failed to bind image memory: %d", err);
1694 ofs += aligned(memReq.size, memReq.alignment);
1696 VkImageViewCreateInfo imgViewInfo = {};
1697 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1698 imgViewInfo.image = images[i];
1699 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1700 imgViewInfo.format = format;
1701 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1702 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1703 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1704 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1705 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1706 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1708 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1709 if (err != VK_SUCCESS) {
1710 qWarning(
"Failed to create image view: %d", err);
1721 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1722 return optimalDsFormat;
1724 const VkFormat dsFormatCandidates[] = {
1725 VK_FORMAT_D24_UNORM_S8_UINT,
1726 VK_FORMAT_D32_SFLOAT_S8_UINT,
1727 VK_FORMAT_D16_UNORM_S8_UINT
1729 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1730 int dsFormatIdx = 0;
1731 while (dsFormatIdx < dsFormatCandidateCount) {
1732 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1733 VkFormatProperties fmtProp;
1734 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1735 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1739 if (dsFormatIdx == dsFormatCandidateCount)
1740 qWarning(
"Failed to find an optimal depth-stencil format");
1742 return optimalDsFormat;
1747 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1749 if (multiViewCount < 2)
1751 if (!multiViewCap) {
1752 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1755#ifdef VK_VERSION_1_1
1756 uint32_t allViewsMask = 0;
1757 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1758 allViewsMask |= (1 << i);
1759 multiViewMask = allViewsMask;
1760 multiViewCorrelationMask = allViewsMask;
1761 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1762 multiViewInfo.subpassCount = 1;
1763 multiViewInfo.pViewMasks = &multiViewMask;
1764 multiViewInfo.correlationMaskCount = 1;
1765 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1766 rpInfo->pNext = &multiViewInfo;
1771#ifdef VK_VERSION_1_1
1778#ifdef VK_KHR_create_renderpass2
1782struct RenderPass2SetupHelper
1784 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1786 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1790 if (multiViewCount >= 2) {
1791 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1792 viewMask |= (1 << i);
1795 attDescs2.resize(rpInfo->attachmentCount);
1796 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1797 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1798 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1800 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1801 att2.flags = att.flags;
1802 att2.format = att.format;
1803 att2.samples = att.samples;
1804 att2.loadOp = att.loadOp;
1805 att2.storeOp = att.storeOp;
1806 att2.stencilLoadOp = att.stencilLoadOp;
1807 att2.stencilStoreOp = att.stencilStoreOp;
1808 att2.initialLayout = att.initialLayout;
1809 att2.finalLayout = att.finalLayout;
1814 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1815 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1816 subpass2.flags = subpassDesc.flags;
1817 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1818 if (multiViewCount >= 2)
1819 subpass2.viewMask = viewMask;
1822 qsizetype startIndex = attRefs2.count();
1823 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1824 attRefs2.append({});
1825 VkAttachmentReference2KHR &attref2(attRefs2.last());
1826 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1827 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1828 attref2.attachment = attref.attachment;
1829 attref2.layout = attref.layout;
1830 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1832 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1833 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1836 if (subpassDesc.pResolveAttachments) {
1837 startIndex = attRefs2.count();
1838 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1839 attRefs2.append({});
1840 VkAttachmentReference2KHR &attref2(attRefs2.last());
1841 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1842 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1843 attref2.attachment = attref.attachment;
1844 attref2.layout = attref.layout;
1845 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1847 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1851 if (subpassDesc.pDepthStencilAttachment) {
1852 startIndex = attRefs2.count();
1853 attRefs2.append({});
1854 VkAttachmentReference2KHR &attref2(attRefs2.last());
1855 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1856 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1857 attref2.attachment = attref.attachment;
1858 attref2.layout = attref.layout;
1859 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1860 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1864#ifdef VK_KHR_depth_stencil_resolve
1866 if (rpD->hasDepthStencilResolve) {
1867 startIndex = attRefs2.count();
1868 attRefs2.append({});
1869 VkAttachmentReference2KHR &attref2(attRefs2.last());
1870 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1871 attref2.attachment = rpD->dsResolveRef.attachment;
1872 attref2.layout = rpD->dsResolveRef.layout;
1873 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1874 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1875 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1876 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1877 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1878 addToChain(&subpass2, &dsResolveDesc);
1882#ifdef VK_KHR_fragment_shading_rate
1883 shadingRateAttInfo = {};
1884 if (rpD->hasShadingRateMap) {
1885 startIndex = attRefs2.count();
1886 attRefs2.append({});
1887 VkAttachmentReference2KHR &attref2(attRefs2.last());
1888 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1889 attref2.attachment = rpD->shadingRateRef.attachment;
1890 attref2.layout = rpD->shadingRateRef.layout;
1891 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1892 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1893 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1894 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1895 addToChain(&subpass2, &shadingRateAttInfo);
1901 subpassDeps2.clear();
1902 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1903 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1904 subpassDeps2.append({});
1905 VkSubpassDependency2 &dep2(subpassDeps2.last());
1906 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1907 dep2.srcSubpass = dep.srcSubpass;
1908 dep2.dstSubpass = dep.dstSubpass;
1909 dep2.srcStageMask = dep.srcStageMask;
1910 dep2.dstStageMask = dep.dstStageMask;
1911 dep2.srcAccessMask = dep.srcAccessMask;
1912 dep2.dstAccessMask = dep.dstAccessMask;
1913 dep2.dependencyFlags = dep.dependencyFlags;
1916 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1917 rpInfo2->pNext =
nullptr;
1918 rpInfo2->flags = rpInfo->flags;
1919 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1920 rpInfo2->pAttachments = attDescs2.constData();
1921 rpInfo2->subpassCount = 1;
1922 rpInfo2->pSubpasses = &subpass2;
1923 rpInfo2->dependencyCount = subpassDeps2.count();
1924 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1925 if (multiViewCount >= 2) {
1926 rpInfo2->correlatedViewMaskCount = 1;
1927 rpInfo2->pCorrelatedViewMasks = &viewMask;
1933 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1934 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1935 VkSubpassDescription2KHR subpass2;
1936 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1937#ifdef VK_KHR_depth_stencil_resolve
1938 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1940#ifdef VK_KHR_fragment_shading_rate
1941 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1948 VkSubpassDescription *subpassDesc,
1951 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1952 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1953 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1954 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1955 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1956 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1958 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1959 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1960 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1961 rpInfo->pAttachments = rpD->attDescs.constData();
1962 rpInfo->subpassCount = 1;
1963 rpInfo->pSubpasses = subpassDesc;
1964 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1965 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1969 bool hasDepthStencil,
1970 VkSampleCountFlagBits samples,
1971 VkFormat colorFormat,
1972 QRhiShadingRateMap *shadingRateMap)
1976 VkAttachmentDescription attDesc = {};
1977 attDesc.format = colorFormat;
1978 attDesc.samples = samples;
1979 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1980 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1981 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1982 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1983 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1984 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1985 rpD->attDescs.append(attDesc);
1987 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1992 rpD->multiViewCount = 0;
1994 if (hasDepthStencil) {
1998 attDesc.format = optimalDepthStencilFormat();
1999 attDesc.samples = samples;
2000 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2001 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2002 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2003 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2004 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2005 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2006 rpD->attDescs.append(attDesc);
2008 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2013 if (samples > VK_SAMPLE_COUNT_1_BIT) {
2015 attDesc.format = colorFormat;
2016 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2017 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2018 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2019 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2020 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2021 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2022 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2023 rpD->attDescs.append(attDesc);
2025 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2028 rpD->dsResolveRef = {};
2030 rpD->shadingRateRef = {};
2031#ifdef VK_KHR_fragment_shading_rate
2032 if (shadingRateMap) {
2034 attDesc.format = VK_FORMAT_R8_UINT;
2035 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2036 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2037 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2038 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2039 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2040 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2041 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2042 rpD->attDescs.append(attDesc);
2044 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2049 VkSubpassDependency subpassDep = {};
2050 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2051 subpassDep.dstSubpass = 0;
2052 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2053 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2054 subpassDep.srcAccessMask = 0;
2055 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2056 rpD->subpassDeps.append(subpassDep);
2057 if (hasDepthStencil) {
2058 memset(&subpassDep, 0,
sizeof(subpassDep));
2059 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2060 subpassDep.dstSubpass = 0;
2061 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2062 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2063 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2064 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2065 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2066 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2067 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2068 rpD->subpassDeps.append(subpassDep);
2071 VkRenderPassCreateInfo rpInfo;
2072 VkSubpassDescription subpassDesc;
2073 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2075#ifdef VK_KHR_create_renderpass2
2076 if (caps.renderPass2KHR) {
2078 VkRenderPassCreateInfo2KHR rpInfo2;
2079 RenderPass2SetupHelper rp2Helper(
this);
2080 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2082 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2083 if (err != VK_SUCCESS) {
2084 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2091 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2092 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2093 if (err != VK_SUCCESS) {
2094 qWarning(
"Failed to create renderpass: %d", err);
2103 const QRhiColorAttachment *colorAttachmentsBegin,
2104 const QRhiColorAttachment *colorAttachmentsEnd,
2108 QRhiRenderBuffer *depthStencilBuffer,
2109 QRhiTexture *depthTexture,
2110 QRhiTexture *depthResolveTexture,
2112 QRhiShadingRateMap *shadingRateMap)
2116 int multiViewCount = 0;
2117 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2120 Q_ASSERT(texD || rbD);
2121 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2122 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2124 VkAttachmentDescription attDesc = {};
2125 attDesc.format = vkformat;
2126 attDesc.samples = samples;
2127 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2128 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2129 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2130 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2132 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2133 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2134 rpD->attDescs.append(attDesc);
2136 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2137 rpD->colorRefs.append(ref);
2139 if (it->multiViewCount() >= 2) {
2140 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2141 qWarning(
"Inconsistent multiViewCount in color attachment set");
2143 multiViewCount = it->multiViewCount();
2144 }
else if (multiViewCount > 0) {
2145 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2148 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2149 rpD->multiViewCount = uint32_t(multiViewCount);
2153 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2154 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2155 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2156 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2157 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2158 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2159 VkAttachmentDescription attDesc = {};
2160 attDesc.format = dsFormat;
2161 attDesc.samples = samples;
2162 attDesc.loadOp = loadOp;
2163 attDesc.storeOp = storeOp;
2164 attDesc.stencilLoadOp = loadOp;
2165 attDesc.stencilStoreOp = storeOp;
2166 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2167 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2168 rpD->attDescs.append(attDesc);
2169 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2170 multiViewCount = depthTexture->arraySize();
2171 rpD->multiViewCount = multiViewCount;
2173 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2178 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2179 if (it->resolveTexture()) {
2181 const VkFormat dstFormat = rtexD->vkformat;
2182 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2183 qWarning(
"Resolving into a multisample texture is not supported");
2187 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2188 if (srcFormat != dstFormat) {
2192 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2193 int(srcFormat),
int(dstFormat));
2196 VkAttachmentDescription attDesc = {};
2197 attDesc.format = rtexD->viewFormat;
2198 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2199 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2200 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2201 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2202 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2203 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2204 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2205 rpD->attDescs.append(attDesc);
2207 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2208 rpD->resolveRefs.append(ref);
2210 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2211 rpD->resolveRefs.append(ref);
2214 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2219 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2220 qWarning(
"Resolving into a multisample depth texture is not supported");
2221 const VkFormat dstFormat = rtexD->vkformat;
2225 Q_ASSERT(texD || rbD);
2226 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2227 if (srcFormat != dstFormat) {
2228 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2229 int(srcFormat),
int(dstFormat));
2232 VkAttachmentDescription attDesc = {};
2233 attDesc.format = rtexD->viewFormat;
2234 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2235 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2236 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2237 attDesc.stencilLoadOp = attDesc.loadOp;
2238 attDesc.stencilStoreOp = attDesc.storeOp;
2239 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2240 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2241 rpD->attDescs.append(attDesc);
2242 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2244 rpD->dsResolveRef = {};
2248 rpD->shadingRateRef = {};
2249#ifdef VK_KHR_fragment_shading_rate
2250 if (shadingRateMap) {
2251 VkAttachmentDescription attDesc = {};
2252 attDesc.format = VK_FORMAT_R8_UINT;
2253 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2254 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2255 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2256 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2257 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2258 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2259 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2260 rpD->attDescs.append(attDesc);
2261 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2266 VkSubpassDependency selfDependency = {};
2267 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2268 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2269 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2270 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2271 selfDependency.srcSubpass = 0;
2272 selfDependency.dstSubpass = 0;
2273 selfDependency.srcStageMask = stageMask;
2274 selfDependency.dstStageMask = stageMask;
2275 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2276 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2277 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2278#ifdef VK_VERSION_1_1
2279 if (rpD->multiViewCount >= 2)
2280 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2282 selfDependency.dependencyFlags = depFlags;
2283 rpD->subpassDeps.append(selfDependency);
2290 VkRenderPassCreateInfo rpInfo;
2291 VkSubpassDescription subpassDesc;
2292 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2295 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2298#ifdef VK_KHR_create_renderpass2
2299 if (caps.renderPass2KHR) {
2301 VkRenderPassCreateInfo2KHR rpInfo2;
2302 RenderPass2SetupHelper rp2Helper(
this);
2303 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2306 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2307 if (err != VK_SUCCESS) {
2308 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2315 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2316 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2319 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2320 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2321 if (err != VK_SUCCESS) {
2322 qWarning(
"Failed to create renderpass: %d", err);
2333 if (swapChainD->pixelSize.isEmpty()) {
2334 qWarning(
"Surface size is 0, cannot create swapchain");
2338 df->vkDeviceWaitIdle(dev);
2340 if (!vkCreateSwapchainKHR) {
2341 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2342 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2343 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2344 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2345 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2346 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2347 qWarning(
"Swapchain functions not available");
2352 VkSurfaceCapabilitiesKHR surfaceCaps;
2353 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2354 quint32 reqBufferCount;
2355 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2356 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2358 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2360 VkSurfaceTransformFlagBitsKHR preTransform =
2361 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2362 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2363 : surfaceCaps.currentTransform;
2389 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2390 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2391 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2392 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2394 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2395 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2396 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2397 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2398 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2399 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2400 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2401 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2402 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2403 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2406 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2407 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2408 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2409 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2411 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2412 && surfaceCaps.maxImageArrayLayers > 1;
2415 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2416 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2420 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2421 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2422 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2423 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2431 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2433 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2434 reuseExisting ?
"recycled" :
"new",
2435 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2437 VkSwapchainCreateInfoKHR swapChainInfo = {};
2438 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2439 swapChainInfo.surface = swapChainD->surface;
2440 swapChainInfo.minImageCount = reqBufferCount;
2441 swapChainInfo.imageFormat = swapChainD->colorFormat;
2442 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2443 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2444 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2445 swapChainInfo.imageUsage = usage;
2446 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2447 swapChainInfo.preTransform = preTransform;
2448 swapChainInfo.compositeAlpha = compositeAlpha;
2449 swapChainInfo.presentMode = presentMode;
2450 swapChainInfo.clipped =
true;
2451 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2453 VkSwapchainKHR newSwapChain;
2454 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2455 if (err != VK_SUCCESS) {
2456 qWarning(
"Failed to create swapchain: %d", err);
2459 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2464 swapChainD->sc = newSwapChain;
2465 swapChainD->lastConnectedSurface = swapChainD->surface;
2467 quint32 actualSwapChainBufferCount = 0;
2468 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2469 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2470 qWarning(
"Failed to get swapchain images: %d", err);
2474 if (actualSwapChainBufferCount != reqBufferCount)
2475 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2478 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2479 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2480 if (err != VK_SUCCESS) {
2481 qWarning(
"Failed to get swapchain images: %d", err);
2485 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2486 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2487 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2488 if (!createTransientImage(swapChainD->colorFormat,
2489 swapChainD->pixelSize,
2490 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2491 VK_IMAGE_ASPECT_COLOR_BIT,
2492 swapChainD->samples,
2493 &swapChainD->msaaImageMem,
2496 swapChainD->bufferCount))
2498 qWarning(
"Failed to create transient image for MSAA color buffer");
2503 VkFenceCreateInfo fenceInfo = {};
2504 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2505 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2508 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2512 image.image = swapChainImages[i];
2513 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2514 image.msaaImage = msaaImages[i];
2515 image.msaaImageView = msaaViews[i];
2518 VkImageViewCreateInfo imgViewInfo = {};
2519 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2520 imgViewInfo.image = swapChainImages[i];
2521 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2522 imgViewInfo.format = swapChainD->colorFormat;
2523 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2524 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2525 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2526 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2527 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2528 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2529 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2530 if (err != VK_SUCCESS) {
2531 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2537 VkSemaphoreCreateInfo semInfo = {};
2538 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2539 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2544 image.image = swapChainImages[i];
2545 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2546 image.msaaImage = msaaImages[i];
2547 image.msaaImageView = msaaViews[i];
2550 VkImageViewCreateInfo imgViewInfo = {};
2551 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2552 imgViewInfo.image = swapChainImages[i];
2553 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2554 imgViewInfo.format = swapChainD->colorFormat;
2555 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2556 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2557 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2558 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2559 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2560 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2561 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2562 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2563 if (err != VK_SUCCESS) {
2564 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2568 VkSemaphoreCreateInfo semInfo = {};
2569 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2570 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2576 swapChainD->currentImageIndex = 0;
2578 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2580 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2581 VkImageViewCreateInfo viewInfo = {};
2582 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2583 viewInfo.image = texD->image;
2584 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2585 viewInfo.format = texD->viewFormat;
2586 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2587 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2588 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2589 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2590 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2591 viewInfo.subresourceRange.baseMipLevel = 0;
2592 viewInfo.subresourceRange.levelCount = 1;
2593 viewInfo.subresourceRange.baseArrayLayer = 0;
2594 viewInfo.subresourceRange.layerCount = 1;
2595 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2596 if (err != VK_SUCCESS) {
2597 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2602 VkSemaphoreCreateInfo semInfo = {};
2603 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2611 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2613 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2614 if (err != VK_SUCCESS) {
2615 qWarning(
"Failed to create command buffer fence: %d", err);
2628 if (swapChainD->sc == VK_NULL_HANDLE)
2632 df->vkDeviceWaitIdle(dev);
2636 if (frame.cmdFence) {
2638 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2639 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2640 frame.cmdFence = VK_NULL_HANDLE;
2643 if (frame.imageSem) {
2644 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2645 frame.imageSem = VK_NULL_HANDLE;
2652 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2653 image.fb = VK_NULL_HANDLE;
2655 if (image.imageView) {
2656 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2657 image.imageView = VK_NULL_HANDLE;
2659 if (image.msaaImageView) {
2660 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2661 image.msaaImageView = VK_NULL_HANDLE;
2663 if (image.msaaImage) {
2664 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2665 image.msaaImage = VK_NULL_HANDLE;
2667 if (image.drawSem) {
2668 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2669 image.drawSem = VK_NULL_HANDLE;
2673 if (swapChainD->msaaImageMem) {
2674 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2675 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2678 if (swapChainD->shadingRateMapView) {
2679 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2680 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2683 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2684 swapChainD->sc = VK_NULL_HANDLE;
2691 VkCommandPoolResetFlags flags = 0;
2696 if (releaseCachedResourcesCalledBeforeFrameStart)
2697 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2700 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2706 for (quint64 i = 0; i < timestampValidBits; i += 8)
2707 mask |= 0xFFULL << i;
2708 const quint64 ts0 = timestamp[0] & mask;
2709 const quint64 ts1 = timestamp[1] & mask;
2710 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2711 if (!qFuzzyIsNull(nsecsPerTick)) {
2712 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2713 const double elapsedSec = elapsedMs / 1000.0;
2724 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2727 inst->handle()->beginFrame(swapChainD->window);
2737 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2738 if (waitResult != QRhi::FrameOpSuccess)
2743 uint32_t imageIndex = 0;
2744 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2745 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2747 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2748 swapChainD->currentImageIndex = imageIndex;
2751 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2752 return QRhi::FrameOpSwapChainOutOfDate;
2754 if (err == VK_ERROR_DEVICE_LOST) {
2755 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2756 printExtraErrorInfo(err);
2758 return QRhi::FrameOpDeviceLost;
2760 qWarning(
"Failed to acquire next swapchain image: %d", err);
2761 return QRhi::FrameOpError;
2767 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2773 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2774 if (cbres != QRhi::FrameOpSuccess)
2777 swapChainD->cbWrapper.cb = frame.cmdBuf;
2780 swapChainD->rtWrapper.d.fb = image.fb;
2784 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2785 swapChainD->rtWrapperRight.d.fb = image.fb;
2792 quint64 timestamp[2] = { 0, 0 };
2793 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2794 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2795 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2796 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2798 if (err == VK_SUCCESS) {
2800 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2802 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2804 qWarning(
"Failed to query timestamp: %d", err);
2809 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2810 int timestampQueryIdx = -1;
2811 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2812 if (!timestampQueryPoolMap.testBit(i)) {
2813 timestampQueryPoolMap.setBit(i);
2814 timestampQueryIdx = i * 2;
2818 if (timestampQueryIdx >= 0) {
2819 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2821 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2822 timestampQueryPool, uint32_t(timestampQueryIdx));
2827 return QRhi::FrameOpSuccess;
2835 auto cleanup = qScopeGuard([
this, swapChainD] {
2836 inst->handle()->endFrame(swapChainD->window);
2841 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2846 VkImageMemoryBarrier presTrans = {};
2847 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2848 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2849 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2850 presTrans.image = image.image;
2851 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2852 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2856 presTrans.srcAccessMask = 0;
2857 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2858 df->vkCmdPipelineBarrier(frame.cmdBuf,
2859 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2860 0, 0,
nullptr, 0,
nullptr,
2864 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2865 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2866 df->vkCmdPipelineBarrier(frame.cmdBuf,
2867 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2868 0, 0,
nullptr, 0,
nullptr,
2876 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2882 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2883 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2885 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2886 needsPresent ? &image.drawSem :
nullptr);
2887 if (submitres != QRhi::FrameOpSuccess)
2895 VkPresentInfoKHR presInfo = {};
2896 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2897 presInfo.swapchainCount = 1;
2898 presInfo.pSwapchains = &swapChainD->sc;
2899 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2900 waitSemaphoresForPresent.append(image.drawSem);
2901 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2902 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2906 inst->presentAboutToBeQueued(swapChainD->window);
2908 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2909 waitSemaphoresForPresent.clear();
2910 if (err != VK_SUCCESS) {
2911 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2912 return QRhi::FrameOpSwapChainOutOfDate;
2913 }
else if (err != VK_SUBOPTIMAL_KHR) {
2914 if (err == VK_ERROR_DEVICE_LOST) {
2915 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2916 printExtraErrorInfo(err);
2918 return QRhi::FrameOpDeviceLost;
2920 qWarning(
"Failed to present: %d", err);
2921 return QRhi::FrameOpError;
2927 inst->presentQueued(swapChainD->window);
2932 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
2937 return QRhi::FrameOpSuccess;
2951 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2961 VkCommandBufferAllocateInfo cmdBufInfo = {};
2962 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2963 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2964 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2965 cmdBufInfo.commandBufferCount = 1;
2967 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2968 if (err != VK_SUCCESS) {
2969 if (err == VK_ERROR_DEVICE_LOST) {
2970 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2971 printExtraErrorInfo(err);
2973 return QRhi::FrameOpDeviceLost;
2975 qWarning(
"Failed to allocate frame command buffer: %d", err);
2976 return QRhi::FrameOpError;
2980 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2981 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2983 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2984 if (err != VK_SUCCESS) {
2985 if (err == VK_ERROR_DEVICE_LOST) {
2986 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2987 printExtraErrorInfo(err);
2989 return QRhi::FrameOpDeviceLost;
2991 qWarning(
"Failed to begin frame command buffer: %d", err);
2992 return QRhi::FrameOpError;
2995 return QRhi::FrameOpSuccess;
2999 VkSemaphore *waitSem, VkSemaphore *signalSem)
3001 VkResult err =
df->vkEndCommandBuffer(cb);
3002 if (err != VK_SUCCESS) {
3003 if (err == VK_ERROR_DEVICE_LOST) {
3004 qWarning(
"Device loss detected in vkEndCommandBuffer()");
3005 printExtraErrorInfo(err);
3007 return QRhi::FrameOpDeviceLost;
3009 qWarning(
"Failed to end frame command buffer: %d", err);
3010 return QRhi::FrameOpError;
3013 VkSubmitInfo submitInfo = {};
3014 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
3015 submitInfo.commandBufferCount = 1;
3016 submitInfo.pCommandBuffers = &cb;
3019 waitSemaphoresForQueueSubmit.append(*waitSem);
3021 signalSemaphoresForQueueSubmit.append(*signalSem);
3023 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
3024 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
3025 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
3026 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3027 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
3029 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3030 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3031 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3034 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3036 waitSemaphoresForQueueSubmit.clear();
3037 signalSemaphoresForQueueSubmit.clear();
3039 if (err != VK_SUCCESS) {
3040 if (err == VK_ERROR_DEVICE_LOST) {
3041 qWarning(
"Device loss detected in vkQueueSubmit()");
3042 printExtraErrorInfo(err);
3044 return QRhi::FrameOpDeviceLost;
3046 qWarning(
"Failed to submit to graphics queue: %d", err);
3047 return QRhi::FrameOpError;
3050 return QRhi::FrameOpSuccess;
3055 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3056 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3057 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3058 if (frame.cmdFenceWaitable) {
3059 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3061 if (err != VK_SUCCESS) {
3062 if (err == VK_ERROR_DEVICE_LOST) {
3063 qWarning(
"Device loss detected in vkWaitForFences()");
3064 printExtraErrorInfo(err);
3066 return QRhi::FrameOpDeviceLost;
3068 qWarning(
"Failed to wait for fence: %d", err);
3069 return QRhi::FrameOpError;
3072 df->vkResetFences(dev, 1, &frame.cmdFence);
3073 frame.cmdFenceWaitable =
false;
3077 if (ofr.cmdFenceWaitable[frameSlot]) {
3078 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3079 if (err != VK_SUCCESS) {
3080 if (err == VK_ERROR_DEVICE_LOST) {
3081 qWarning(
"Device loss detected in vkWaitForFences()");
3082 printExtraErrorInfo(err);
3084 return QRhi::FrameOpDeviceLost;
3086 qWarning(
"Failed to wait for offscreen fence: %d", err);
3087 return QRhi::FrameOpError;
3089 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3090 ofr.cmdFenceWaitable[frameSlot] =
false;
3093 return QRhi::FrameOpSuccess;
3098 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3099 if (waitResult != QRhi::FrameOpSuccess)
3105 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3106 if (cbres != QRhi::FrameOpSuccess)
3112 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3113 quint64 timestamp[2] = { 0, 0 };
3114 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3115 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3116 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3117 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3118 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3119 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3120 if (err == VK_SUCCESS) {
3122 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3126 qWarning(
"Failed to query timestamp: %d", err);
3130 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3131 int timestampQueryIdx = -1;
3132 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3133 if (!timestampQueryPoolMap.testBit(i)) {
3134 timestampQueryPoolMap.setBit(i);
3135 timestampQueryIdx = i * 2;
3139 if (timestampQueryIdx >= 0) {
3140 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3142 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3143 timestampQueryPool, uint32_t(timestampQueryIdx));
3144 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3149 return QRhi::FrameOpSuccess;
3155 Q_ASSERT(ofr.active);
3161 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3165 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3166 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3167 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3170 if (!ofr.cmdFence[currentFrameSlot]) {
3171 VkFenceCreateInfo fenceInfo = {};
3172 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3173 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3174 if (err != VK_SUCCESS) {
3175 qWarning(
"Failed to create command buffer fence: %d", err);
3176 return QRhi::FrameOpError;
3180 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3181 if (submitres != QRhi::FrameOpSuccess)
3184 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3187 if (readbacksPending) {
3188 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3189 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3190 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3197 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3199 return QRhi::FrameOpSuccess;
3221 swapChainD->cbWrapper.resetCommands();
3222 cb = swapChainD->cbWrapper.cb;
3224 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3225 if (submitres != QRhi::FrameOpSuccess)
3229 df->vkQueueWaitIdle(gfxQueue);
3236 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3239 startPrimaryCommandBuffer(&frame.cmdBuf);
3240 swapChainD->cbWrapper.cb = frame.cmdBuf;
3247 return QRhi::FrameOpSuccess;
3254 u
.access =
int(bufUsage.access);
3255 u
.stage =
int(bufUsage.stage);
3263 u
.access =
int(texUsage.access);
3264 u
.stage =
int(texUsage.stage);
3270 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3273 rtD->lastActiveFrameSlot = currentFrameSlot;
3274 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3276 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3284 texD->lastActiveFrameSlot = currentFrameSlot;
3289 rbD->lastActiveFrameSlot = currentFrameSlot;
3295 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3298 if (rtD->m_desc.depthStencilBuffer()) {
3300 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3307 rbD->lastActiveFrameSlot = currentFrameSlot;
3309 if (rtD->m_desc.depthTexture()) {
3314 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3316 if (rtD->m_desc.depthResolveTexture()) {
3321 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3323 if (rtD->m_desc.shadingRateMap()) {
3328 texD->lastActiveFrameSlot = currentFrameSlot;
3342 VkCommandBuffer secondaryCb;
3344 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3345 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3346 freeSecondaryCbs[currentFrameSlot].removeLast();
3348 VkCommandBufferAllocateInfo cmdBufInfo = {};
3349 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3350 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3351 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3352 cmdBufInfo.commandBufferCount = 1;
3354 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3355 if (err != VK_SUCCESS) {
3356 qWarning(
"Failed to create secondary command buffer: %d", err);
3357 return VK_NULL_HANDLE;
3361 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3362 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3363 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3364 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3365 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3366 cmdBufInheritInfo.subpass = 0;
3368 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3369 cmdBufInheritInfo.framebuffer = rtD->fb;
3371 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3373 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3374 if (err != VK_SUCCESS) {
3375 qWarning(
"Failed to begin secondary command buffer: %d", err);
3376 return VK_NULL_HANDLE;
3384 VkResult err =
df->vkEndCommandBuffer(cb);
3385 if (err != VK_SUCCESS)
3386 qWarning(
"Failed to end secondary command buffer: %d", err);
3390 cmd.args.executeSecondary.cb = cb;
3394 e.lastActiveFrameSlot = currentFrameSlot;
3395 e.secondaryCommandBuffer.cb = cb;
3396 releaseQueue.append(e);
3400 QRhiRenderTarget *rt,
3401 const QColor &colorClearValue,
3402 const QRhiDepthStencilClearValue &depthStencilClearValue,
3403 QRhiResourceUpdateBatch *resourceUpdates,
3404 QRhiCommandBuffer::BeginPassFlags flags)
3409 if (resourceUpdates)
3419 switch (rt->resourceType()) {
3420 case QRhiResource::SwapChainRenderTarget:
3422 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3432 texD->lastActiveFrameSlot = currentFrameSlot;
3435 case QRhiResource::TextureRenderTarget:
3449 cbD->currentTarget = rt;
3454 VkRenderPassBeginInfo rpBeginInfo = {};
3455 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3456 rpBeginInfo.renderPass = rtD
->rp->rp;
3457 rpBeginInfo.framebuffer = rtD->fb;
3458 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3459 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3461 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3462 [](
const VkAttachmentDescription &attDesc) {
3463 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3464 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3467 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3468 if (rpHasAnyClearOp) {
3470 VkClearValue cv = {};
3471 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3472 colorClearValue.alphaF() } };
3476 VkClearValue cv = {};
3477 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3481 VkClearValue cv = {};
3482 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3483 colorClearValue.alphaF() } };
3487 VkClearValue cv = {};
3488 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3492 VkClearValue cv = {};
3493 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3497 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3498 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3502 cmd.args.beginRenderPass.desc = rpBeginInfo;
3503 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3505 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3508 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3513 rateCmd.args.setShadingRate.w = 1;
3514 rateCmd.args.setShadingRate.h = 1;
3526 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3527 cbD->activeSecondaryCbStack.removeLast();
3528 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3535 cbD->currentTarget =
nullptr;
3537 if (resourceUpdates)
3542 QRhiResourceUpdateBatch *resourceUpdates,
3543 QRhiCommandBuffer::BeginPassFlags flags)
3548 if (resourceUpdates)
3556 cbD->computePassState.reset();
3559 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3570 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3571 cbD->activeSecondaryCbStack.removeLast();
3572 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3577 if (resourceUpdates)
3584 Q_ASSERT(psD->pipeline);
3588 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3590 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3594 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3595 cmd.args.bindPipeline.pipeline = psD->pipeline;
3598 cbD->currentGraphicsPipeline =
nullptr;
3599 cbD->currentComputePipeline = ps;
3600 cbD->currentPipelineGeneration = psD->generation;
3603 psD->lastActiveFrameSlot = currentFrameSlot;
3608 QRhiShaderResourceBinding::Type bindingType,
3609 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3611 VkAccessFlags access = 0;
3612 if (bindingType == loadTypeVal) {
3613 access = VK_ACCESS_SHADER_READ_BIT;
3615 access = VK_ACCESS_SHADER_WRITE_BIT;
3616 if (bindingType == loadStoreTypeVal)
3617 access |= VK_ACCESS_SHADER_READ_BIT;
3619 auto it = writtenResources->find(resource);
3620 if (it != writtenResources->end())
3621 it->second.accessFlags |= access;
3622 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3623 writtenResources->insert(resource, { access,
true });
3633 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3634 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3635 if (cbD->currentComputeSrb) {
3639 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3640 accessAndIsNewFlag = { 0,
false };
3643 for (
auto &binding : srbD->m_bindings) {
3644 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3646 case QRhiShaderResourceBinding::ImageLoad:
3647 case QRhiShaderResourceBinding::ImageStore:
3648 case QRhiShaderResourceBinding::ImageLoadStore:
3649 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3652 QRhiShaderResourceBinding::ImageLoad,
3653 QRhiShaderResourceBinding::ImageStore,
3654 QRhiShaderResourceBinding::ImageLoadStore);
3656 case QRhiShaderResourceBinding::BufferLoad:
3657 case QRhiShaderResourceBinding::BufferStore:
3658 case QRhiShaderResourceBinding::BufferLoadStore:
3659 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3662 QRhiShaderResourceBinding::BufferLoad,
3663 QRhiShaderResourceBinding::BufferStore,
3664 QRhiShaderResourceBinding::BufferLoadStore);
3671 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3672 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3673 const bool isNewInThisDispatch = it->second.isNew;
3674 if (accessInThisDispatch && !isNewInThisDispatch) {
3675 if (it.key()->resourceType() == QRhiResource::Texture) {
3677 VkImageMemoryBarrier barrier = {};
3678 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3679 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3681 barrier.subresourceRange.baseMipLevel = 0;
3682 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3683 barrier.subresourceRange.baseArrayLayer = 0;
3684 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3685 barrier.oldLayout = texD->usageState.layout;
3686 barrier.newLayout = texD->usageState.layout;
3687 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3688 barrier.dstAccessMask = accessInThisDispatch;
3689 barrier.image = texD->image;
3690 imageBarriers.append(barrier);
3693 VkBufferMemoryBarrier barrier = {};
3694 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3695 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3696 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3697 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3698 barrier.dstAccessMask = accessInThisDispatch;
3699 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3700 barrier.size = VK_WHOLE_SIZE;
3701 bufferBarriers.append(barrier);
3707 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3708 it = cbD->computePassState.writtenResources.erase(it);
3715 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3716 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3717 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3719 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3720 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3722 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3724 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3727 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3728 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3729 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3730 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3731 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3732 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3733 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3734 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3738 cmd.args.dispatch.x = x;
3739 cmd.args.dispatch.y = y;
3740 cmd.args.dispatch.z = z;
3746 VkShaderModuleCreateInfo shaderInfo = {};
3747 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3748 shaderInfo.codeSize = size_t(spirv.size());
3749 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3750 VkShaderModule shaderModule;
3751 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3752 if (err != VK_SUCCESS) {
3753 qWarning(
"Failed to create shader module: %d", err);
3754 return VK_NULL_HANDLE;
3756 return shaderModule;
3764 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3765 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3766 pipelineCacheInfo.initialDataSize = initialDataSize;
3767 pipelineCacheInfo.pInitialData = initialData;
3768 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3769 if (err != VK_SUCCESS) {
3770 qWarning(
"Failed to create pipeline cache: %d", err);
3780 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3781 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3782 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3783 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3784 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3786 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3787 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3790 VkWriteDescriptorSet writeInfo = {};
3791 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3792 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3793 writeInfo.dstBinding = uint32_t(b->binding);
3794 writeInfo.descriptorCount = 1;
3796 int bufferInfoIndex = -1;
3797 int imageInfoIndex = -1;
3800 case QRhiShaderResourceBinding::UniformBuffer:
3802 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3803 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3804 QRhiBuffer *buf = b->u.ubuf.buf;
3806 bd.ubuf.id = bufD->m_id;
3807 bd.ubuf.generation = bufD->generation;
3808 VkDescriptorBufferInfo bufInfo = {};
3809 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3810 bufInfo.offset = b->u.ubuf.offset;
3811 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3813 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3814 bufferInfoIndex = bufferInfos.size();
3815 bufferInfos.append(bufInfo);
3818 case QRhiShaderResourceBinding::SampledTexture:
3820 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3821 writeInfo.descriptorCount = data->count;
3822 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3823 ArrayOfImageDesc imageInfo(data->count);
3824 for (
int elem = 0; elem < data->count; ++elem) {
3827 bd.stex.d[elem].texId = texD->m_id;
3828 bd.stex.d[elem].texGeneration = texD->generation;
3829 bd.stex.d[elem].samplerId = samplerD->m_id;
3830 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3831 imageInfo[elem].sampler = samplerD->sampler;
3832 imageInfo[elem].imageView = texD->imageView;
3833 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3835 bd.stex.count = data->count;
3836 imageInfoIndex = imageInfos.size();
3837 imageInfos.append(imageInfo);
3840 case QRhiShaderResourceBinding::Texture:
3842 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3843 writeInfo.descriptorCount = data->count;
3844 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3845 ArrayOfImageDesc imageInfo(data->count);
3846 for (
int elem = 0; elem < data->count; ++elem) {
3848 bd.stex.d[elem].texId = texD->m_id;
3849 bd.stex.d[elem].texGeneration = texD->generation;
3850 bd.stex.d[elem].samplerId = 0;
3851 bd.stex.d[elem].samplerGeneration = 0;
3852 imageInfo[elem].sampler = VK_NULL_HANDLE;
3853 imageInfo[elem].imageView = texD->imageView;
3854 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3856 bd.stex.count = data->count;
3857 imageInfoIndex = imageInfos.size();
3858 imageInfos.append(imageInfo);
3861 case QRhiShaderResourceBinding::Sampler:
3864 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3865 bd.stex.d[0].texId = 0;
3866 bd.stex.d[0].texGeneration = 0;
3867 bd.stex.d[0].samplerId = samplerD->m_id;
3868 bd.stex.d[0].samplerGeneration = samplerD->generation;
3869 ArrayOfImageDesc imageInfo(1);
3870 imageInfo[0].sampler = samplerD->sampler;
3871 imageInfo[0].imageView = VK_NULL_HANDLE;
3872 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3873 imageInfoIndex = imageInfos.size();
3874 imageInfos.append(imageInfo);
3877 case QRhiShaderResourceBinding::ImageLoad:
3878 case QRhiShaderResourceBinding::ImageStore:
3879 case QRhiShaderResourceBinding::ImageLoadStore:
3882 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3884 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3885 bd.simage.id = texD->m_id;
3886 bd.simage.generation = texD->generation;
3887 ArrayOfImageDesc imageInfo(1);
3888 imageInfo[0].sampler = VK_NULL_HANDLE;
3889 imageInfo[0].imageView = view;
3890 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3891 imageInfoIndex = imageInfos.size();
3892 imageInfos.append(imageInfo);
3896 case QRhiShaderResourceBinding::BufferLoad:
3897 case QRhiShaderResourceBinding::BufferStore:
3898 case QRhiShaderResourceBinding::BufferLoadStore:
3901 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3902 bd.sbuf.id = bufD->m_id;
3903 bd.sbuf.generation = bufD->generation;
3904 VkDescriptorBufferInfo bufInfo = {};
3905 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3906 bufInfo.offset = b->u.sbuf.offset;
3907 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3908 bufferInfoIndex = bufferInfos.size();
3909 bufferInfos.append(bufInfo);
3916 writeInfos.append(writeInfo);
3917 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3920 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3921 const int bufferInfoIndex = infoIndices[i].first;
3922 const int imageInfoIndex = infoIndices[i].second;
3923 if (bufferInfoIndex >= 0)
3924 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3925 else if (imageInfoIndex >= 0)
3926 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3929 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3934 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3935 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3936 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3937 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3938 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3939 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3943 VkAccessFlags access, VkPipelineStageFlags stage)
3946 Q_ASSERT(access && stage);
3954 if (s.access == access && s.stage == stage) {
3957 if (!accessIsWrite(access))
3961 VkBufferMemoryBarrier bufMemBarrier = {};
3962 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3963 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3964 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3965 bufMemBarrier.srcAccessMask = s.access;
3966 bufMemBarrier.dstAccessMask = access;
3967 bufMemBarrier.buffer = bufD->buffers[slot];
3968 bufMemBarrier.size = VK_WHOLE_SIZE;
3972 cmd.args.bufferBarrier.srcStageMask = s.stage;
3973 cmd.args.bufferBarrier.dstStageMask = stage;
3974 cmd.args.bufferBarrier.count = 1;
3975 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3976 cbD->pools.bufferBarrier.append(bufMemBarrier);
3983 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3986 Q_ASSERT(layout && access && stage);
3988 if (s.access == access && s.stage == stage && s.layout == layout) {
3989 if (!accessIsWrite(access))
3993 VkImageMemoryBarrier barrier = {};
3994 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3995 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3996 barrier.subresourceRange.baseMipLevel = 0;
3997 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3998 barrier.subresourceRange.baseArrayLayer = 0;
3999 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4000 barrier.oldLayout = s.layout;
4001 barrier.newLayout = layout;
4002 barrier.srcAccessMask = s.access;
4003 barrier.dstAccessMask = access;
4004 barrier.image = texD->image;
4006 VkPipelineStageFlags srcStage = s.stage;
4009 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4013 cmd.args.imageBarrier.srcStageMask = srcStage;
4014 cmd.args.imageBarrier.dstStageMask = stage;
4015 cmd.args.imageBarrier.count = 1;
4016 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4017 cbD->pools.imageBarrier.append(barrier);
4028 VkImageMemoryBarrier barrier = {};
4029 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4030 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4031 barrier.subresourceRange.baseMipLevel = 0;
4032 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4033 barrier.subresourceRange.baseArrayLayer = 0;
4034 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4035 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4036 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4037 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4038 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4039 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4040 barrier.image = rbD->image;
4042 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4043 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4047 cmd.args.imageBarrier.srcStageMask = stages;
4048 cmd.args.imageBarrier.dstStageMask = stages;
4049 cmd.args.imageBarrier.count = 1;
4050 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4051 cbD->pools.imageBarrier.append(barrier);
4055 VkImageLayout oldLayout, VkImageLayout newLayout,
4056 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4057 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4058 int startLayer,
int layerCount,
4059 int startLevel,
int levelCount)
4062 VkImageMemoryBarrier barrier = {};
4063 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4064 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4065 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4066 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4067 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4068 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4069 barrier.oldLayout = oldLayout;
4070 barrier.newLayout = newLayout;
4071 barrier.srcAccessMask = srcAccess;
4072 barrier.dstAccessMask = dstAccess;
4073 barrier.image = image;
4077 cmd.args.imageBarrier.srcStageMask = srcStage;
4078 cmd.args.imageBarrier.dstStageMask = dstStage;
4079 cmd.args.imageBarrier.count = 1;
4080 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4081 cbD->pools.imageBarrier.append(barrier);
4086 VkDeviceSize size = 0;
4087 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4088 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4089 if (imageSizeBytes > 0)
4090 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4095 const QRhiTextureSubresourceUploadDescription &subresDesc,
4096 size_t *curOfs,
void *mp,
4097 BufferImageCopyList *copyInfos)
4099 qsizetype copySizeBytes = 0;
4100 qsizetype imageSizeBytes = 0;
4101 const void *src =
nullptr;
4102 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4103 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4105 VkBufferImageCopy copyInfo = {};
4106 copyInfo.bufferOffset = *curOfs;
4107 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4108 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4109 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4110 copyInfo.imageSubresource.layerCount = 1;
4111 copyInfo.imageExtent.depth = 1;
4113 copyInfo.imageOffset.z = uint32_t(layer);
4115 copyInfo.imageOffset.y = uint32_t(layer);
4117 const QByteArray rawData = subresDesc.data();
4118 const QPoint dp = subresDesc.destinationTopLeft();
4119 QImage image = subresDesc.image();
4120 if (!image.isNull()) {
4121 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4122 QSize size = image.size();
4123 src = image.constBits();
4126 int bpc = qMax(1, image.depth() / 8);
4128 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4129 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4130 const int sx = subresDesc.sourceTopLeft().x();
4131 const int sy = subresDesc.sourceTopLeft().y();
4132 if (!subresDesc.sourceSize().isEmpty())
4133 size = subresDesc.sourceSize();
4134 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4135 if (size.width() == image.width()) {
4138 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4139 copySizeBytes = size.height() * image.bytesPerLine();
4141 image = image.copy(sx, sy, size.width(), size.height());
4142 src = image.constBits();
4145 copySizeBytes = image.sizeInBytes();
4146 bpc = qMax(1, image.depth() / 8);
4147 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4150 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4152 copyInfo.imageOffset.x = dp.x();
4153 copyInfo.imageOffset.y = dp.y();
4154 copyInfo.imageExtent.width = uint32_t(size.width());
4155 copyInfo.imageExtent.height = uint32_t(size.height());
4156 copyInfos->append(copyInfo);
4157 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4158 copySizeBytes = imageSizeBytes = rawData.size();
4159 src = rawData.constData();
4160 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4161 const int subresw = size.width();
4162 const int subresh = size.height();
4163 if (!subresDesc.sourceSize().isEmpty())
4164 size = subresDesc.sourceSize();
4165 const int w = size.width();
4166 const int h = size.height();
4168 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4170 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4171 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4174 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4175 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4176 copyInfos->append(copyInfo);
4177 }
else if (!rawData.isEmpty()) {
4178 copySizeBytes = imageSizeBytes = rawData.size();
4179 src = rawData.constData();
4180 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4181 if (!subresDesc.sourceSize().isEmpty())
4182 size = subresDesc.sourceSize();
4183 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4185 quint32 bytesPerPixel = 0;
4186 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4187 if (subresDesc.dataStride() && bytesPerPixel)
4188 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4190 size = clampedSubResourceUploadSizeForSourceData(size, subresDesc.dataStride(),
4191 bytesPerPixel, rawData.size());
4193 if (!size.isEmpty()) {
4194 copyInfo.imageOffset.x = dp.x();
4195 copyInfo.imageOffset.y = dp.y();
4196 copyInfo.imageExtent.width = uint32_t(size.width());
4197 copyInfo.imageExtent.height = uint32_t(size.height());
4198 copyInfos->append(copyInfo);
4201 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4205 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4206 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4212 if (err == VK_ERROR_DEVICE_LOST)
4213 printDeviceLossErrorInfo();
4214 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4215 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4220#ifdef VK_EXT_device_fault
4221 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4224 VkDeviceFaultCountsEXT faultCounts{};
4225 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4226 faultCounts.pNext =
nullptr;
4228 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4229 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4230 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4233 faultCounts.vendorBinarySize = 0;
4235 const auto numAddressInfos = faultCounts.addressInfoCount;
4236 const auto addressInfos
4237 = q20::make_unique_for_overwrite<VkDeviceFaultAddressInfoEXT[]>(numAddressInfos);
4239 const auto numVendorInfos = faultCounts.vendorInfoCount;
4240 const auto vendorInfos
4241 = q20::make_unique_for_overwrite<VkDeviceFaultVendorInfoEXT[]>(numVendorInfos);
4243 VkDeviceFaultInfoEXT info{};
4244 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4245 info.pNext =
nullptr;
4246 info.pAddressInfos = numAddressInfos ? addressInfos.get() :
nullptr;
4247 info.pVendorInfos = numVendorInfos ? vendorInfos.get() :
nullptr;
4248 info.pVendorBinaryData =
nullptr;
4250 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4251 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4252 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4256 const char *desc = info.description[0] ? info.description :
"n/a";
4257 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4258 faultCounts.addressInfoCount,
4259 faultCounts.vendorInfoCount,
4260 (
unsigned long long)faultCounts.vendorBinarySize,
4263 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4264 const auto &a = addressInfos[i];
4265 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4267 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4268 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4269 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4270 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4271 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4272 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4273 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4274 default:
return "UNKNOWN";
4277 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4279 addressTypeString(a.addressType),
4280 (
unsigned long long)a.reportedAddress,
4281 (
unsigned long long)a.addressPrecision);
4284 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4285 const auto &v = vendorInfos[i];
4286 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4288 (
unsigned long long)v.vendorFaultCode,
4289 (
unsigned long long)v.vendorFaultData,
4303 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4305 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4306 bufD->pendingDynamicUpdates[i].clear();
4307 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4311 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4312 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4314 if (!bufD->stagingBuffers[currentFrameSlot]) {
4315 VkBufferCreateInfo bufferInfo = {};
4316 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4319 bufferInfo.size = bufD->m_size;
4320 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4322 VmaAllocationCreateInfo allocInfo = {};
4323 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4325 VmaAllocation allocation;
4326 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4327 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4328 if (err == VK_SUCCESS) {
4329 bufD->stagingAllocations[currentFrameSlot] = allocation;
4330 setAllocationName(allocation, bufD->name());
4332 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4333 printExtraErrorInfo(err);
4338 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4339 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4340 u.offset, u
.data.size());
4341 if (err != VK_SUCCESS) {
4342 qWarning(
"Failed to copy memory to buffer: %d", err);
4346 trackedBufferBarrier(cbD, bufD, 0,
4347 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4349 VkBufferCopy copyInfo = {};
4350 copyInfo.srcOffset = u.offset;
4351 copyInfo.dstOffset = u.offset;
4352 copyInfo.size = u
.data.size();
4356 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4357 cmd.args.copyBuffer.dst = bufD->buffers[0];
4358 cmd.args.copyBuffer.desc = copyInfo;
4367 bufD->lastActiveFrameSlot = currentFrameSlot;
4369 if (bufD->m_type == QRhiBuffer::Immutable) {
4372 e.lastActiveFrameSlot = currentFrameSlot;
4373 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4374 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4375 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4376 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4377 releaseQueue.append(e);
4381 if (bufD->m_type == QRhiBuffer::Dynamic) {
4383 u.result->data.resizeForOverwrite(u.readSize);
4384 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4385 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4386 u.offset, u.result->data.data(), u.readSize);
4387 if (err != VK_SUCCESS) {
4388 qWarning(
"Failed to copy memory from buffer: %d", err);
4389 u.result->data.clear();
4391 if (u.result->completed)
4392 u.result->completed();
4401 readback.activeFrameSlot = currentFrameSlot;
4402 readback.result = u.result;
4403 readback.byteSize = u.readSize;
4405 VkBufferCreateInfo bufferInfo = {};
4406 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4407 bufferInfo.size = readback.byteSize;
4408 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4410 VmaAllocationCreateInfo allocInfo = {};
4411 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4413 VmaAllocation allocation;
4414 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4415 if (err == VK_SUCCESS) {
4417 setAllocationName(allocation, bufD->name());
4419 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4420 printExtraErrorInfo(err);
4424 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4426 VkBufferCopy copyInfo = {};
4427 copyInfo.srcOffset = u.offset;
4428 copyInfo.size = u.readSize;
4432 cmd.args.copyBuffer.src = bufD->buffers[0];
4433 cmd.args.copyBuffer.dst = readback.stagingBuf;
4434 cmd.args.copyBuffer.desc = copyInfo;
4436 bufD->lastActiveFrameSlot = currentFrameSlot;
4438 activeBufferReadbacks.append(readback);
4448 VkDeviceSize stagingSize = 0;
4449 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4450 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4451 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4452 stagingSize += subresUploadByteSize(subresDesc);
4456 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4457 VkBufferCreateInfo bufferInfo = {};
4458 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4459 bufferInfo.size = stagingSize;
4460 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4462 VmaAllocationCreateInfo allocInfo = {};
4463 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4465 VmaAllocation allocation;
4466 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4467 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4468 if (err != VK_SUCCESS) {
4469 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4470 printExtraErrorInfo(err);
4473 utexD->stagingAllocations[currentFrameSlot] = allocation;
4474 setAllocationName(allocation, utexD->name());
4476 BufferImageCopyList copyInfos;
4479 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4480 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4481 if (err != VK_SUCCESS) {
4482 qWarning(
"Failed to map image data: %d", err);
4483 vmaDestroyBuffer(toVmaAllocator(allocator), utexD->stagingBuffers[currentFrameSlot], a);
4484 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4485 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4489 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4490 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4491 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4494 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4495 prepareUploadSubres(utexD, layer, level,
4496 subresDesc, &curOfs, mp, ©Infos);
4500 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4501 vmaUnmapMemory(toVmaAllocator(allocator), a);
4503 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4504 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4506 if (!copyInfos.isEmpty()) {
4509 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4510 cmd.args.copyBufferToImage.dst = utexD->image;
4511 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4512 cmd.args.copyBufferToImage.count = copyInfos.size();
4513 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4514 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4520 e.lastActiveFrameSlot = currentFrameSlot;
4521 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4522 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4523 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4524 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4525 releaseQueue.append(e);
4530 utexD->lastActiveFrameSlot = currentFrameSlot;
4534 qWarning(
"Texture copy with matching source and destination is not supported");
4539 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4540 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4542 VkImageCopy region = {};
4543 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4544 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4545 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4546 region.srcSubresource.layerCount = 1;
4548 region.srcOffset.x = u.desc.sourceTopLeft().x();
4549 region.srcOffset.y = u.desc.sourceTopLeft().y();
4551 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4553 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4554 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4555 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4556 region.dstSubresource.layerCount = 1;
4558 region.dstOffset.x = u.desc.destinationTopLeft().x();
4559 region.dstOffset.y = u.desc.destinationTopLeft().y();
4561 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4563 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4564 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4565 region.extent.width = uint32_t(copySize.width());
4566 region.extent.height = uint32_t(copySize.height());
4567 region.extent.depth = 1;
4569 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4570 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4571 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4572 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4576 cmd.args.copyImage.src = srcD->image;
4577 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4578 cmd.args.copyImage.dst = dstD->image;
4579 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4580 cmd.args.copyImage.desc = region;
4582 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4585 readback.activeFrameSlot = currentFrameSlot;
4586 readback.desc = u.rb;
4587 readback.result = u.result;
4593 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4594 qWarning(
"Multisample texture cannot be read back");
4597 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4598 if (u.rb.rect().isValid())
4599 readback.rect = u.rb.rect();
4601 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4602 readback.format = texD->m_format;
4603 texD->lastActiveFrameSlot = currentFrameSlot;
4608 qWarning(
"Swapchain does not support readback");
4611 if (u.rb.rect().isValid())
4612 readback.rect = u.rb.rect();
4614 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4615 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4616 if (readback.format == QRhiTexture::UnknownFormat)
4622 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4625 VkBufferCreateInfo bufferInfo = {};
4626 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4627 bufferInfo.size = readback.byteSize;
4628 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4630 VmaAllocationCreateInfo allocInfo = {};
4631 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4633 VmaAllocation allocation;
4634 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4635 if (err == VK_SUCCESS) {
4637 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4639 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4640 printExtraErrorInfo(err);
4645 VkBufferImageCopy copyDesc = {};
4646 copyDesc.bufferOffset = 0;
4647 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4648 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4649 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4650 copyDesc.imageSubresource.layerCount = 1;
4651 copyDesc.imageOffset.x = readback.rect.x();
4652 copyDesc.imageOffset.y = readback.rect.y();
4654 copyDesc.imageOffset.z = u.rb.layer();
4655 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4656 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4657 copyDesc.imageExtent.depth = 1;
4660 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4661 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4664 cmd.args.copyImageToBuffer.src = texD->image;
4665 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4666 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4667 cmd.args.copyImageToBuffer.desc = copyDesc;
4671 VkImage image = imageRes.image;
4674 qWarning(
"Attempted to read back undefined swapchain image content, "
4675 "results are undefined. (do a render pass first)");
4677 subresourceBarrier(cbD, image,
4678 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4679 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4680 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4688 cmd.args.copyImageToBuffer.src = image;
4689 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4690 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4691 cmd.args.copyImageToBuffer.desc = copyDesc;
4694 activeTextureReadbacks.append(readback);
4697 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4698 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4699 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4700 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4702 VkImageLayout origLayout = utexD->usageState.layout;
4703 VkAccessFlags origAccess = utexD->usageState.access;
4704 VkPipelineStageFlags origStage = utexD->usageState.stage;
4706 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4708 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4709 int w = utexD->m_pixelSize.width();
4710 int h = utexD->m_pixelSize.height();
4711 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4712 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4714 subresourceBarrier(cbD, utexD->image,
4715 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4716 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4717 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4721 subresourceBarrier(cbD, utexD->image,
4722 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4723 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4724 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4729 subresourceBarrier(cbD, utexD->image,
4730 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4731 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4732 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4736 VkImageBlit region = {};
4737 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4738 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4739 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4740 region.srcSubresource.layerCount = 1;
4742 region.srcOffsets[1].x = qMax(1, w);
4743 region.srcOffsets[1].y = qMax(1, h);
4744 region.srcOffsets[1].z = qMax(1, depth);
4746 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4747 region.dstSubresource.mipLevel = uint32_t(level);
4748 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4749 region.dstSubresource.layerCount = 1;
4751 region.dstOffsets[1].x = qMax(1, w >> 1);
4752 region.dstOffsets[1].y = qMax(1, h >> 1);
4753 region.dstOffsets[1].z = qMax(1, depth >> 1);
4757 cmd.args.blitImage.src = utexD->image;
4758 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4759 cmd.args.blitImage.dst = utexD->image;
4760 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4761 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4762 cmd.args.blitImage.desc = region;
4769 if (utexD->mipLevelCount > 1) {
4770 subresourceBarrier(cbD, utexD->image,
4771 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4772 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4773 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4775 0,
int(utexD->mipLevelCount) - 1);
4776 subresourceBarrier(cbD, utexD->image,
4777 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4778 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4779 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4781 int(utexD->mipLevelCount) - 1, 1);
4784 utexD->lastActiveFrameSlot = currentFrameSlot;
4793 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4796 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4798 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4802 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4803 if (err != VK_SUCCESS) {
4804 qWarning(
"Failed to map buffer: %d", err);
4807 quint32 changeBegin = UINT32_MAX;
4808 quint32 changeEnd = 0;
4809 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4810 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4811 if (u.offset < changeBegin)
4812 changeBegin = u.offset;
4813 if (u.offset + u.data.size() > changeEnd)
4814 changeEnd = u.offset + u.data.size();
4816 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4817 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4818 vmaUnmapMemory(toVmaAllocator(allocator), a);
4820 bufD->pendingDynamicUpdates[slot].clear();
4826 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4827 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4833 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4834 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4835 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4840 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4841 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4843 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4844 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4845 if (e.texture.extraImageViews[i])
4846 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4852 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4857 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4859 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4862 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4863 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4866 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4867 if (e.shaderResourceBindings.poolIndex >= 0) {
4868 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4869 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4876 qrhivk_releaseRenderBuffer(e, dev,
df);
4882 qrhivk_releaseSampler(e, dev,
df);
4885 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4887 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4888 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4890 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4891 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4892 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4895 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4898 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4900 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4901 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4907 releaseQueue.removeAt(i);
4914 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4916 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4918 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4919 readback.result->format = readback.format;
4920 readback.result->pixelSize = readback.rect.size();
4921 readback.result->data.resizeForOverwrite(readback.byteSize);
4922 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4923 toVmaAllocation(readback.stagingAlloc),
4924 0, readback.result->data.data(), readback.byteSize);
4925 if (err != VK_SUCCESS) {
4926 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4927 readback.result->data.clear();
4930 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4932 if (readback.result->completed)
4933 completedCallbacks.append(readback.result->completed);
4935 activeTextureReadbacks.remove(i);
4939 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4941 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4942 readback.result->data.resizeForOverwrite(readback.byteSize);
4943 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4944 toVmaAllocation(readback.stagingAlloc),
4945 0, readback.result->data.data(), readback.byteSize);
4946 if (err != VK_SUCCESS) {
4947 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4948 readback.result->data.clear();
4951 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4953 if (readback.result->completed)
4954 completedCallbacks.append(readback.result->completed);
4956 activeBufferReadbacks.remove(i);
4960 for (
const auto &f : completedCallbacks)
4967} qvk_sampleCounts[] = {
4969 { VK_SAMPLE_COUNT_1_BIT, 1 },
4970 { VK_SAMPLE_COUNT_2_BIT, 2 },
4971 { VK_SAMPLE_COUNT_4_BIT, 4 },
4972 { VK_SAMPLE_COUNT_8_BIT, 8 },
4973 { VK_SAMPLE_COUNT_16_BIT, 16 },
4974 { VK_SAMPLE_COUNT_32_BIT, 32 },
4975 { VK_SAMPLE_COUNT_64_BIT, 64 }
4980 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4981 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4982 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4983 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4986 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4987 if ((color & qvk_sampleCount.mask)
4988 && (depth & qvk_sampleCount.mask)
4989 && (stencil & qvk_sampleCount.mask))
4991 result.append(qvk_sampleCount.count);
5000 const int s = effectiveSampleCount(sampleCount);
5002 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5003 if (qvk_sampleCount.count == s)
5004 return qvk_sampleCount.mask;
5007 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
5012 QList<QSize> result;
5013#ifdef VK_KHR_fragment_shading_rate
5014 sampleCount = qMax(1, sampleCount);
5015 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
5016 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
5017 if (qvk_sampleCount.count == sampleCount) {
5018 mask = qvk_sampleCount.mask;
5022 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
5023 if (s.sampleCounts & mask)
5024 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
5027 Q_UNUSED(sampleCount);
5028 result.append(QSize(1, 1));
5035 cbD->passResTrackers.emplace_back();
5040 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5047 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5051 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5052 1, &cmd.args.copyBuffer.desc);
5055 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5056 cmd.args.copyBufferToImage.dstLayout,
5057 uint32_t(cmd.args.copyBufferToImage.count),
5058 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5061 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5062 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5063 1, &cmd.args.copyImage.desc);
5066 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5067 cmd.args.copyImageToBuffer.dst,
5068 1, &cmd.args.copyImageToBuffer.desc);
5071 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5072 0, 0,
nullptr, 0,
nullptr,
5073 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5076 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5078 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5082 const auto &barrier = cmd.args.imageAndBufferBarrier;
5083 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5084 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5085 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5086 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5087 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5089 barrier.bufferCount, bufferBarrierData,
5090 barrier.imageCount, imageBarrierData);
5093 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5094 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5095 1, &cmd.args.blitImage.desc,
5096 cmd.args.blitImage.filter);
5099 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5100 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5101 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5102 : VK_SUBPASS_CONTENTS_INLINE);
5105 VkMemoryBarrier barrier = {};
5106 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5107 barrier.pNext =
nullptr;
5108 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5109 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5110 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5116 df->vkCmdEndRenderPass(cbD->cb);
5119 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5123 const uint32_t *offsets =
nullptr;
5124 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5125 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5126 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5127 cmd.args.bindDescriptorSet.pipelineLayout,
5128 0, 1, &cmd.args.bindDescriptorSet.descSet,
5129 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5134 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5135 uint32_t(cmd.args.bindVertexBuffer.count),
5136 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5137 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5140 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5141 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5144 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5147 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5150 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5153 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5156 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5157 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5160 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5161 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5162 cmd.args.drawIndexed.firstInstance);
5165 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5166 cmd.args.drawIndirect.indirectBufferOffset,
5167 cmd.args.drawIndirect.drawCount,
5168 cmd.args.drawIndirect.stride);
5171 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5172 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5173 cmd.args.drawIndexedIndirect.drawCount,
5174 cmd.args.drawIndexedIndirect.stride);
5177#ifdef VK_EXT_debug_utils
5178 cmd.args.debugMarkerBegin.label.pLabelName =
5179 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5180 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5184#ifdef VK_EXT_debug_utils
5185 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5189#ifdef VK_EXT_debug_utils
5190 cmd.args.debugMarkerInsert.label.pLabelName =
5191 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5192 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5199 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5202 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5206#ifdef VK_KHR_fragment_shading_rate
5207 VkFragmentShadingRateCombinerOpKHR op[2] = {
5208 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5209 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5211 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5212 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5225 case QRhiPassResourceTracker::BufIndirectDraw:
5226 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5227 case QRhiPassResourceTracker::BufVertexInput:
5228 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5229 case QRhiPassResourceTracker::BufIndexRead:
5230 return VK_ACCESS_INDEX_READ_BIT;
5231 case QRhiPassResourceTracker::BufUniformRead:
5232 return VK_ACCESS_UNIFORM_READ_BIT;
5233 case QRhiPassResourceTracker::BufStorageLoad:
5234 return VK_ACCESS_SHADER_READ_BIT;
5235 case QRhiPassResourceTracker::BufStorageStore:
5236 return VK_ACCESS_SHADER_WRITE_BIT;
5237 case QRhiPassResourceTracker::BufStorageLoadStore:
5238 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5249 case QRhiPassResourceTracker::BufIndirectDrawStage:
5250 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5251 case QRhiPassResourceTracker::BufVertexInputStage:
5252 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5253 case QRhiPassResourceTracker::BufVertexStage:
5254 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5255 case QRhiPassResourceTracker::BufTCStage:
5256 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5257 case QRhiPassResourceTracker::BufTEStage:
5258 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5259 case QRhiPassResourceTracker::BufFragmentStage:
5260 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5261 case QRhiPassResourceTracker::BufComputeStage:
5262 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5263 case QRhiPassResourceTracker::BufGeometryStage:
5264 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5275 u.access = VkAccessFlags(usage
.access);
5276 u.stage = VkPipelineStageFlags(usage
.stage);
5283 case QRhiPassResourceTracker::TexSample:
5284 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5285 case QRhiPassResourceTracker::TexColorOutput:
5286 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5287 case QRhiPassResourceTracker::TexDepthOutput:
5288 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5289 case QRhiPassResourceTracker::TexStorageLoad:
5290 case QRhiPassResourceTracker::TexStorageStore:
5291 case QRhiPassResourceTracker::TexStorageLoadStore:
5292 return VK_IMAGE_LAYOUT_GENERAL;
5293 case QRhiPassResourceTracker::TexShadingRate:
5294#ifdef VK_KHR_fragment_shading_rate
5295 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5297 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5303 return VK_IMAGE_LAYOUT_GENERAL;
5309 case QRhiPassResourceTracker::TexSample:
5310 return VK_ACCESS_SHADER_READ_BIT;
5311 case QRhiPassResourceTracker::TexColorOutput:
5312 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5313 case QRhiPassResourceTracker::TexDepthOutput:
5314 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5315 case QRhiPassResourceTracker::TexStorageLoad:
5316 return VK_ACCESS_SHADER_READ_BIT;
5317 case QRhiPassResourceTracker::TexStorageStore:
5318 return VK_ACCESS_SHADER_WRITE_BIT;
5319 case QRhiPassResourceTracker::TexStorageLoadStore:
5320 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5333 case QRhiPassResourceTracker::TexVertexStage:
5334 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5335 case QRhiPassResourceTracker::TexTCStage:
5336 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5337 case QRhiPassResourceTracker::TexTEStage:
5338 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5339 case QRhiPassResourceTracker::TexFragmentStage:
5340 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5341 case QRhiPassResourceTracker::TexColorOutputStage:
5342 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5343 case QRhiPassResourceTracker::TexDepthOutputStage:
5344 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5345 case QRhiPassResourceTracker::TexComputeStage:
5346 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5347 case QRhiPassResourceTracker::TexGeometryStage:
5348 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5359 u.layout = VkImageLayout(usage
.layout);
5360 u.access = VkAccessFlags(usage
.access);
5361 u.stage = VkPipelineStageFlags(usage
.stage);
5372 const VkAccessFlags newAccess = toVkAccess(access);
5373 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5374 if (u.access == newAccess && u.stage == newStage) {
5375 if (!accessIsWrite(newAccess))
5379 u.access = newAccess;
5389 const VkAccessFlags newAccess = toVkAccess(access);
5390 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5391 const VkImageLayout newLayout = toVkLayout(access);
5392 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5393 if (!accessIsWrite(newAccess))
5397 u.layout = newLayout;
5398 u.access = newAccess;
5407 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5408 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5409 VkAccessFlags access = toVkAccess(trackedB.access);
5410 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5411 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5414 if (s.access == access && s.stage == stage) {
5415 if (!accessIsWrite(access))
5418 VkBufferMemoryBarrier bufMemBarrier = {};
5419 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5420 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5421 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5422 bufMemBarrier.srcAccessMask = s.access;
5423 bufMemBarrier.dstAccessMask = access;
5424 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5425 bufMemBarrier.size = VK_WHOLE_SIZE;
5426 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5432 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5433 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5434 VkImageLayout layout = toVkLayout(trackedT.access);
5435 VkAccessFlags access = toVkAccess(trackedT.access);
5436 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5437 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5438 if (s.access == access && s.stage == stage && s.layout == layout) {
5439 if (!accessIsWrite(access))
5442 VkImageMemoryBarrier barrier = {};
5443 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5444 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5445 barrier.subresourceRange.baseMipLevel = 0;
5446 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5447 barrier.subresourceRange.baseArrayLayer = 0;
5448 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5449 barrier.oldLayout = s.layout;
5450 barrier.newLayout = layout;
5451 barrier.srcAccessMask = s.access;
5452 barrier.dstAccessMask = access;
5453 barrier.image = texD->image;
5454 VkPipelineStageFlags srcStage = s.stage;
5457 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5458 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5467 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5468 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5469 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5471 qWarning(
"Physical device surface queries not available");
5475 return new QVkSwapChain(
this);
5478QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5480 return new QVkBuffer(
this, type, usage, size);
5485 return int(ubufAlign);
5508 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
5509 0.0f, -1.0f, 0.0f, 0.0f,
5510 0.0f, 0.0f, 0.5f, 0.5f,
5511 0.0f, 0.0f, 0.0f, 1.0f);
5520 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5521 if (!physDevFeatures.textureCompressionBC)
5525 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5526 if (!physDevFeatures.textureCompressionETC2)
5530 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5531 if (!physDevFeatures.textureCompressionASTC_LDR)
5535 VkFormat vkformat = toVkTextureFormat(format, flags);
5536 VkFormatProperties props;
5537 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5538 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5544 case QRhi::MultisampleTexture:
5546 case QRhi::MultisampleRenderBuffer:
5548 case QRhi::DebugMarkers:
5549 return caps.debugUtils;
5550 case QRhi::Timestamps:
5551 return timestampValidBits != 0;
5552 case QRhi::Instancing:
5554 case QRhi::CustomInstanceStepRate:
5555 return caps.vertexAttribDivisor;
5556 case QRhi::PrimitiveRestart:
5558 case QRhi::NonDynamicUniformBuffers:
5560 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5562 case QRhi::NPOTTextureRepeat:
5564 case QRhi::RedOrAlpha8IsRed:
5566 case QRhi::ElementIndexUint:
5569 return caps.compute;
5570 case QRhi::WideLines:
5571 return caps.wideLines;
5572 case QRhi::VertexShaderPointSize:
5574 case QRhi::BaseVertex:
5576 case QRhi::BaseInstance:
5578 case QRhi::TriangleFanTopology:
5580 case QRhi::ReadBackNonUniformBuffer:
5582 case QRhi::ReadBackNonBaseMipLevel:
5584 case QRhi::TexelFetch:
5586 case QRhi::RenderToNonBaseMipLevel:
5588 case QRhi::IntAttributes:
5590 case QRhi::ScreenSpaceDerivatives:
5592 case QRhi::ReadBackAnyTextureFormat:
5594 case QRhi::PipelineCacheDataLoadSave:
5596 case QRhi::ImageDataStride:
5598 case QRhi::RenderBufferImport:
5600 case QRhi::ThreeDimensionalTextures:
5602 case QRhi::RenderTo3DTextureSlice:
5603 return caps.texture3DSliceAs2D;
5604 case QRhi::TextureArrays:
5606 case QRhi::Tessellation:
5607 return caps.tessellation;
5608 case QRhi::GeometryShader:
5609 return caps.geometryShader;
5610 case QRhi::TextureArrayRange:
5612 case QRhi::NonFillPolygonMode:
5613 return caps.nonFillPolygonMode;
5614 case QRhi::OneDimensionalTextures:
5616 case QRhi::OneDimensionalTextureMipmaps:
5618 case QRhi::HalfAttributes:
5620 case QRhi::RenderToOneDimensionalTexture:
5622 case QRhi::ThreeDimensionalTextureMipmaps:
5624 case QRhi::MultiView:
5625 return caps.multiView;
5626 case QRhi::TextureViewFormat:
5628 case QRhi::ResolveDepthStencil:
5629 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5630 case QRhi::VariableRateShading:
5631 return caps.renderPass2KHR && caps.perDrawShadingRate;
5632 case QRhi::VariableRateShadingMap:
5633 case QRhi::VariableRateShadingMapWithTexture:
5634 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5635 case QRhi::PerRenderTargetBlending:
5636 case QRhi::SampleVariables:
5638 case QRhi::InstanceIndexIncludesBaseInstance:
5640 case QRhi::DepthClamp:
5641 return caps.depthClamp;
5642 case QRhi::DrawIndirect:
5644 case QRhi::DrawIndirectMulti:
5645 return caps.drawIndirectMulti;
5646 case QRhi::ShaderDrawParameters:
5647 return caps.shaderDrawParameters;
5649 Q_UNREACHABLE_RETURN(
false);
5656 case QRhi::TextureSizeMin:
5658 case QRhi::TextureSizeMax:
5659 return int(physDevProperties.limits.maxImageDimension2D);
5660 case QRhi::MaxColorAttachments:
5661 return int(physDevProperties.limits.maxColorAttachments);
5662 case QRhi::FramesInFlight:
5664 case QRhi::MaxAsyncReadbackFrames:
5666 case QRhi::MaxThreadGroupsPerDimension:
5667 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5668 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5669 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5670 case QRhi::MaxThreadsPerThreadGroup:
5671 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5672 case QRhi::MaxThreadGroupX:
5673 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5674 case QRhi::MaxThreadGroupY:
5675 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5676 case QRhi::MaxThreadGroupZ:
5677 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5678 case QRhi::TextureArraySizeMax:
5679 return int(physDevProperties.limits.maxImageArrayLayers);
5680 case QRhi::MaxUniformBufferRange:
5681 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5682 case QRhi::MaxVertexInputs:
5683 return physDevProperties.limits.maxVertexInputAttributes;
5684 case QRhi::MaxVertexOutputs:
5685 return physDevProperties.limits.maxVertexOutputComponents / 4;
5686 case QRhi::ShadingRateImageTileSize:
5687 return caps.imageBasedShadingRateTileSize;
5689 Q_UNREACHABLE_RETURN(0);
5695 return &nativeHandlesStruct;
5700 return driverInfoStruct;
5706 result.totalPipelineCreationTime = totalPipelineCreationTime();
5708 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5709 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5711 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5712 for (uint32_t i = 0; i < count; ++i) {
5713 const VmaStatistics &stats(budgets[i].statistics);
5714 result.blockCount += stats.blockCount;
5715 result.allocCount += stats.allocationCount;
5716 result.usedBytes += stats.allocationBytes;
5717 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5731 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5735 waitSemaphoresForQueueSubmit.clear();
5736 if (sp->waitSemaphoreCount)
5737 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5739 signalSemaphoresForQueueSubmit.clear();
5740 if (sp->signalSemaphoreCount)
5741 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5743 waitSemaphoresForPresent.clear();
5744 if (sp->presentWaitSemaphoreCount)
5745 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5775 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5778 size_t dataSize = 0;
5779 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5780 if (err != VK_SUCCESS) {
5781 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5782 return QByteArray();
5785 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5786 data.resize(dataOffset + dataSize);
5787 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5788 if (err != VK_SUCCESS) {
5789 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5790 return QByteArray();
5794 header.rhiId = pipelineCacheRhiId();
5795 header.arch = quint32(
sizeof(
void*));
5796 header.driverVersion = physDevProperties.driverVersion;
5797 header.vendorId = physDevProperties.vendorID;
5798 header.deviceId = physDevProperties.deviceID;
5799 header.dataSize = quint32(dataSize);
5800 header.uuidSize = VK_UUID_SIZE;
5801 header.reserved = 0;
5802 memcpy(data.data(), &header, headerSize);
5803 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5814 if (data.size() < qsizetype(headerSize)) {
5815 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5819 memcpy(&header, data.constData(), headerSize);
5821 const quint32 rhiId = pipelineCacheRhiId();
5822 if (header.rhiId != rhiId) {
5823 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5824 rhiId, header.rhiId);
5827 const quint32 arch = quint32(
sizeof(
void*));
5828 if (header.arch != arch) {
5829 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5833 if (header.driverVersion != physDevProperties.driverVersion) {
5834 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5835 physDevProperties.driverVersion, header.driverVersion);
5838 if (header.vendorId != physDevProperties.vendorID) {
5839 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5840 physDevProperties.vendorID, header.vendorId);
5843 if (header.deviceId != physDevProperties.deviceID) {
5844 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5845 physDevProperties.deviceID, header.deviceId);
5848 if (header.uuidSize != VK_UUID_SIZE) {
5849 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5850 quint32(VK_UUID_SIZE), header.uuidSize);
5854 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5855 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5858 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5859 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5863 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5864 if (quint64(data.size()) < quint64(dataOffset) + header.dataSize) {
5865 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5869 if (pipelineCache) {
5870 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5871 pipelineCache = VK_NULL_HANDLE;
5874 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5875 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5876 int(header.dataSize));
5878 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5882QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5883 int sampleCount, QRhiRenderBuffer::Flags flags,
5884 QRhiTexture::Format backingFormatHint)
5886 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5890 const QSize &pixelSize,
int depth,
int arraySize,
5891 int sampleCount, QRhiTexture::Flags flags)
5893 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5897 QRhiSampler::Filter mipmapMode,
5898 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5900 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5905 return new QVkShadingRateMap(
this);
5909 QRhiTextureRenderTarget::Flags flags)
5916 return new QVkGraphicsPipeline(
this);
5921 return new QVkComputePipeline(
this);
5926 return new QVkShaderResourceBindings(
this);
5932 Q_ASSERT(psD->pipeline);
5936 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5938 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5942 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5943 cmd.args.bindPipeline.pipeline = psD->pipeline;
5946 cbD->currentGraphicsPipeline = ps;
5947 cbD->currentComputePipeline =
nullptr;
5948 cbD->currentPipelineGeneration = psD->generation;
5954 psD->lastActiveFrameSlot = currentFrameSlot;
5958 int dynamicOffsetCount,
5959 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5969 srb = gfxPsD->m_shaderResourceBindings;
5971 srb = compPsD->m_shaderResourceBindings;
5975 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5976 bool rewriteDescSet =
false;
5977 bool addWriteBarrier =
false;
5978 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5979 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5983 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5984 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5987 case QRhiShaderResourceBinding::UniformBuffer:
5990 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5991 sanityCheckResourceOwnership(bufD);
5993 if (bufD->m_type == QRhiBuffer::Dynamic)
5996 bufD->lastActiveFrameSlot = currentFrameSlot;
5997 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5999 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
6005 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
6006 rewriteDescSet =
true;
6007 bd.ubuf.id = bufD->m_id;
6008 bd.ubuf.generation = bufD->generation;
6012 case QRhiShaderResourceBinding::SampledTexture:
6013 case QRhiShaderResourceBinding::Texture:
6014 case QRhiShaderResourceBinding::Sampler:
6016 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
6017 if (bd.stex.count != data->count) {
6018 bd.stex.count = data->count;
6019 rewriteDescSet =
true;
6021 for (
int elem = 0; elem < data->count; ++elem) {
6027 Q_ASSERT(texD || samplerD);
6028 sanityCheckResourceOwnership(texD);
6029 sanityCheckResourceOwnership(samplerD);
6031 texD->lastActiveFrameSlot = currentFrameSlot;
6037 samplerD->lastActiveFrameSlot = currentFrameSlot;
6038 const quint64 texId = texD ? texD->m_id : 0;
6039 const uint texGen = texD ? texD->generation : 0;
6040 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6041 const uint samplerGen = samplerD ? samplerD->generation : 0;
6042 if (texGen != bd.stex.d[elem].texGeneration
6043 || texId != bd.stex.d[elem].texId
6044 || samplerGen != bd.stex.d[elem].samplerGeneration
6045 || samplerId != bd.stex.d[elem].samplerId)
6047 rewriteDescSet =
true;
6048 bd.stex.d[elem].texId = texId;
6049 bd.stex.d[elem].texGeneration = texGen;
6050 bd.stex.d[elem].samplerId = samplerId;
6051 bd.stex.d[elem].samplerGeneration = samplerGen;
6056 case QRhiShaderResourceBinding::ImageLoad:
6057 case QRhiShaderResourceBinding::ImageStore:
6058 case QRhiShaderResourceBinding::ImageLoadStore:
6061 sanityCheckResourceOwnership(texD);
6062 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6063 texD->lastActiveFrameSlot = currentFrameSlot;
6065 if (b->type == QRhiShaderResourceBinding::ImageLoad)
6067 else if (b->type == QRhiShaderResourceBinding::ImageStore)
6072 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6073 const auto prevAccess = passResTracker.textures().find(texD);
6074 if (prevAccess != passResTracker.textures().end()) {
6078 addWriteBarrier =
true;
6079 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6080 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6088 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6089 rewriteDescSet =
true;
6090 bd.simage.id = texD->m_id;
6091 bd.simage.generation = texD->generation;
6095 case QRhiShaderResourceBinding::BufferLoad:
6096 case QRhiShaderResourceBinding::BufferStore:
6097 case QRhiShaderResourceBinding::BufferLoadStore:
6100 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6101 sanityCheckResourceOwnership(bufD);
6103 if (bufD->m_type == QRhiBuffer::Dynamic)
6106 bufD->lastActiveFrameSlot = currentFrameSlot;
6108 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6110 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6115 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6116 const auto prevAccess = passResTracker.buffers().find(bufD);
6117 if (prevAccess != passResTracker.buffers().end()) {
6121 addWriteBarrier =
true;
6122 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6123 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6126 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6130 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6131 rewriteDescSet =
true;
6132 bd.sbuf.id = bufD->m_id;
6133 bd.sbuf.generation = bufD->generation;
6143 if (addWriteBarrier) {
6145 VkMemoryBarrier barrier = {};
6146 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6147 barrier.pNext =
nullptr;
6148 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6149 barrier.srcAccessMask = barrier.dstAccessMask;
6150 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6157 cmd.args.memoryBarrier.dependencyFlags = 0;
6158 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6159 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6160 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6161 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6167 updateShaderResourceBindings(srb);
6171 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6172 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6174 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6176 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6177 QVarLengthArray<uint32_t, 4> dynOfs;
6182 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6183 uint32_t offset = 0;
6184 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6185 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6186 if (bindingOffsetPair.first == bindingNumber) {
6187 offset = bindingOffsetPair.second;
6191 dynOfs.append(offset);
6195 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6196 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6197 gfxPsD ? gfxPsD->layout : compPsD->layout,
6198 0, 1, &srbD->descSets[currentFrameSlot],
6199 uint32_t(dynOfs.size()),
6200 dynOfs.size() ? dynOfs.constData() :
nullptr);
6204 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6205 : VK_PIPELINE_BIND_POINT_COMPUTE;
6206 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6207 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6208 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6209 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6210 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6214 cbD->currentGraphicsSrb = srb;
6215 cbD->currentComputeSrb =
nullptr;
6217 cbD->currentGraphicsSrb =
nullptr;
6218 cbD->currentComputeSrb = srb;
6220 cbD->currentSrbGeneration = srbD->generation;
6221 cbD->currentDescSetSlot = currentFrameSlot;
6224 srbD->lastActiveFrameSlot = currentFrameSlot;
6228 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6229 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6235 bool needsBindVBuf =
false;
6236 for (
int i = 0; i < bindingCount; ++i) {
6237 const int inputSlot = startBinding + i;
6239 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6240 bufD->lastActiveFrameSlot = currentFrameSlot;
6241 if (bufD->m_type == QRhiBuffer::Dynamic)
6244 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6245 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6246 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6248 needsBindVBuf =
true;
6249 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6250 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6254 if (needsBindVBuf) {
6255 QVarLengthArray<VkBuffer, 4> bufs;
6256 QVarLengthArray<VkDeviceSize, 4> ofs;
6257 for (
int i = 0; i < bindingCount; ++i) {
6259 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6260 bufs.append(bufD->buffers[slot]);
6261 ofs.append(bindings[i].second);
6268 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6269 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6273 cmd.args.bindVertexBuffer.startBinding = startBinding;
6274 cmd.args.bindVertexBuffer.count = bufs.size();
6275 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6276 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6277 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6278 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6284 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6285 ibufD->lastActiveFrameSlot = currentFrameSlot;
6286 if (ibufD->m_type == QRhiBuffer::Dynamic)
6289 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6290 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6291 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6292 : VK_INDEX_TYPE_UINT32;
6294 if (cbD->currentIndexBuffer != vkindexbuf
6295 || cbD->currentIndexOffset != indexOffset
6296 || cbD->currentIndexFormat != type)
6298 cbD->currentIndexBuffer = vkindexbuf;
6299 cbD->currentIndexOffset = indexOffset;
6300 cbD->currentIndexFormat = type;
6303 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6307 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6308 cmd.args.bindIndexBuffer.ofs = indexOffset;
6309 cmd.args.bindIndexBuffer.type = type;
6323 const QSize outputSize = cbD->currentTarget->pixelSize();
6324 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6325 float x = 0, y = 0, w = 0, h = 0;
6327 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6330 w = outputSize.width();
6331 h = outputSize.height();
6334 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6338 VkRect2D *s = &cmd.args.setScissor.scissor;
6339 s->offset.x = int32_t(x);
6340 s->offset.y = int32_t(y);
6341 s->extent.width = uint32_t(w);
6342 s->extent.height = uint32_t(h);
6345 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6346 cbD->commands.unget();
6356 const QSize outputSize = cbD->currentTarget->pixelSize();
6360 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6364 VkViewport *vp = &cmd.args.setViewport.viewport;
6369 vp->minDepth = viewport.minDepth();
6370 vp->maxDepth = viewport.maxDepth();
6373 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6374 cbD->commands.unget();
6379 cbD->currentViewport = viewport;
6380 if (cbD->currentGraphicsPipeline
6381 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6391 Q_ASSERT(!cbD->currentGraphicsPipeline
6393 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6394 const QSize outputSize = cbD->currentTarget->pixelSize();
6398 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6402 VkRect2D *s = &cmd.args.setScissor.scissor;
6405 s->extent.width = uint32_t(w);
6406 s->extent.height = uint32_t(h);
6409 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6410 cbD->commands.unget();
6424 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6425 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6429 cmd.args.setBlendConstants.c[0] = c.redF();
6430 cmd.args.setBlendConstants.c[1] = c.greenF();
6431 cmd.args.setBlendConstants.c[2] = c.blueF();
6432 cmd.args.setBlendConstants.c[3] = c.alphaF();
6442 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6446 cmd.args.setStencilRef.ref = refValue;
6452#ifdef VK_KHR_fragment_shading_rate
6453 if (!vkCmdSetFragmentShadingRateKHR)
6456 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6457 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6458 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6460 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6461 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6462 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6464 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6465 if (cbD->passUsesSecondaryCb) {
6466 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6468 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6469 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6470 cmd.args.setShadingRate.w = size.width;
6471 cmd.args.setShadingRate.h = size.height;
6473 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6474 cbD->hasShadingRateSet =
true;
6477 Q_UNUSED(coarsePixelSize);
6482 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6488 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6492 cmd.args.draw.vertexCount = vertexCount;
6493 cmd.args.draw.instanceCount = instanceCount;
6494 cmd.args.draw.firstVertex = firstVertex;
6495 cmd.args.draw.firstInstance = firstInstance;
6500 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6506 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6507 firstIndex, vertexOffset, firstInstance);
6511 cmd.args.drawIndexed.indexCount = indexCount;
6512 cmd.args.drawIndexed.instanceCount = instanceCount;
6513 cmd.args.drawIndexed.firstIndex = firstIndex;
6514 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6515 cmd.args.drawIndexed.firstInstance = firstInstance;
6520 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6527 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6528 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6530 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6534 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6537 if (caps.drawIndirectMulti) {
6538 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6539 indirectBufVk, indirectBufferOffset,
6542 VkDeviceSize offset = indirectBufferOffset;
6543 for (quint32 i = 0; i < drawCount; ++i) {
6544 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6545 indirectBufVk, offset,
6551 if (caps.drawIndirectMulti) {
6554 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6555 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6556 cmd.args.drawIndirect.drawCount = drawCount;
6557 cmd.args.drawIndirect.stride = stride;
6559 VkDeviceSize offset = indirectBufferOffset;
6560 for (quint32 i = 0; i < drawCount; ++i) {
6563 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6564 cmd.args.drawIndirect.indirectBufferOffset = offset;
6565 cmd.args.drawIndirect.drawCount = 1;
6566 cmd.args.drawIndirect.stride = stride;
6574 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6581 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6582 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6584 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6588 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6591 if (caps.drawIndirectMulti) {
6592 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6593 indirectBufVk, indirectBufferOffset,
6596 VkDeviceSize offset = indirectBufferOffset;
6597 for (quint32 i = 0; i < drawCount; ++i) {
6598 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6599 indirectBufVk, offset,
6605 if (caps.drawIndirectMulti) {
6608 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6609 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
6610 cmd.args.drawIndexedIndirect.drawCount = drawCount;
6611 cmd.args.drawIndexedIndirect.stride = stride;
6613 VkDeviceSize offset = indirectBufferOffset;
6614 for (quint32 i = 0; i < drawCount; ++i) {
6617 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6618 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
6619 cmd.args.drawIndexedIndirect.drawCount = 1;
6620 cmd.args.drawIndexedIndirect.stride = stride;
6629#ifdef VK_EXT_debug_utils
6630 if (!debugMarkers || !caps.debugUtils)
6633 VkDebugUtilsLabelEXT label = {};
6634 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6636 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6637 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6638 label.pLabelName = name.constData();
6639 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6641 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6642 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6643 cmd.args.debugMarkerBegin.label = label;
6644 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6645 cbD->pools.debugMarkerData.append(name);
6655#ifdef VK_EXT_debug_utils
6656 if (!debugMarkers || !caps.debugUtils)
6659 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6660 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6661 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6663 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6664 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6673#ifdef VK_EXT_debug_utils
6674 if (!debugMarkers || !caps.debugUtils)
6677 VkDebugUtilsLabelEXT label = {};
6678 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6680 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6681 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6682 label.pLabelName = msg.constData();
6683 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6685 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6686 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6687 cmd.args.debugMarkerInsert.label = label;
6688 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6689 cbD->pools.debugMarkerData.append(msg);
6699 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6704 Q_ASSERT(cbD->currentTarget);
6707 switch (cbD->currentTarget->resourceType()) {
6708 case QRhiResource::SwapChainRenderTarget:
6711 case QRhiResource::TextureRenderTarget:
6743 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6744 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6748 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6749 cbD->activeSecondaryCbStack.removeLast();
6750 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6752 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6754 cbD->activeSecondaryCbStack.append(extCb);
6766 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6767 cbD->activeSecondaryCbStack.removeLast();
6768 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6769 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6783 if (!debugMarkers || name.isEmpty())
6786 QByteArray decoratedName = name;
6788 decoratedName +=
'/';
6789 decoratedName += QByteArray::number(slot);
6791 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6796#ifdef VK_EXT_debug_utils
6797 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6800 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6801 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6802 nameInfo.objectType = type;
6803 nameInfo.objectHandle = object;
6804 QByteArray decoratedName = name;
6806 decoratedName +=
'/';
6807 decoratedName += QByteArray::number(slot);
6809 nameInfo.pObjectName = decoratedName.constData();
6810 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6822 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6823 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6824 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6825 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6826 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6827 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6828 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6829 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6830 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
6831 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
6832 return VkBufferUsageFlagBits(u);
6838 case QRhiSampler::Nearest:
6839 return VK_FILTER_NEAREST;
6840 case QRhiSampler::Linear:
6841 return VK_FILTER_LINEAR;
6843 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6850 case QRhiSampler::None:
6851 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6852 case QRhiSampler::Nearest:
6853 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6854 case QRhiSampler::Linear:
6855 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6857 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6864 case QRhiSampler::Repeat:
6865 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6866 case QRhiSampler::ClampToEdge:
6867 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6868 case QRhiSampler::Mirror:
6869 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6871 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6878 case QRhiShaderStage::Vertex:
6879 return VK_SHADER_STAGE_VERTEX_BIT;
6880 case QRhiShaderStage::TessellationControl:
6881 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6882 case QRhiShaderStage::TessellationEvaluation:
6883 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6884 case QRhiShaderStage::Fragment:
6885 return VK_SHADER_STAGE_FRAGMENT_BIT;
6886 case QRhiShaderStage::Compute:
6887 return VK_SHADER_STAGE_COMPUTE_BIT;
6888 case QRhiShaderStage::Geometry:
6889 return VK_SHADER_STAGE_GEOMETRY_BIT;
6891 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6898 case QRhiVertexInputAttribute::Float4:
6899 return VK_FORMAT_R32G32B32A32_SFLOAT;
6900 case QRhiVertexInputAttribute::Float3:
6901 return VK_FORMAT_R32G32B32_SFLOAT;
6902 case QRhiVertexInputAttribute::Float2:
6903 return VK_FORMAT_R32G32_SFLOAT;
6904 case QRhiVertexInputAttribute::Float:
6905 return VK_FORMAT_R32_SFLOAT;
6906 case QRhiVertexInputAttribute::UNormByte4:
6907 return VK_FORMAT_R8G8B8A8_UNORM;
6908 case QRhiVertexInputAttribute::UNormByte2:
6909 return VK_FORMAT_R8G8_UNORM;
6910 case QRhiVertexInputAttribute::UNormByte:
6911 return VK_FORMAT_R8_UNORM;
6912 case QRhiVertexInputAttribute::UInt4:
6913 return VK_FORMAT_R32G32B32A32_UINT;
6914 case QRhiVertexInputAttribute::UInt3:
6915 return VK_FORMAT_R32G32B32_UINT;
6916 case QRhiVertexInputAttribute::UInt2:
6917 return VK_FORMAT_R32G32_UINT;
6918 case QRhiVertexInputAttribute::UInt:
6919 return VK_FORMAT_R32_UINT;
6920 case QRhiVertexInputAttribute::SInt4:
6921 return VK_FORMAT_R32G32B32A32_SINT;
6922 case QRhiVertexInputAttribute::SInt3:
6923 return VK_FORMAT_R32G32B32_SINT;
6924 case QRhiVertexInputAttribute::SInt2:
6925 return VK_FORMAT_R32G32_SINT;
6926 case QRhiVertexInputAttribute::SInt:
6927 return VK_FORMAT_R32_SINT;
6928 case QRhiVertexInputAttribute::Half4:
6929 return VK_FORMAT_R16G16B16A16_SFLOAT;
6930 case QRhiVertexInputAttribute::Half3:
6931 return VK_FORMAT_R16G16B16_SFLOAT;
6932 case QRhiVertexInputAttribute::Half2:
6933 return VK_FORMAT_R16G16_SFLOAT;
6934 case QRhiVertexInputAttribute::Half:
6935 return VK_FORMAT_R16_SFLOAT;
6936 case QRhiVertexInputAttribute::UShort4:
6937 return VK_FORMAT_R16G16B16A16_UINT;
6938 case QRhiVertexInputAttribute::UShort3:
6939 return VK_FORMAT_R16G16B16_UINT;
6940 case QRhiVertexInputAttribute::UShort2:
6941 return VK_FORMAT_R16G16_UINT;
6942 case QRhiVertexInputAttribute::UShort:
6943 return VK_FORMAT_R16_UINT;
6944 case QRhiVertexInputAttribute::SShort4:
6945 return VK_FORMAT_R16G16B16A16_SINT;
6946 case QRhiVertexInputAttribute::SShort3:
6947 return VK_FORMAT_R16G16B16_SINT;
6948 case QRhiVertexInputAttribute::SShort2:
6949 return VK_FORMAT_R16G16_SINT;
6950 case QRhiVertexInputAttribute::SShort:
6951 return VK_FORMAT_R16_SINT;
6953 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6960 case QRhiGraphicsPipeline::Triangles:
6961 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6962 case QRhiGraphicsPipeline::TriangleStrip:
6963 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6964 case QRhiGraphicsPipeline::TriangleFan:
6965 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6966 case QRhiGraphicsPipeline::Lines:
6967 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6968 case QRhiGraphicsPipeline::LineStrip:
6969 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6970 case QRhiGraphicsPipeline::Points:
6971 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6972 case QRhiGraphicsPipeline::Patches:
6973 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6975 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6982 case QRhiGraphicsPipeline::None:
6983 return VK_CULL_MODE_NONE;
6984 case QRhiGraphicsPipeline::Front:
6985 return VK_CULL_MODE_FRONT_BIT;
6986 case QRhiGraphicsPipeline::Back:
6987 return VK_CULL_MODE_BACK_BIT;
6989 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6996 case QRhiGraphicsPipeline::CCW:
6997 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6998 case QRhiGraphicsPipeline::CW:
6999 return VK_FRONT_FACE_CLOCKWISE;
7001 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
7008 if (c.testFlag(QRhiGraphicsPipeline::R))
7009 f |= VK_COLOR_COMPONENT_R_BIT;
7010 if (c.testFlag(QRhiGraphicsPipeline::G))
7011 f |= VK_COLOR_COMPONENT_G_BIT;
7012 if (c.testFlag(QRhiGraphicsPipeline::B))
7013 f |= VK_COLOR_COMPONENT_B_BIT;
7014 if (c.testFlag(QRhiGraphicsPipeline::A))
7015 f |= VK_COLOR_COMPONENT_A_BIT;
7016 return VkColorComponentFlags(f);
7022 case QRhiGraphicsPipeline::Zero:
7023 return VK_BLEND_FACTOR_ZERO;
7024 case QRhiGraphicsPipeline::One:
7025 return VK_BLEND_FACTOR_ONE;
7026 case QRhiGraphicsPipeline::SrcColor:
7027 return VK_BLEND_FACTOR_SRC_COLOR;
7028 case QRhiGraphicsPipeline::OneMinusSrcColor:
7029 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
7030 case QRhiGraphicsPipeline::DstColor:
7031 return VK_BLEND_FACTOR_DST_COLOR;
7032 case QRhiGraphicsPipeline::OneMinusDstColor:
7033 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
7034 case QRhiGraphicsPipeline::SrcAlpha:
7035 return VK_BLEND_FACTOR_SRC_ALPHA;
7036 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7037 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
7038 case QRhiGraphicsPipeline::DstAlpha:
7039 return VK_BLEND_FACTOR_DST_ALPHA;
7040 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7041 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7042 case QRhiGraphicsPipeline::ConstantColor:
7043 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7044 case QRhiGraphicsPipeline::OneMinusConstantColor:
7045 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7046 case QRhiGraphicsPipeline::ConstantAlpha:
7047 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7048 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7049 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7050 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7051 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7052 case QRhiGraphicsPipeline::Src1Color:
7053 return VK_BLEND_FACTOR_SRC1_COLOR;
7054 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7055 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7056 case QRhiGraphicsPipeline::Src1Alpha:
7057 return VK_BLEND_FACTOR_SRC1_ALPHA;
7058 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7059 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7061 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7068 case QRhiGraphicsPipeline::Add:
7069 return VK_BLEND_OP_ADD;
7070 case QRhiGraphicsPipeline::Subtract:
7071 return VK_BLEND_OP_SUBTRACT;
7072 case QRhiGraphicsPipeline::ReverseSubtract:
7073 return VK_BLEND_OP_REVERSE_SUBTRACT;
7074 case QRhiGraphicsPipeline::Min:
7075 return VK_BLEND_OP_MIN;
7076 case QRhiGraphicsPipeline::Max:
7077 return VK_BLEND_OP_MAX;
7079 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7086 case QRhiGraphicsPipeline::Never:
7087 return VK_COMPARE_OP_NEVER;
7088 case QRhiGraphicsPipeline::Less:
7089 return VK_COMPARE_OP_LESS;
7090 case QRhiGraphicsPipeline::Equal:
7091 return VK_COMPARE_OP_EQUAL;
7092 case QRhiGraphicsPipeline::LessOrEqual:
7093 return VK_COMPARE_OP_LESS_OR_EQUAL;
7094 case QRhiGraphicsPipeline::Greater:
7095 return VK_COMPARE_OP_GREATER;
7096 case QRhiGraphicsPipeline::NotEqual:
7097 return VK_COMPARE_OP_NOT_EQUAL;
7098 case QRhiGraphicsPipeline::GreaterOrEqual:
7099 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7100 case QRhiGraphicsPipeline::Always:
7101 return VK_COMPARE_OP_ALWAYS;
7103 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7110 case QRhiGraphicsPipeline::StencilZero:
7111 return VK_STENCIL_OP_ZERO;
7112 case QRhiGraphicsPipeline::Keep:
7113 return VK_STENCIL_OP_KEEP;
7114 case QRhiGraphicsPipeline::Replace:
7115 return VK_STENCIL_OP_REPLACE;
7116 case QRhiGraphicsPipeline::IncrementAndClamp:
7117 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7118 case QRhiGraphicsPipeline::DecrementAndClamp:
7119 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7120 case QRhiGraphicsPipeline::Invert:
7121 return VK_STENCIL_OP_INVERT;
7122 case QRhiGraphicsPipeline::IncrementAndWrap:
7123 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7124 case QRhiGraphicsPipeline::DecrementAndWrap:
7125 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7127 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7134 case QRhiGraphicsPipeline::Fill:
7135 return VK_POLYGON_MODE_FILL;
7136 case QRhiGraphicsPipeline::Line:
7137 return VK_POLYGON_MODE_LINE;
7139 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7145 dst->failOp = toVkStencilOp(src.failOp);
7146 dst->passOp = toVkStencilOp(src.passOp);
7147 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7148 dst->compareOp = toVkCompareOp(src.compareOp);
7154 case QRhiShaderResourceBinding::UniformBuffer:
7155 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7156 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7158 case QRhiShaderResourceBinding::SampledTexture:
7159 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7161 case QRhiShaderResourceBinding::Texture:
7162 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7164 case QRhiShaderResourceBinding::Sampler:
7165 return VK_DESCRIPTOR_TYPE_SAMPLER;
7167 case QRhiShaderResourceBinding::ImageLoad:
7168 case QRhiShaderResourceBinding::ImageStore:
7169 case QRhiShaderResourceBinding::ImageLoadStore:
7170 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7172 case QRhiShaderResourceBinding::BufferLoad:
7173 case QRhiShaderResourceBinding::BufferStore:
7174 case QRhiShaderResourceBinding::BufferLoadStore:
7175 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7178 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7185 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7186 s |= VK_SHADER_STAGE_VERTEX_BIT;
7187 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7188 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7189 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7190 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7191 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7192 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7193 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7194 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7195 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7196 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7197 return VkShaderStageFlags(s);
7203 case QRhiSampler::Never:
7204 return VK_COMPARE_OP_NEVER;
7205 case QRhiSampler::Less:
7206 return VK_COMPARE_OP_LESS;
7207 case QRhiSampler::Equal:
7208 return VK_COMPARE_OP_EQUAL;
7209 case QRhiSampler::LessOrEqual:
7210 return VK_COMPARE_OP_LESS_OR_EQUAL;
7211 case QRhiSampler::Greater:
7212 return VK_COMPARE_OP_GREATER;
7213 case QRhiSampler::NotEqual:
7214 return VK_COMPARE_OP_NOT_EQUAL;
7215 case QRhiSampler::GreaterOrEqual:
7216 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7217 case QRhiSampler::Always:
7218 return VK_COMPARE_OP_ALWAYS;
7220 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7228 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7248 e.buffer.buffers[i] = buffers[i];
7250 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7253 buffers[i] = VK_NULL_HANDLE;
7255 stagingBuffers[i] = VK_NULL_HANDLE;
7257 pendingDynamicUpdates[i].clear();
7265 rhiD->releaseQueue.append(e);
7266 rhiD->unregisterResource(
this);
7275 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7276 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7280 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7282 VkBufferCreateInfo bufferInfo = {};
7283 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7284 bufferInfo.size = nonZeroSize;
7285 bufferInfo.usage = toVkBufferUsage(m_usage);
7287 VmaAllocationCreateInfo allocInfo = {};
7289 if (m_type == Dynamic) {
7294 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7297 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7299 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7300 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7304 VkResult err = VK_SUCCESS;
7306 buffers[i] = VK_NULL_HANDLE;
7308 usageState[i].access = usageState[i].stage = 0;
7309 if (i == 0 || m_type == Dynamic) {
7310 VmaAllocation allocation;
7311 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7312 if (err != VK_SUCCESS)
7315 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7316 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7317 m_type == Dynamic ? i : -1);
7321 if (err != VK_SUCCESS) {
7322 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7323 rhiD->printExtraErrorInfo(err);
7329 rhiD->registerResource(
this);
7335 if (m_type == Dynamic) {
7341 b.objects[i] = &buffers[i];
7346 return { { &buffers[0] }, 1 };
7356 Q_ASSERT(m_type == Dynamic);
7358 Q_ASSERT(rhiD->inFrame);
7359 const int slot = rhiD->currentFrameSlot;
7361 VmaAllocation a = toVmaAllocation(allocations[slot]);
7362 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7363 if (err != VK_SUCCESS) {
7364 qWarning(
"Failed to map buffer: %d", err);
7367 return static_cast<
char *>(p);
7373 const int slot = rhiD->currentFrameSlot;
7374 VmaAllocation a = toVmaAllocation(allocations[slot]);
7375 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7376 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7380 int sampleCount, Flags flags,
7381 QRhiTexture::Format backingFormatHint)
7394 if (!memory && !backingTexture)
7401 e.renderBuffer.memory = memory;
7402 e.renderBuffer.image = image;
7403 e.renderBuffer.imageView = imageView;
7405 memory = VK_NULL_HANDLE;
7406 image = VK_NULL_HANDLE;
7407 imageView = VK_NULL_HANDLE;
7417 rhiD->releaseQueue.append(e);
7418 rhiD->unregisterResource(
this);
7424 if (memory || backingTexture)
7427 if (m_pixelSize.isEmpty())
7431 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7434 case QRhiRenderBuffer::Color:
7442 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7450 vkformat = backingTexture->vkformat;
7453 case QRhiRenderBuffer::DepthStencil:
7454 vkformat = rhiD->optimalDepthStencilFormat();
7455 if (!rhiD->createTransientImage(vkformat,
7457 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7458 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7467 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7476 rhiD->registerResource(
this);
7482 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7483 return m_backingFormatHint;
7485 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7489 int arraySize,
int sampleCount, Flags flags)
7493 stagingBuffers[i] = VK_NULL_HANDLE;
7496 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7497 perLevelImageViews[i] = VK_NULL_HANDLE;
7514 e.texture.image = owns ? image : VK_NULL_HANDLE;
7515 e.texture.imageView = imageView;
7519 e.texture.stagingBuffers[i] = stagingBuffers[i];
7522 stagingBuffers[i] = VK_NULL_HANDLE;
7526 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7527 e.texture.extraImageViews[i] = perLevelImageViews[i];
7528 perLevelImageViews[i] = VK_NULL_HANDLE;
7531 image = VK_NULL_HANDLE;
7532 imageView = VK_NULL_HANDLE;
7537 rhiD->releaseQueue.append(e);
7538 rhiD->unregisterResource(
this);
7548 vkformat = toVkTextureFormat(m_format, m_flags);
7549 if (m_writeViewFormat.format != UnknownFormat)
7550 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7552 viewFormat = vkformat;
7553 if (m_readViewFormat.format != UnknownFormat)
7554 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7556 viewFormatForSampling = vkformat;
7558 VkFormatProperties props;
7559 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7560 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7561 if (!canSampleOptimal) {
7562 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7566 const bool isCube = m_flags.testFlag(CubeMap);
7567 const bool isArray = m_flags.testFlag(TextureArray);
7568 const bool is3D = m_flags.testFlag(ThreeDimensional);
7569 const bool is1D = m_flags.testFlag(OneDimensional);
7570 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7572 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7573 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7575 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7576 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7577 if (mipLevelCount > maxLevels) {
7578 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7579 mipLevelCount = maxLevels;
7581 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7582 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7584 qWarning(
"Cubemap texture cannot be multisample");
7588 qWarning(
"3D texture cannot be multisample");
7592 qWarning(
"Multisample texture cannot have mipmaps");
7596 if (isCube && is3D) {
7597 qWarning(
"Texture cannot be both cube and 3D");
7600 if (isArray && is3D) {
7601 qWarning(
"Texture cannot be both array and 3D");
7604 if (isCube && is1D) {
7605 qWarning(
"Texture cannot be both cube and 1D");
7609 qWarning(
"Texture cannot be both 1D and 3D");
7612 if (m_depth > 1 && !is3D) {
7613 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7616 if (m_arraySize > 0 && !isArray) {
7617 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7620 if (m_arraySize < 1 && isArray) {
7621 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7625 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7626 usageState.access = 0;
7627 usageState.stage = 0;
7629 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
7633 *adjustedSize = size;
7642 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7643 const bool isCube = m_flags.testFlag(CubeMap);
7644 const bool isArray = m_flags.testFlag(TextureArray);
7645 const bool is3D = m_flags.testFlag(ThreeDimensional);
7646 const bool is1D = m_flags.testFlag(OneDimensional);
7648 VkImageViewCreateInfo viewInfo = {};
7649 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7650 viewInfo.image = image;
7651 viewInfo.viewType = isCube
7652 ? VK_IMAGE_VIEW_TYPE_CUBE
7653 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7654 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7655 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7656 viewInfo.format = viewFormatForSampling;
7657 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7658 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7659 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7660 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7661 viewInfo.subresourceRange.aspectMask = aspectMask;
7664 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7665 viewInfo.subresourceRange.levelCount = mipLevelCount;
7666 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7667 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7668 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7670 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7673 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7674 if (err != VK_SUCCESS) {
7675 qWarning(
"Failed to create image view: %d", err);
7688 if (!prepareCreate(&size))
7692 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7693 const bool isDepth = isDepthTextureFormat(m_format);
7694 const bool isCube = m_flags.testFlag(CubeMap);
7695 const bool isArray = m_flags.testFlag(TextureArray);
7696 const bool is3D = m_flags.testFlag(ThreeDimensional);
7697 const bool is1D = m_flags.testFlag(OneDimensional);
7699 VkImageCreateInfo imageInfo = {};
7700 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7701 imageInfo.flags = 0;
7703 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7705 if (is3D && isRenderTarget) {
7711 if (!rhiD->caps.texture3DSliceAs2D)
7712 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7713#ifdef VK_VERSION_1_1
7714 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7716 imageInfo.flags |= 0x00000020;
7720 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7721 imageInfo.format = vkformat;
7722 imageInfo.extent.width = uint32_t(size.width());
7723 imageInfo.extent.height = uint32_t(size.height());
7724 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7725 imageInfo.mipLevels = mipLevelCount;
7726 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7727 imageInfo.samples = samples;
7728 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7729 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7731 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7732 if (isRenderTarget) {
7734 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7736 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7738 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7739 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7740 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7741 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7742 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7743 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7744#ifdef VK_KHR_fragment_shading_rate
7745 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7746 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7749 VmaAllocationCreateInfo allocInfo = {};
7750 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7752 VmaAllocation allocation;
7753 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7754 if (err != VK_SUCCESS) {
7755 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7756 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7757 int(imageInfo.format),
7758 imageInfo.mipLevels,
7759 imageInfo.arrayLayers,
7760 int(imageInfo.samples),
7762 rhiD->printExtraErrorInfo(err);
7766 rhiD->setAllocationName(allocation, m_objectName);
7771 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7774 rhiD->registerResource(
this);
7780 VkImage img = VkImage(src.object);
7784 if (!prepareCreate())
7792 usageState.layout = VkImageLayout(src.layout);
7796 rhiD->registerResource(
this);
7802 return {quint64(image), usageState.layout};
7807 usageState.layout = VkImageLayout(layout);
7812 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7813 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7814 return perLevelImageViews[level];
7816 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7817 const bool isCube = m_flags.testFlag(CubeMap);
7818 const bool isArray = m_flags.testFlag(TextureArray);
7819 const bool is3D = m_flags.testFlag(ThreeDimensional);
7820 const bool is1D = m_flags.testFlag(OneDimensional);
7822 VkImageViewCreateInfo viewInfo = {};
7823 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7824 viewInfo.image = image;
7825 viewInfo.viewType = isCube
7826 ? VK_IMAGE_VIEW_TYPE_CUBE
7827 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7828 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7829 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7830 viewInfo.format = viewFormat;
7831 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7832 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7833 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7834 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7835 viewInfo.subresourceRange.aspectMask = aspectMask;
7836 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7837 viewInfo.subresourceRange.levelCount = 1;
7838 viewInfo.subresourceRange.baseArrayLayer = 0;
7839 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7841 VkImageView v = VK_NULL_HANDLE;
7843 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7844 if (err != VK_SUCCESS) {
7845 qWarning(
"Failed to create image view: %d", err);
7846 return VK_NULL_HANDLE;
7849 perLevelImageViews[level] = v;
7854 AddressMode u, AddressMode v, AddressMode w)
7873 e.sampler.sampler = sampler;
7874 sampler = VK_NULL_HANDLE;
7878 rhiD->releaseQueue.append(e);
7879 rhiD->unregisterResource(
this);
7888 VkSamplerCreateInfo samplerInfo = {};
7889 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7890 samplerInfo.magFilter = toVkFilter(m_magFilter);
7891 samplerInfo.minFilter = toVkFilter(m_minFilter);
7892 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7893 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7894 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7895 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7896 samplerInfo.maxAnisotropy = 1.0f;
7897 samplerInfo.compareEnable = m_compareOp != Never;
7898 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7899 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7902 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7903 if (err != VK_SUCCESS) {
7904 qWarning(
"Failed to create sampler: %d", err);
7910 rhiD->registerResource(
this);
7917 serializedFormatData.reserve(64);
7931 rp = VK_NULL_HANDLE;
7939 e.renderPass.rp = rp;
7941 rp = VK_NULL_HANDLE;
7945 rhiD->releaseQueue.append(e);
7946 rhiD->unregisterResource(
this);
7952 return a.format == b.format
7953 && a.samples == b.samples
7954 && a.loadOp == b.loadOp
7955 && a.storeOp == b.storeOp
7956 && a.stencilLoadOp == b.stencilLoadOp
7957 && a.stencilStoreOp == b.stencilStoreOp
7958 && a.initialLayout == b.initialLayout
7959 && a.finalLayout == b.finalLayout;
7972 if (attDescs.size() != o->attDescs.size())
7974 if (colorRefs.size() != o->colorRefs.size())
7976 if (resolveRefs.size() != o->resolveRefs.size())
7982 if (multiViewCount != o->multiViewCount)
7987 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7988 const uint32_t attIdx = colorRefs[i].attachment;
7989 if (attIdx != o->colorRefs[i].attachment)
7991 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7996 const uint32_t attIdx = dsRef.attachment;
7997 if (attIdx != o->dsRef.attachment)
7999 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8003 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8004 const uint32_t attIdx = resolveRefs[i].attachment;
8005 if (attIdx != o->resolveRefs[i].attachment)
8007 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8012 const uint32_t attIdx = dsResolveRef.attachment;
8013 if (attIdx != o->dsResolveRef.attachment)
8015 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8020 const uint32_t attIdx = shadingRateRef.attachment;
8021 if (attIdx != o->shadingRateRef.attachment)
8023 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
8034 serializedFormatData.clear();
8035 auto p =
std::back_inserter(serializedFormatData);
8037 *p++ = attDescs.size();
8038 *p++ = colorRefs.size();
8039 *p++ = resolveRefs.size();
8043 *p++ = multiViewCount;
8045 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8046 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8047 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8048 *p++ = used ? a->format : 0;
8049 *p++ = used ? a->samples : 0;
8050 *p++ = used ? a->loadOp : 0;
8051 *p++ = used ? a->storeOp : 0;
8052 *p++ = used ? a->stencilLoadOp : 0;
8053 *p++ = used ? a->stencilStoreOp : 0;
8054 *p++ = used ? a->initialLayout : 0;
8055 *p++ = used ? a->finalLayout : 0;
8058 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8059 const uint32_t attIdx = colorRefs[i].attachment;
8061 serializeAttachmentData(attIdx);
8065 const uint32_t attIdx = dsRef.attachment;
8067 serializeAttachmentData(attIdx);
8070 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8071 const uint32_t attIdx = resolveRefs[i].attachment;
8073 serializeAttachmentData(attIdx);
8077 const uint32_t attIdx = dsResolveRef.attachment;
8079 serializeAttachmentData(attIdx);
8083 const uint32_t attIdx = shadingRateRef.attachment;
8085 serializeAttachmentData(attIdx);
8094 rpD->attDescs = attDescs;
8095 rpD->colorRefs = colorRefs;
8096 rpD->resolveRefs = resolveRefs;
8097 rpD->subpassDeps = subpassDeps;
8101 rpD->multiViewCount = multiViewCount;
8103 rpD->dsResolveRef = dsResolveRef;
8104 rpD->shadingRateRef = shadingRateRef;
8106 VkRenderPassCreateInfo rpInfo;
8107 VkSubpassDescription subpassDesc;
8108 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8112 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8117#ifdef VK_KHR_create_renderpass2
8118 if (rhiD->caps.renderPass2KHR) {
8120 VkRenderPassCreateInfo2KHR rpInfo2;
8121 RenderPass2SetupHelper rp2Helper(rhiD);
8122 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8126 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8127 if (err != VK_SUCCESS) {
8128 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8135 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8136 if (err != VK_SUCCESS) {
8137 qWarning(
"Failed to create renderpass: %d", err);
8144 rhiD->registerResource(rpD);
8150 return serializedFormatData;
8155 nativeHandlesStruct.renderPass = rp;
8156 return &nativeHandlesStruct;
8182 texture =
QRHI_RES(QVkTexture, src);
8214 return d.sampleCount;
8218 const QRhiTextureRenderTargetDescription &desc,
8223 rtv[att] = VK_NULL_HANDLE;
8224 resrtv[att] = VK_NULL_HANDLE;
8242 e.textureRenderTarget.fb = d.fb;
8243 d.fb = VK_NULL_HANDLE;
8246 e.textureRenderTarget.rtv[att] = rtv[att];
8247 e.textureRenderTarget.resrtv[att] = resrtv[att];
8248 rtv[att] = VK_NULL_HANDLE;
8249 resrtv[att] = VK_NULL_HANDLE;
8252 e.textureRenderTarget.dsv = dsv;
8253 dsv = VK_NULL_HANDLE;
8254 e.textureRenderTarget.resdsv = resdsv;
8255 resdsv = VK_NULL_HANDLE;
8257 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8258 shadingRateMapView = VK_NULL_HANDLE;
8262 rhiD->releaseQueue.append(e);
8263 rhiD->unregisterResource(
this);
8273 if (!rhiD->createOffscreenRenderPass(rp,
8274 m_desc.cbeginColorAttachments(),
8275 m_desc.cendColorAttachments(),
8276 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8277 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8278 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8279 m_desc.depthStencilBuffer(),
8280 m_desc.depthTexture(),
8281 m_desc.depthResolveTexture(),
8282 m_desc.depthLayer(),
8283 m_desc.shadingRateMap()))
8291 rhiD->registerResource(rp);
8300 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8301 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8302 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8305 QVarLengthArray<VkImageView, 8> views;
8306 d.multiViewCount = 0;
8308 d.colorAttCount = 0;
8310 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8311 d.colorAttCount += 1;
8314 Q_ASSERT(texD || rbD);
8316 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8317 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8318 const bool isMultiView = it->multiViewCount() >= 2;
8319 if (isMultiView && d.multiViewCount == 0)
8320 d.multiViewCount = it->multiViewCount();
8321 VkImageViewCreateInfo viewInfo = {};
8322 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8323 viewInfo.image = texD->image;
8324 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8325 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8326 : VK_IMAGE_VIEW_TYPE_2D);
8327 viewInfo.format = texD->viewFormat;
8328 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8329 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8330 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8331 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8332 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8333 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8334 viewInfo.subresourceRange.levelCount = 1;
8335 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8336 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8337 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8338 if (err != VK_SUCCESS) {
8339 qWarning(
"Failed to create render target image view: %d", err);
8342 views.append(rtv[attIndex]);
8343 if (attIndex == 0) {
8344 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8345 d.sampleCount = texD->samples;
8350 if (attIndex == 0) {
8351 d.pixelSize = rbD->pixelSize();
8352 d.sampleCount = rbD->samples;
8358 if (hasDepthStencil) {
8359 if (m_desc.depthTexture()) {
8362 VkImageViewCreateInfo viewInfo = {};
8363 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8364 viewInfo.image = depthTexD->image;
8365 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8366 viewInfo.format = depthTexD->viewFormat;
8367 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8368 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8369 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8370 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8371 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8372 viewInfo.subresourceRange.levelCount = 1;
8373 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8374 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8375 viewInfo.subresourceRange.layerCount = 1;
8378 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8379 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8380 if (err != VK_SUCCESS) {
8381 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8385 if (d.colorAttCount == 0) {
8386 d.pixelSize = depthTexD->pixelSize();
8387 d.sampleCount = depthTexD->samples;
8391 views.append(depthRbD->imageView);
8392 if (d.colorAttCount == 0) {
8393 d.pixelSize = depthRbD->pixelSize();
8394 d.sampleCount = depthRbD->samples;
8402 d.resolveAttCount = 0;
8404 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8405 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8406 if (it->resolveTexture()) {
8408 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8409 d.resolveAttCount += 1;
8411 VkImageViewCreateInfo viewInfo = {};
8412 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8413 viewInfo.image = resTexD->image;
8414 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8415 : VK_IMAGE_VIEW_TYPE_2D;
8416 viewInfo.format = resTexD->viewFormat;
8417 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8418 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8419 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8420 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8421 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8422 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8423 viewInfo.subresourceRange.levelCount = 1;
8424 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8425 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8426 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8427 if (err != VK_SUCCESS) {
8428 qWarning(
"Failed to create render target resolve image view: %d", err);
8431 views.append(resrtv[attIndex]);
8435 if (m_desc.depthResolveTexture()) {
8437 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8439 VkImageViewCreateInfo viewInfo = {};
8440 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8441 viewInfo.image = resTexD->image;
8442 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8443 : VK_IMAGE_VIEW_TYPE_2D;
8444 viewInfo.format = resTexD->viewFormat;
8445 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8446 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8447 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8448 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8449 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8450 viewInfo.subresourceRange.baseMipLevel = 0;
8451 viewInfo.subresourceRange.levelCount = 1;
8452 viewInfo.subresourceRange.baseArrayLayer = 0;
8453 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8454 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8455 if (err != VK_SUCCESS) {
8456 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8459 views.append(resdsv);
8460 d.dsResolveAttCount = 1;
8462 d.dsResolveAttCount = 0;
8465 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8467 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8469 VkImageViewCreateInfo viewInfo = {};
8470 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8471 viewInfo.image = texD->image;
8472 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8473 : VK_IMAGE_VIEW_TYPE_2D;
8474 viewInfo.format = texD->viewFormat;
8475 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8476 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8477 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8478 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8479 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8480 viewInfo.subresourceRange.baseMipLevel = 0;
8481 viewInfo.subresourceRange.levelCount = 1;
8482 viewInfo.subresourceRange.baseArrayLayer = 0;
8483 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8484 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8485 if (err != VK_SUCCESS) {
8486 qWarning(
"Failed to create render target shading rate map view: %d", err);
8489 views.append(shadingRateMapView);
8490 d.shadingRateAttCount = 1;
8492 d.shadingRateAttCount = 0;
8495 if (!m_renderPassDesc)
8496 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8498 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8499 Q_ASSERT(d.rp && d.rp->rp);
8501 VkFramebufferCreateInfo fbInfo = {};
8502 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8503 fbInfo.renderPass = d.rp->rp;
8504 fbInfo.attachmentCount = uint32_t(views.count());
8505 fbInfo.pAttachments = views.constData();
8506 fbInfo.width = uint32_t(d.pixelSize.width());
8507 fbInfo.height = uint32_t(d.pixelSize.height());
8510 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8511 if (err != VK_SUCCESS) {
8512 qWarning(
"Failed to create framebuffer: %d", err);
8516 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8519 rhiD->registerResource(
this);
8525 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8538 return d.sampleCount;
8556 sortedBindings.clear();
8557 sortedDynamicOffsetBindingNumbers.clear();
8563 e.shaderResourceBindings.poolIndex =
poolIndex;
8564 e.shaderResourceBindings.layout = layout;
8567 layout = VK_NULL_HANDLE;
8568 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8569 descSets[i] = VK_NULL_HANDLE;
8573 rhiD->releaseQueue.append(e);
8574 rhiD->unregisterResource(
this);
8584 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8587 rhiD->updateLayoutDesc(
this);
8589 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8590 descSets[i] = VK_NULL_HANDLE;
8592 sortedBindings.clear();
8593 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8594 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8596 sortedDynamicOffsetBindingNumbers.clear();
8597 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8598 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8599 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8600 if (b->u.ubuf.hasDynamicOffset)
8601 sortedDynamicOffsetBindingNumbers.append(b->binding);
8605 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
8606 vkbindings.reserve(sortedBindings.size());
8607 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8608 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8609 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
8610 vkbinding.binding = uint32_t(b->binding);
8611 vkbinding.descriptorType = toVkDescriptorType(b);
8612 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8613 vkbinding.descriptorCount = b->u.stex.count;
8615 vkbinding.descriptorCount = 1;
8616 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8619 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8620 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8621 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8622 layoutInfo.pBindings = vkbindings.constData();
8624 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8625 if (err != VK_SUCCESS) {
8626 qWarning(
"Failed to create descriptor set layout: %d", err);
8629 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
8631 VkDescriptorSetAllocateInfo allocInfo = {};
8632 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8635 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8636 layouts[i] = layout;
8637 allocInfo.pSetLayouts = layouts;
8638 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8642 boundResourceData[i].resize(sortedBindings.size());
8643 for (BoundResourceData &bd : boundResourceData[i])
8644 memset(&bd, 0,
sizeof(BoundResourceData));
8648 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
8652 rhiD->registerResource(
this);
8658 sortedBindings.clear();
8659 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8660 if (!flags.testFlag(BindingsAreSorted))
8661 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8663 sortedDynamicOffsetBindingNumbers.clear();
8664 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8665 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8666 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8667 if (b->u.ubuf.hasDynamicOffset)
8668 sortedDynamicOffsetBindingNumbers.append(b->binding);
8682 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8683 for (BoundResourceData &bd : boundResourceData[i])
8684 memset(&bd, 0,
sizeof(BoundResourceData));
8702 if (!pipeline && !layout)
8709 e.pipelineState.pipeline = pipeline;
8710 e.pipelineState.layout = layout;
8712 pipeline = VK_NULL_HANDLE;
8713 layout = VK_NULL_HANDLE;
8717 rhiD->releaseQueue.append(e);
8718 rhiD->unregisterResource(
this);
8724 if (pipeline || layout)
8728 rhiD->pipelineCreationStart();
8729 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8732 if (!rhiD->ensurePipelineCache())
8735 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8736 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8737 pipelineLayoutInfo.setLayoutCount = 1;
8739 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8740 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8741 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8742 if (err != VK_SUCCESS) {
8743 qWarning(
"Failed to create pipeline layout: %d", err);
8746 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
8747 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
8748 layout = VK_NULL_HANDLE;
8751 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8752 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8754 QVarLengthArray<VkShaderModule, 4> shaders;
8755 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
8756 for (VkShaderModule shader : shaders)
8757 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8759 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8760 QVarLengthArray<QByteArray, 4> entryPointNames;
8761 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8762 const QShader bakedShader = shaderStage.shader();
8763 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8764 if (spirv.shader().isEmpty()) {
8765 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8768 VkShaderModule shader = rhiD->createShader(spirv.shader());
8770 shaders.append(shader);
8771 VkPipelineShaderStageCreateInfo shaderInfo = {};
8772 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8773 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8774 shaderInfo.module = shader;
8775 entryPointNames.append(spirv.entryPoint());
8776 shaderInfo.pName =
nullptr;
8777 shaderStageCreateInfos.append(shaderInfo);
8782 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
8783 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
8785 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8786 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8788 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8789#ifdef VK_EXT_vertex_attribute_divisor
8790 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8792 int bindingIndex = 0;
8793 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8794 it != itEnd; ++it, ++bindingIndex)
8796 VkVertexInputBindingDescription bindingInfo = {
8797 uint32_t(bindingIndex),
8799 it->classification() == QRhiVertexInputBinding::PerVertex
8800 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8802 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8803#ifdef VK_EXT_vertex_attribute_divisor
8804 if (rhiD->caps.vertexAttribDivisor) {
8805 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8809 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8810 "VK_EXT_vertex_attribute_divisor on the device and "
8811 "VK_KHR_get_physical_device_properties2 on the instance");
8814 vertexBindings.append(bindingInfo);
8816 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8817 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8820 VkVertexInputAttributeDescription attributeInfo = {
8821 uint32_t(it->location()),
8822 uint32_t(it->binding()),
8823 toVkAttributeFormat(it->format()),
8826 vertexAttributes.append(attributeInfo);
8828 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8829 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8830 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8831 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8832 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8833 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8834#ifdef VK_EXT_vertex_attribute_divisor
8835 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8836 if (!nonOneStepRates.isEmpty()) {
8837 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8838 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8839 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8840 vertexInputInfo.pNext = &divisorInfo;
8843 pipelineInfo.pVertexInputState = &vertexInputInfo;
8845 QVarLengthArray<VkDynamicState, 8> dynEnable;
8846 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8847 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8848 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8849 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8850 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8851 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8852#ifdef VK_KHR_fragment_shading_rate
8853 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8854 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8857 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8858 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8859 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8860 dynamicInfo.pDynamicStates = dynEnable.constData();
8861 pipelineInfo.pDynamicState = &dynamicInfo;
8863 VkPipelineViewportStateCreateInfo viewportInfo = {};
8864 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8865 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8866 pipelineInfo.pViewportState = &viewportInfo;
8868 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8869 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8870 inputAsmInfo.topology = toVkTopology(m_topology);
8871 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8872 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8874 VkPipelineTessellationStateCreateInfo tessInfo = {};
8875#ifdef VK_VERSION_1_1
8876 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8878 if (m_topology == Patches) {
8879 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8880 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8887#ifdef VK_VERSION_1_1
8888 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8889 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8890 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8891 tessInfo.pNext = &originInfo;
8893 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8896 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8899 pipelineInfo.pTessellationState = &tessInfo;
8902 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8903 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8904 if (m_depthClamp && rhiD->caps.depthClamp)
8905 rastInfo.depthClampEnable = m_depthClamp;
8906 rastInfo.cullMode = toVkCullMode(m_cullMode);
8907 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8908 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8909 rastInfo.depthBiasEnable =
true;
8910 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8911 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8913 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8914 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8915 pipelineInfo.pRasterizationState = &rastInfo;
8917 VkPipelineMultisampleStateCreateInfo msInfo = {};
8918 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8919 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8920 pipelineInfo.pMultisampleState = &msInfo;
8922 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8923 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8924 dsInfo.depthTestEnable = m_depthTest;
8925 dsInfo.depthWriteEnable = m_depthWrite;
8926 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8927 dsInfo.stencilTestEnable = m_stencilTest;
8928 if (m_stencilTest) {
8929 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8930 dsInfo.front.compareMask = m_stencilReadMask;
8931 dsInfo.front.writeMask = m_stencilWriteMask;
8932 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8933 dsInfo.back.compareMask = m_stencilReadMask;
8934 dsInfo.back.writeMask = m_stencilWriteMask;
8936 pipelineInfo.pDepthStencilState = &dsInfo;
8938 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8939 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8940 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8941 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8942 VkPipelineColorBlendAttachmentState blend = {};
8943 blend.blendEnable = b.enable;
8944 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8945 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8946 blend.colorBlendOp = toVkBlendOp(b.opColor);
8947 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8948 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8949 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8950 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8951 vktargetBlends.append(blend);
8953 if (vktargetBlends.isEmpty()) {
8954 VkPipelineColorBlendAttachmentState blend = {};
8955 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8956 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8957 vktargetBlends.append(blend);
8959 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8960 blendInfo.pAttachments = vktargetBlends.constData();
8961 pipelineInfo.pColorBlendState = &blendInfo;
8963 pipelineInfo.layout = layout;
8965 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8966 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8968 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8970 if (err != VK_SUCCESS) {
8971 qWarning(
"Failed to create graphics pipeline: %d", err);
8974 pipelineLayoutCleanup.dismiss();
8976 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8978 rhiD->pipelineCreationEnd();
8981 rhiD->registerResource(
this);
8997 if (!pipeline && !layout)
9004 e.pipelineState.pipeline = pipeline;
9005 e.pipelineState.layout = layout;
9007 pipeline = VK_NULL_HANDLE;
9008 layout = VK_NULL_HANDLE;
9012 rhiD->releaseQueue.append(e);
9013 rhiD->unregisterResource(
this);
9019 if (pipeline || layout)
9023 rhiD->pipelineCreationStart();
9024 if (!rhiD->ensurePipelineCache())
9027 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
9028 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
9029 pipelineLayoutInfo.setLayoutCount = 1;
9031 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
9032 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
9033 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
9034 if (err != VK_SUCCESS) {
9035 qWarning(
"Failed to create pipeline layout: %d", err);
9038 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9039 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9040 layout = VK_NULL_HANDLE;
9043 VkComputePipelineCreateInfo pipelineInfo = {};
9044 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9045 pipelineInfo.layout = layout;
9047 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9048 qWarning(
"Compute pipeline requires a compute shader stage");
9051 const QShader bakedShader = m_shaderStage.shader();
9052 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9053 if (spirv.shader().isEmpty()) {
9054 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9057 if (bakedShader.stage() != QShader::ComputeStage) {
9058 qWarning() << bakedShader <<
"is not a compute shader";
9061 VkShaderModule shader = rhiD->createShader(spirv.shader());
9064 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9065 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9067 VkPipelineShaderStageCreateInfo shaderInfo = {};
9068 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9069 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9070 shaderInfo.module = shader;
9071 const QByteArray entryPointName = spirv.entryPoint();
9072 shaderInfo.pName = entryPointName.constData();
9073 pipelineInfo.stage = shaderInfo;
9075 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9076 if (err != VK_SUCCESS) {
9077 qWarning(
"Failed to create graphics pipeline: %d", err);
9080 pipelineLayoutCleanup.dismiss();
9082 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9084 rhiD->pipelineCreationEnd();
9087 rhiD->registerResource(
this);
9116 nativeHandlesStruct.commandBuffer = cb;
9118 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9119 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9121 nativeHandlesStruct.commandBuffer = cb;
9124 return &nativeHandlesStruct;
9142 if (sc == VK_NULL_HANDLE)
9147 rhiD->swapchains.remove(
this);
9153 frame.cmdBuf = VK_NULL_HANDLE;
9157 surface = lastConnectedSurface = VK_NULL_HANDLE;
9160 rhiD->unregisterResource(
this);
9175 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9185 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9187 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9188 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9189 if (bufferSize.width == uint32_t(-1)) {
9190 Q_ASSERT(bufferSize.height == uint32_t(-1));
9191 return m_window->size() * m_window->devicePixelRatio();
9193 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9199 case QRhiSwapChain::HDRExtendedSrgbLinear:
9200 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9201 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9202 case QRhiSwapChain::HDR10:
9203 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9204 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9205 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9206 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9207 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9220 qWarning(
"Attempted to call isFormatSupported() without a window set");
9225 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9228 uint32_t formatCount = 0;
9229 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9230 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9232 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9233 for (uint32_t i = 0; i < formatCount; ++i) {
9234 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9246 QRHI_RES_RHI(QRhiVulkan);
9248 if (m_window && rhiD->adapterLuidValid)
9249 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9263 if (!rhiD->createDefaultRenderPass(rp,
9264 m_depthStencil !=
nullptr,
9275 rhiD->registerResource(rp);
9282 case VK_FORMAT_R8_SRGB:
9283 case VK_FORMAT_R8G8_SRGB:
9284 case VK_FORMAT_R8G8B8_SRGB:
9285 case VK_FORMAT_B8G8R8_SRGB:
9286 case VK_FORMAT_R8G8B8A8_SRGB:
9287 case VK_FORMAT_B8G8R8A8_SRGB:
9288 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9303 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9305 qWarning(
"Failed to get surface for window");
9308 if (surface == surf)
9314 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9315 qWarning(
"Presenting not supported on this window");
9319 quint32 formatCount = 0;
9320 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9321 QList<VkSurfaceFormatKHR> formats(formatCount);
9322 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9326 colorFormat = formats.constFirst().format;
9327 colorSpace = formats.constFirst().colorSpace;
9330 const bool srgbRequested = m_flags.testFlag(sRGB);
9331 bool foundBestFormat =
false;
9332 if (m_format == SDR) {
9333 for (
int i = 0; i <
int(formatCount); ++i) {
9335 if (srgbRequested) {
9336 ok = defaultSrgbColorFormat == formats[i].format;
9338 ok = defaultColorFormat == formats[i].format;
9341 foundBestFormat =
true;
9342 colorFormat = formats[i].format;
9343 colorSpace = formats[i].colorSpace;
9350 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9351 for (
int i = 0; i <
int(formatCount); ++i) {
9353 if (m_format != SDR) {
9354 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9355 }
else if (srgbRequested) {
9356 ok = isSrgbFormat(formats[i].format);
9359 colorFormat = formats[i].format;
9360 colorSpace = formats[i].colorSpace;
9367 if (m_format != SDR) {
9368 VkSurfaceFormatKHR format{};
9369 format.format = colorFormat;
9370 format.colorSpace = colorSpace;
9371 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9372 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9376 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9377 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9382#if QT_CONFIG(wayland)
9387 const bool hasPassThrough =
9388 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9389 return fmt.format == colorFormat
9390 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9392 if (hasPassThrough) {
9393 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9397 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9399 quint32 presModeCount = 0;
9400 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9401 supportedPresentationModes.resize(presModeCount);
9402 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9403 supportedPresentationModes.data());
9411 const bool needsRegistration = !window || window != m_window;
9418 if (window && window != m_window)
9422 m_currentPixelSize = surfacePixelSize();
9423 pixelSize = m_currentPixelSize;
9426 qWarning(
"Failed to create new swapchain");
9430 if (needsRegistration || !rhiD->swapchains.contains(
this))
9431 rhiD->swapchains.insert(
this);
9433 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9434 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9435 m_depthStencil->sampleCount(), m_sampleCount);
9437 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9438 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9439 m_depthStencil->setPixelSize(pixelSize);
9440 if (!m_depthStencil->create())
9441 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9442 pixelSize.width(), pixelSize.height());
9444 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9445 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9446 pixelSize.width(), pixelSize.height());
9450 if (!m_renderPassDesc)
9451 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9453 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9454 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9455 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9457 rtWrapper.d.pixelSize = pixelSize;
9458 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9459 rtWrapper.d.sampleCount = samples;
9460 rtWrapper.d.colorAttCount = 1;
9461 if (m_depthStencil) {
9462 rtWrapper.d.dsAttCount = 1;
9463 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9465 rtWrapper.d.dsAttCount = 0;
9468 rtWrapper.d.dsResolveAttCount = 0;
9469 if (samples > VK_SAMPLE_COUNT_1_BIT)
9470 rtWrapper.d.resolveAttCount = 1;
9472 rtWrapper.d.resolveAttCount = 0;
9474 if (shadingRateMapView)
9475 rtWrapper.d.shadingRateAttCount = 1;
9477 rtWrapper.d.shadingRateAttCount = 0;
9482 QVarLengthArray<VkImageView, 4> views;
9483 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9485 views.append(
ds->imageView);
9486 if (samples > VK_SAMPLE_COUNT_1_BIT)
9487 views.append(image.imageView);
9488 if (shadingRateMapView)
9489 views.append(shadingRateMapView);
9491 VkFramebufferCreateInfo fbInfo = {};
9492 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9493 fbInfo.renderPass = rtWrapper.d.rp->rp;
9494 fbInfo.attachmentCount = uint32_t(views.count());
9495 fbInfo.pAttachments = views.constData();
9496 fbInfo.width = uint32_t(pixelSize.width());
9497 fbInfo.height = uint32_t(pixelSize.height());
9500 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9501 if (err != VK_SUCCESS) {
9502 qWarning(
"Failed to create framebuffer: %d", err);
9508 rtWrapperRight.setRenderPassDescriptor(
9510 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9511 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9513 rtWrapperRight.d.pixelSize = pixelSize;
9514 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9515 rtWrapperRight.d.sampleCount = samples;
9516 rtWrapperRight.d.colorAttCount = 1;
9517 if (m_depthStencil) {
9518 rtWrapperRight.d.dsAttCount = 1;
9519 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9521 rtWrapperRight.d.dsAttCount = 0;
9524 rtWrapperRight.d.dsResolveAttCount = 0;
9525 if (samples > VK_SAMPLE_COUNT_1_BIT)
9526 rtWrapperRight.d.resolveAttCount = 1;
9528 rtWrapperRight.d.resolveAttCount = 0;
9533 QVarLengthArray<VkImageView, 4> views;
9534 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9536 views.append(
ds->imageView);
9537 if (samples > VK_SAMPLE_COUNT_1_BIT)
9538 views.append(image.imageView);
9539 if (shadingRateMapView)
9540 views.append(shadingRateMapView);
9542 VkFramebufferCreateInfo fbInfo = {};
9543 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9544 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9545 fbInfo.attachmentCount = uint32_t(views.count());
9546 fbInfo.pAttachments = views.constData();
9547 fbInfo.width = uint32_t(pixelSize.width());
9548 fbInfo.height = uint32_t(pixelSize.height());
9551 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9552 if (err != VK_SUCCESS) {
9553 qWarning(
"Failed to create framebuffer: %d", err);
9561 if (needsRegistration)
9562 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
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)
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) 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 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
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)