5#include <qpa/qplatformvulkaninstance.h>
7#define VMA_IMPLEMENTATION
8#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
9#define VMA_STATIC_VULKAN_FUNCTIONS 0
10#define VMA_RECORDING_ENABLED 0
11#define VMA_DEDICATED_ALLOCATION 0
13Q_STATIC_LOGGING_CATEGORY(QRHI_LOG_VMA,
"qt.rhi.vma")
15#define VMA_ASSERT(expr) Q_ASSERT(expr)
17#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1
18#define VMA_DEBUG_LOG(str) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), (str))
19#define VMA_DEBUG_LOG_FORMAT(format, ...) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, __VA_ARGS__)
21template<
typename... Args>
22static void debugVmaLeak(
const char *format, Args&&... args)
26 static bool leakCheck =
true;
29 static bool leakCheck = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)(
"QT_RHI_LEAK_CHECK");
32 QT_PREPEND_NAMESPACE(qWarning)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, std::forward<Args>(args)...);
34#define VMA_LEAK_LOG_FORMAT(format, ...) debugVmaLeak(format, __VA_ARGS__)
36QT_WARNING_DISABLE_GCC(
"-Wsuggest-override")
37QT_WARNING_DISABLE_GCC(
"-Wundef")
38QT_WARNING_DISABLE_CLANG(
"-Wundef")
39#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1100
40QT_WARNING_DISABLE_CLANG(
"-Wdeprecated-copy")
42#include "vk_mem_alloc.h"
46#include <QVulkanFunctions>
47#include <QtGui/qwindow.h>
48#include <private/qvulkandefaultinstance_p.h>
54
55
56
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
85
86
87
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
195
196
197
198
199
202
203
204
205
208
209
210
211
212
216
217
218
219
220
221
222
223
224
225
228
229
230
231
234
235
236
237
238
241
242
243
244
247
248
249
250
253
254
255
256
257
260
261
262
263
264
267
268
269
270
271
275
276
277
278
279
280
281
282
283
284
285
286
287
288
291
292
293
294
298
299
300
301
302
303
304
305
308
309
310
311
315
316
317
318
319
320
321
324
325
326
327
328
329
332
333
334
335
336
337
340
341
342
343
344
345
348
349
350
351
352
353
356
357
358
359
360
361
364
365
366
367
368
369
372inline Int aligned(Int v, Int byteAlign)
374 return (v + byteAlign - 1) & ~(byteAlign - 1);
379static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
381 return globalVulkanInstance->getInstanceProcAddr(pName);
384static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
386 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
391 return reinterpret_cast<VmaAllocation>(a);
396 return reinterpret_cast<VmaAllocator>(a);
400
401
402
403
404
405
406QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
409 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"),
411 QByteArrayLiteral(
"VK_EXT_swapchain_colorspace")
416
417
418
419
420QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
423 QByteArrayLiteral(
"VK_KHR_swapchain"),
424 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
425 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
426 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
427 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
440 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
441 inst = QVulkanDefaultInstance::instance();
445 requestedDeviceExtensions = params->deviceExtensions;
448 physDev = importParams->physDev;
449 dev = importParams->dev;
450 if (dev && physDev) {
452 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
453 gfxQueueIdx = importParams->gfxQueueIdx;
455 if (importParams->vmemAllocator) {
464 QVulkanInstance::DebugMessageTypeFlags type,
465 const void *callbackData)
469#ifdef VK_EXT_debug_utils
470 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
474 if (strstr(d->pMessage,
"Mapping an image with layout")
475 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
486 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
489 Q_UNUSED(callbackData);
497 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
498 return QRhiDriverInfo::UnknownDevice;
499 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
500 return QRhiDriverInfo::IntegratedDevice;
501 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
502 return QRhiDriverInfo::DiscreteDevice;
503 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
504 return QRhiDriverInfo::VirtualDevice;
505 case VK_PHYSICAL_DEVICE_TYPE_CPU:
506 return QRhiDriverInfo::CpuDevice;
508 return QRhiDriverInfo::UnknownDevice;
512static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
514 info->deviceName = QByteArray(physDevProperties.deviceName);
515 info->deviceId = physDevProperties.deviceID;
516 info->vendorId = physDevProperties.vendorID;
517 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
523 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
525 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
531 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
537 if (!inst->isValid()) {
538 qWarning(
"Vulkan instance is not valid");
543 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
545 globalVulkanInstance = inst;
546 f = inst->functions();
547 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
548 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
549 for (
const char *ext : inst->extensions())
550 qCDebug(QRHI_LOG_INFO,
" %s", ext);
554 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
556 QList<VkQueueFamilyProperties> queueFamilyProps;
557 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
558 uint32_t queueCount = 0;
559 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
560 queueFamilyProps.resize(
int(queueCount));
561 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
566 uint32_t physDevCount = 0;
567 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
569 qWarning(
"No physical devices");
572 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
573 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
574 if (err != VK_SUCCESS || !physDevCount) {
575 qWarning(
"Failed to enumerate physical devices: %d", err);
579 int physDevIndex = -1;
580 int requestedPhysDevIndex = -1;
581 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
582 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
584 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
585 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
586 for (
int i = 0; i <
int(physDevCount); ++i) {
587 if (physDevs[i] == requestedPhysDev) {
588 requestedPhysDevIndex = i;
594 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
595 for (
int i = 0; i <
int(physDevCount); ++i) {
596 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
597 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
598 requestedPhysDevIndex = i;
604 for (
int i = 0; i <
int(physDevCount); ++i) {
605 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
606 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
608 physDevProperties.deviceName,
609 VK_VERSION_MAJOR(physDevProperties.driverVersion),
610 VK_VERSION_MINOR(physDevProperties.driverVersion),
611 VK_VERSION_PATCH(physDevProperties.driverVersion),
612 VK_VERSION_MAJOR(physDevProperties.apiVersion),
613 VK_VERSION_MINOR(physDevProperties.apiVersion),
614 VK_VERSION_PATCH(physDevProperties.apiVersion),
615 physDevProperties.vendorID,
616 physDevProperties.deviceID,
617 physDevProperties.deviceType);
618 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
620 qCDebug(QRHI_LOG_INFO,
" using this physical device");
624 if (physDevIndex < 0) {
625 qWarning(
"No matching physical device");
628 physDev = physDevs[physDevIndex];
629 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
631 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
632 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
633 physDevProperties.deviceName,
634 VK_VERSION_MAJOR(physDevProperties.driverVersion),
635 VK_VERSION_MINOR(physDevProperties.driverVersion),
636 VK_VERSION_PATCH(physDevProperties.driverVersion),
637 VK_VERSION_MAJOR(physDevProperties.apiVersion),
638 VK_VERSION_MINOR(physDevProperties.apiVersion),
639 VK_VERSION_PATCH(physDevProperties.apiVersion),
640 physDevProperties.vendorID,
641 physDevProperties.deviceID,
642 physDevProperties.deviceType);
645 caps.apiVersion = inst->apiVersion();
651 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
652 VK_VERSION_MINOR(physDevProperties.apiVersion));
653 if (physDevApiVersion < caps.apiVersion) {
654 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
655 <<
"whereas the chosen physical device has" << physDevApiVersion
656 <<
"- restricting to the latter";
657 caps.apiVersion = physDevApiVersion;
662 QVulkanInfoVector<QVulkanExtension> devExts;
663 uint32_t devExtCount = 0;
664 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
666 QList<VkExtensionProperties> extProps(devExtCount);
667 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
668 for (
const VkExtensionProperties &p : std::as_const(extProps))
669 devExts.append({ p.extensionName, p.specVersion });
671 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
673 bool featuresQueried =
false;
675 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
676 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
679#ifdef VK_KHR_fragment_shading_rate
680 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
681 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
682 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
683 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
685#ifdef VK_EXT_device_fault
686 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
687 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
688 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
689 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
695 if (!featuresQueried) {
697 if (caps.apiVersion >= QVersionNumber(1, 2)) {
698 physDevFeatures11IfApi12OrNewer = {};
699 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
700 physDevFeatures12 = {};
701 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
703 physDevFeatures13 = {};
704 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
706 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
707 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
709 if (caps.apiVersion >= QVersionNumber(1, 3))
710 physDevFeatures12.pNext = &physDevFeatures13;
712 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
713 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
714 featuresQueried =
true;
721 if (!featuresQueried) {
729 if (caps.apiVersion == QVersionNumber(1, 1)) {
730 multiviewFeaturesIfApi11 = {};
731 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
732 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
733 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
734 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
735 featuresQueried =
true;
740 if (!featuresQueried) {
743 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
744 featuresQueried =
true;
752 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
753 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
754 queryQueueFamilyProps();
755 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
756 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
757 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
758 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
759 if (!gfxQueueFamilyIdxOpt.has_value()
760 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
761 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
763 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
764 gfxQueueFamilyIdxOpt = i;
765 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
766 computelessGfxQueueCandidateIdxOpt = i;
769 if (gfxQueueFamilyIdxOpt.has_value()) {
770 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
772 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
773 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
775 qWarning(
"No graphics (or no graphics+present) queue family found");
780 VkDeviceQueueCreateInfo queueInfo = {};
781 const float prio[] = { 0 };
782 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
783 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
784 queueInfo.queueCount = 1;
785 queueInfo.pQueuePriorities = prio;
787 QList<
const char *> devLayers;
788 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
789 devLayers.append(
"VK_LAYER_KHRONOS_validation");
791 QList<
const char *> requestedDevExts;
792 requestedDevExts.append(
"VK_KHR_swapchain");
794 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
796 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
797 if (hasPhysDevProp2) {
798 requestedDevExts.append(
"VK_KHR_portability_subset");
800 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
801 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
806#ifdef VK_EXT_vertex_attribute_divisor
807 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
808 if (hasPhysDevProp2) {
809 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
810 caps.vertexAttribDivisor =
true;
815#ifdef VK_KHR_create_renderpass2
816 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
817 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
818 caps.renderPass2KHR =
true;
822#ifdef VK_KHR_depth_stencil_resolve
823 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
824 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
825 caps.depthStencilResolveKHR =
true;
829#ifdef VK_KHR_fragment_shading_rate
830 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
831 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
834#ifdef VK_EXT_device_fault
835 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
836 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
837 caps.deviceFault =
true;
841 for (
const QByteArray &ext : requestedDeviceExtensions) {
842 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
843 if (devExts.contains(ext)) {
844 requestedDevExts.append(ext.constData());
846 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
852 QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
853 for (
const QByteArray &ext : envExtList) {
854 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
855 if (devExts.contains(ext)) {
856 requestedDevExts.append(ext.constData());
858 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
864 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
865 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
866 for (
const char *ext : requestedDevExts)
867 qCDebug(QRHI_LOG_INFO,
" %s", ext);
870 VkDeviceCreateInfo devInfo = {};
871 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
872 devInfo.queueCreateInfoCount = 1;
873 devInfo.pQueueCreateInfos = &queueInfo;
874 devInfo.enabledLayerCount = uint32_t(devLayers.size());
875 devInfo.ppEnabledLayerNames = devLayers.constData();
876 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
877 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
893 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
896 physDevFeatures13.robustImageAccess = VK_FALSE;
900 if (caps.apiVersion >= QVersionNumber(1, 1)) {
907 devInfo.pNext = &physDevFeaturesChainable;
911 physDevFeatures.robustBufferAccess = VK_FALSE;
912 devInfo.pEnabledFeatures = &physDevFeatures;
915 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
916 if (err != VK_SUCCESS) {
917 qWarning(
"Failed to create device: %d", err);
921 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
926 caps.deviceFault =
true;
927 caps.vertexAttribDivisor =
true;
928 caps.renderPass2KHR =
true;
929 caps.depthStencilResolveKHR =
true;
932 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
933 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
934 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
935 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
936 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
937 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
939 df = inst->deviceFunctions(dev);
941 VkCommandPoolCreateInfo poolInfo = {};
942 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
943 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
945 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
946 if (err != VK_SUCCESS) {
947 qWarning(
"Failed to create command pool: %d", err);
952 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
953 gfxQueueFamilyIdx, gfxQueueIdx);
955 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
957 if (queueFamilyProps.isEmpty())
958 queryQueueFamilyProps();
960 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
961 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
963 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
966 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
968 caps.depthClamp = physDevFeatures.depthClamp;
970 caps.wideLines = physDevFeatures.wideLines;
972 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
974 caps.tessellation = physDevFeatures.tessellationShader;
975 caps.geometryShader = physDevFeatures.geometryShader;
977 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
980 if (caps.apiVersion >= QVersionNumber(1, 2))
981 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
985 if (caps.apiVersion == QVersionNumber(1, 1))
986 caps.multiView = multiviewFeaturesIfApi11.multiview;
989#ifdef VK_KHR_fragment_shading_rate
990 fragmentShadingRates.clear();
991 if (caps.apiVersion >= QVersionNumber(1, 1)) {
992 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
993 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
994 if (caps.imageBasedShadingRate) {
995 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
996 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
997 VkPhysicalDeviceProperties2 props2 = {};
998 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
999 props2.pNext = &shadingRateProps;
1000 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1001 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1004 if (caps.perDrawShadingRate) {
1005 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1006 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1007 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1008 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1010 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1011 fragmentShadingRates.resize(count);
1012 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1014 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1016 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1018 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1019 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1028#ifdef VK_KHR_create_renderpass2
1029 if (caps.renderPass2KHR) {
1030 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1031 if (!vkCreateRenderPass2KHR)
1032 caps.renderPass2KHR =
false;
1038 adapterLuidValid =
false;
1040#ifdef VK_VERSION_1_2
1041 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1042 VkPhysicalDeviceVulkan11Properties v11props = {};
1043 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1044 VkPhysicalDeviceProperties2 props2 = {};
1045 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1046 props2.pNext = &v11props;
1047 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1048 if (v11props.deviceLUIDValid) {
1049 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1050 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1051 adapterLuidValid =
true;
1052 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1053 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1054 adapterLuid.LowPart, adapterLuid.HighPart);
1061 VmaVulkanFunctions funcs = {};
1062 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1063 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1065 VmaAllocatorCreateInfo allocatorInfo = {};
1068 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1069 allocatorInfo.physicalDevice = physDev;
1070 allocatorInfo.device = dev;
1071 allocatorInfo.pVulkanFunctions = &funcs;
1072 allocatorInfo.instance = inst->vkInstance();
1080#ifdef VK_VERSION_1_4
1081 if (caps.apiVersion >= QVersionNumber(1, 4))
1082 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1085#ifdef VK_VERSION_1_3
1086 if (caps.apiVersion >= QVersionNumber(1, 3))
1087 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1090#ifdef VK_VERSION_1_2
1091 if (caps.apiVersion >= QVersionNumber(1, 2))
1092 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1095#ifdef VK_VERSION_1_1
1096 if (caps.apiVersion >= QVersionNumber(1, 1))
1097 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1100#ifdef VK_VERSION_1_0
1101 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1104 VmaAllocator vmaallocator;
1105 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1106 if (err != VK_SUCCESS) {
1107 qWarning(
"Failed to create allocator: %d", err);
1113 inst->installDebugOutputFilter(qvk_debug_filter);
1115 VkDescriptorPool pool;
1116 VkResult err = createDescriptorPool(&pool);
1117 if (err == VK_SUCCESS)
1118 descriptorPools.append(pool);
1120 qWarning(
"Failed to create initial descriptor pool: %d", err);
1122 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1123 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1124 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1126 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1127 if (err != VK_SUCCESS) {
1128 qWarning(
"Failed to create timestamp query pool: %d", err);
1131 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1132 timestampQueryPoolMap.fill(
false);
1134#ifdef VK_EXT_debug_utils
1135 if (caps.debugUtils) {
1136 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1137 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1138 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1139 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1143#ifdef VK_EXT_device_fault
1144 if (caps.deviceFault) {
1145 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1151 nativeHandlesStruct.physDev = physDev;
1152 nativeHandlesStruct.dev = dev;
1153 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1154 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1155 nativeHandlesStruct.gfxQueue = gfxQueue;
1156 nativeHandlesStruct.vmemAllocator = allocator;
1157 nativeHandlesStruct.inst = inst;
1168 df->vkDeviceWaitIdle(dev);
1175 dxgiHdrInfo =
nullptr;
1179 df->vkDestroyFence(dev, ofr.cmdFence,
nullptr);
1180 ofr.cmdFence = VK_NULL_HANDLE;
1183 if (pipelineCache) {
1184 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1185 pipelineCache = VK_NULL_HANDLE;
1188 for (
const DescriptorPoolData &pool : descriptorPools)
1189 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1191 descriptorPools.clear();
1193 if (timestampQueryPool) {
1194 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1195 timestampQueryPool = VK_NULL_HANDLE;
1199 vmaDestroyAllocator(toVmaAllocator(allocator));
1205 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1206 cmdPool[i] = VK_NULL_HANDLE;
1208 freeSecondaryCbs[i].clear();
1209 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1212 if (!importedDevice && dev) {
1213 df->vkDestroyDevice(dev,
nullptr);
1214 inst->resetDeviceFunctions(dev);
1215 dev = VK_NULL_HANDLE;
1225QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1227 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1228 if (nativeHandles) {
1229 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1230 requestedPhysDev = h->physDev;
1233 QRhi::AdapterList list;
1234 QVulkanFunctions *f = inst->functions();
1235 uint32_t physDevCount = 0;
1236 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1240 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1241 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1242 if (err != VK_SUCCESS || !physDevCount)
1245 VkPhysicalDeviceProperties physDevProperties = {};
1246 for (uint32_t i = 0; i < physDevCount; ++i) {
1247 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1250 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1251 QVulkanAdapter *a =
new QVulkanAdapter;
1252 a->physDev = physDevs[i];
1253 fillDriverInfo(&a->adapterInfo, physDevProperties);
1267 VkDescriptorPoolSize descPoolSizes[] = {
1268 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1269 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1270 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1271 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1272 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1274 VkDescriptorPoolCreateInfo descPoolInfo = {};
1275 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1279 descPoolInfo.flags = 0;
1281 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1282 descPoolInfo.pPoolSizes = descPoolSizes;
1283 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1288 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1289 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1290 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1291 if (r == VK_SUCCESS)
1292 descriptorPools[poolIndex].refCount += 1;
1296 int lastPoolIdx = descriptorPools.size() - 1;
1297 for (
int i = lastPoolIdx; i >= 0; --i) {
1298 if (descriptorPools[i].refCount == 0) {
1299 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1300 descriptorPools[i].allocedDescSets = 0;
1302 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1303 VkResult err = tryAllocate(i);
1304 if (err == VK_SUCCESS) {
1305 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1306 *resultPoolIndex = i;
1312 VkDescriptorPool newPool;
1313 VkResult poolErr = createDescriptorPool(&newPool);
1314 if (poolErr == VK_SUCCESS) {
1315 descriptorPools.append(newPool);
1316 lastPoolIdx = descriptorPools.size() - 1;
1317 VkResult err = tryAllocate(lastPoolIdx);
1318 if (err != VK_SUCCESS) {
1319 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1322 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1323 *resultPoolIndex = lastPoolIdx;
1326 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1333 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1335 case QRhiTexture::RGBA8:
1336 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1337 case QRhiTexture::BGRA8:
1338 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1339 case QRhiTexture::R8:
1340 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1341 case QRhiTexture::RG8:
1342 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1343 case QRhiTexture::R16:
1344 return VK_FORMAT_R16_UNORM;
1345 case QRhiTexture::RG16:
1346 return VK_FORMAT_R16G16_UNORM;
1347 case QRhiTexture::RED_OR_ALPHA8:
1348 return VK_FORMAT_R8_UNORM;
1350 case QRhiTexture::RGBA16F:
1351 return VK_FORMAT_R16G16B16A16_SFLOAT;
1352 case QRhiTexture::RGBA32F:
1353 return VK_FORMAT_R32G32B32A32_SFLOAT;
1354 case QRhiTexture::R16F:
1355 return VK_FORMAT_R16_SFLOAT;
1356 case QRhiTexture::R32F:
1357 return VK_FORMAT_R32_SFLOAT;
1359 case QRhiTexture::RGB10A2:
1361 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1363 case QRhiTexture::R8SI:
1364 return VK_FORMAT_R8_SINT;
1365 case QRhiTexture::R32SI:
1366 return VK_FORMAT_R32_SINT;
1367 case QRhiTexture::RG32SI:
1368 return VK_FORMAT_R32G32_SINT;
1369 case QRhiTexture::RGBA32SI:
1370 return VK_FORMAT_R32G32B32A32_SINT;
1372 case QRhiTexture::R8UI:
1373 return VK_FORMAT_R8_UINT;
1374 case QRhiTexture::R32UI:
1375 return VK_FORMAT_R32_UINT;
1376 case QRhiTexture::RG32UI:
1377 return VK_FORMAT_R32G32_UINT;
1378 case QRhiTexture::RGBA32UI:
1379 return VK_FORMAT_R32G32B32A32_UINT;
1381 case QRhiTexture::D16:
1382 return VK_FORMAT_D16_UNORM;
1383 case QRhiTexture::D24:
1384 return VK_FORMAT_X8_D24_UNORM_PACK32;
1385 case QRhiTexture::D24S8:
1386 return VK_FORMAT_D24_UNORM_S8_UINT;
1387 case QRhiTexture::D32F:
1388 return VK_FORMAT_D32_SFLOAT;
1389 case QRhiTexture::D32FS8:
1390 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1392 case QRhiTexture::BC1:
1393 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1394 case QRhiTexture::BC2:
1395 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1396 case QRhiTexture::BC3:
1397 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1398 case QRhiTexture::BC4:
1399 return VK_FORMAT_BC4_UNORM_BLOCK;
1400 case QRhiTexture::BC5:
1401 return VK_FORMAT_BC5_UNORM_BLOCK;
1402 case QRhiTexture::BC6H:
1403 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1404 case QRhiTexture::BC7:
1405 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1407 case QRhiTexture::ETC2_RGB8:
1408 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1409 case QRhiTexture::ETC2_RGB8A1:
1410 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1411 case QRhiTexture::ETC2_RGBA8:
1412 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1414 case QRhiTexture::ASTC_4x4:
1415 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1416 case QRhiTexture::ASTC_5x4:
1417 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1418 case QRhiTexture::ASTC_5x5:
1419 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1420 case QRhiTexture::ASTC_6x5:
1421 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1422 case QRhiTexture::ASTC_6x6:
1423 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1424 case QRhiTexture::ASTC_8x5:
1425 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1426 case QRhiTexture::ASTC_8x6:
1427 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1428 case QRhiTexture::ASTC_8x8:
1429 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1430 case QRhiTexture::ASTC_10x5:
1431 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1432 case QRhiTexture::ASTC_10x6:
1433 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1434 case QRhiTexture::ASTC_10x8:
1435 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1436 case QRhiTexture::ASTC_10x10:
1437 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1438 case QRhiTexture::ASTC_12x10:
1439 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1440 case QRhiTexture::ASTC_12x12:
1441 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1444 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1451 case VK_FORMAT_R8G8B8A8_UNORM:
1452 return QRhiTexture::RGBA8;
1453 case VK_FORMAT_R8G8B8A8_SRGB:
1455 (*flags) |= QRhiTexture::sRGB;
1456 return QRhiTexture::RGBA8;
1457 case VK_FORMAT_B8G8R8A8_UNORM:
1458 return QRhiTexture::BGRA8;
1459 case VK_FORMAT_B8G8R8A8_SRGB:
1461 (*flags) |= QRhiTexture::sRGB;
1462 return QRhiTexture::BGRA8;
1463 case VK_FORMAT_R16G16B16A16_SFLOAT:
1464 return QRhiTexture::RGBA16F;
1465 case VK_FORMAT_R32G32B32A32_SFLOAT:
1466 return QRhiTexture::RGBA32F;
1467 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1468 return QRhiTexture::RGB10A2;
1470 qWarning(
"VkFormat %d cannot be read back", format);
1473 return QRhiTexture::UnknownFormat;
1479 case QRhiTexture::Format::D16:
1480 case QRhiTexture::Format::D24:
1481 case QRhiTexture::Format::D24S8:
1482 case QRhiTexture::Format::D32F:
1483 case QRhiTexture::Format::D32FS8:
1494 case QRhiTexture::Format::D24S8:
1495 case QRhiTexture::Format::D32FS8:
1505 if (isDepthTextureFormat(format)) {
1506 if (isStencilTextureFormat(format))
1507 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1509 return VK_IMAGE_ASPECT_DEPTH_BIT;
1511 return VK_IMAGE_ASPECT_COLOR_BIT;
1522 VkPhysicalDeviceMemoryProperties physDevMemProps;
1523 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1525 VkMemoryRequirements memReq;
1526 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1527 uint32_t memTypeIndex = uint32_t(-1);
1529 if (memReq.memoryTypeBits) {
1531 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1532 bool foundDevLocal =
false;
1533 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1534 if (memReq.memoryTypeBits & (1 << i)) {
1535 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1536 if (!foundDevLocal) {
1537 foundDevLocal =
true;
1540 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1549 return memTypeIndex;
1553 const QSize &pixelSize,
1554 VkImageUsageFlags usage,
1555 VkImageAspectFlags aspectMask,
1556 VkSampleCountFlagBits samples,
1557 VkDeviceMemory *mem,
1562 VkMemoryRequirements memReq;
1565 for (
int i = 0; i < count; ++i) {
1566 VkImageCreateInfo imgInfo = {};
1567 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1568 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1569 imgInfo.format = format;
1570 imgInfo.extent.width = uint32_t(pixelSize.width());
1571 imgInfo.extent.height = uint32_t(pixelSize.height());
1572 imgInfo.extent.depth = 1;
1573 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1574 imgInfo.samples = samples;
1575 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1576 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1577 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1579 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1580 if (err != VK_SUCCESS) {
1581 qWarning(
"Failed to create image: %d", err);
1588 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1591 VkMemoryAllocateInfo memInfo = {};
1592 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1593 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1595 uint32_t startIndex = 0;
1597 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1598 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1599 qWarning(
"No suitable memory type found");
1602 startIndex = memInfo.memoryTypeIndex + 1;
1603 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1604 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1605 qWarning(
"Failed to allocate image memory: %d", err);
1608 }
while (err != VK_SUCCESS);
1610 VkDeviceSize ofs = 0;
1611 for (
int i = 0; i < count; ++i) {
1612 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1613 if (err != VK_SUCCESS) {
1614 qWarning(
"Failed to bind image memory: %d", err);
1617 ofs += aligned(memReq.size, memReq.alignment);
1619 VkImageViewCreateInfo imgViewInfo = {};
1620 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1621 imgViewInfo.image = images[i];
1622 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1623 imgViewInfo.format = format;
1624 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1625 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1626 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1627 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1628 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1629 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1631 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1632 if (err != VK_SUCCESS) {
1633 qWarning(
"Failed to create image view: %d", err);
1643 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1644 return optimalDsFormat;
1646 const VkFormat dsFormatCandidates[] = {
1647 VK_FORMAT_D24_UNORM_S8_UINT,
1648 VK_FORMAT_D32_SFLOAT_S8_UINT,
1649 VK_FORMAT_D16_UNORM_S8_UINT
1651 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1652 int dsFormatIdx = 0;
1653 while (dsFormatIdx < dsFormatCandidateCount) {
1654 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1655 VkFormatProperties fmtProp;
1656 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1657 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1661 if (dsFormatIdx == dsFormatCandidateCount)
1662 qWarning(
"Failed to find an optimal depth-stencil format");
1664 return optimalDsFormat;
1669 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1671 if (multiViewCount < 2)
1673 if (!multiViewCap) {
1674 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1677#ifdef VK_VERSION_1_1
1678 uint32_t allViewsMask = 0;
1679 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1680 allViewsMask |= (1 << i);
1681 multiViewMask = allViewsMask;
1682 multiViewCorrelationMask = allViewsMask;
1683 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1684 multiViewInfo.subpassCount = 1;
1685 multiViewInfo.pViewMasks = &multiViewMask;
1686 multiViewInfo.correlationMaskCount = 1;
1687 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1688 rpInfo->pNext = &multiViewInfo;
1693#ifdef VK_VERSION_1_1
1700#ifdef VK_KHR_create_renderpass2
1704struct RenderPass2SetupHelper
1706 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1708 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1712 if (multiViewCount >= 2) {
1713 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1714 viewMask |= (1 << i);
1717 attDescs2.resize(rpInfo->attachmentCount);
1718 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1719 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1720 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1722 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1723 att2.flags = att.flags;
1724 att2.format = att.format;
1725 att2.samples = att.samples;
1726 att2.loadOp = att.loadOp;
1727 att2.storeOp = att.storeOp;
1728 att2.stencilLoadOp = att.stencilLoadOp;
1729 att2.stencilStoreOp = att.stencilStoreOp;
1730 att2.initialLayout = att.initialLayout;
1731 att2.finalLayout = att.finalLayout;
1736 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1737 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1738 subpass2.flags = subpassDesc.flags;
1739 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1740 if (multiViewCount >= 2)
1741 subpass2.viewMask = viewMask;
1744 qsizetype startIndex = attRefs2.count();
1745 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1746 attRefs2.append({});
1747 VkAttachmentReference2KHR &attref2(attRefs2.last());
1748 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1749 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1750 attref2.attachment = attref.attachment;
1751 attref2.layout = attref.layout;
1752 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1754 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1755 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1758 if (subpassDesc.pResolveAttachments) {
1759 startIndex = attRefs2.count();
1760 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1761 attRefs2.append({});
1762 VkAttachmentReference2KHR &attref2(attRefs2.last());
1763 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1764 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1765 attref2.attachment = attref.attachment;
1766 attref2.layout = attref.layout;
1767 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1769 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1773 if (subpassDesc.pDepthStencilAttachment) {
1774 startIndex = attRefs2.count();
1775 attRefs2.append({});
1776 VkAttachmentReference2KHR &attref2(attRefs2.last());
1777 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1778 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1779 attref2.attachment = attref.attachment;
1780 attref2.layout = attref.layout;
1781 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1782 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1786#ifdef VK_KHR_depth_stencil_resolve
1788 if (rpD->hasDepthStencilResolve) {
1789 startIndex = attRefs2.count();
1790 attRefs2.append({});
1791 VkAttachmentReference2KHR &attref2(attRefs2.last());
1792 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1793 attref2.attachment = rpD->dsResolveRef.attachment;
1794 attref2.layout = rpD->dsResolveRef.layout;
1795 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1796 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1797 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1798 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1799 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1800 addToChain(&subpass2, &dsResolveDesc);
1804#ifdef VK_KHR_fragment_shading_rate
1805 shadingRateAttInfo = {};
1806 if (rpD->hasShadingRateMap) {
1807 startIndex = attRefs2.count();
1808 attRefs2.append({});
1809 VkAttachmentReference2KHR &attref2(attRefs2.last());
1810 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1811 attref2.attachment = rpD->shadingRateRef.attachment;
1812 attref2.layout = rpD->shadingRateRef.layout;
1813 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1814 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1815 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1816 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1817 addToChain(&subpass2, &shadingRateAttInfo);
1823 subpassDeps2.clear();
1824 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1825 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1826 subpassDeps2.append({});
1827 VkSubpassDependency2 &dep2(subpassDeps2.last());
1828 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1829 dep2.srcSubpass = dep.srcSubpass;
1830 dep2.dstSubpass = dep.dstSubpass;
1831 dep2.srcStageMask = dep.srcStageMask;
1832 dep2.dstStageMask = dep.dstStageMask;
1833 dep2.srcAccessMask = dep.srcAccessMask;
1834 dep2.dstAccessMask = dep.dstAccessMask;
1835 dep2.dependencyFlags = dep.dependencyFlags;
1838 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1839 rpInfo2->pNext =
nullptr;
1840 rpInfo2->flags = rpInfo->flags;
1841 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1842 rpInfo2->pAttachments = attDescs2.constData();
1843 rpInfo2->subpassCount = 1;
1844 rpInfo2->pSubpasses = &subpass2;
1845 rpInfo2->dependencyCount = subpassDeps2.count();
1846 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1847 if (multiViewCount >= 2) {
1848 rpInfo2->correlatedViewMaskCount = 1;
1849 rpInfo2->pCorrelatedViewMasks = &viewMask;
1855 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1856 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1857 VkSubpassDescription2KHR subpass2;
1858 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1859#ifdef VK_KHR_depth_stencil_resolve
1860 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1862#ifdef VK_KHR_fragment_shading_rate
1863 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1870 VkSubpassDescription *subpassDesc,
1873 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1874 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1875 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1876 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1877 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1878 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1880 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1881 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1882 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1883 rpInfo->pAttachments = rpD->attDescs.constData();
1884 rpInfo->subpassCount = 1;
1885 rpInfo->pSubpasses = subpassDesc;
1886 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1887 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1891 bool hasDepthStencil,
1892 VkSampleCountFlagBits samples,
1893 VkFormat colorFormat,
1894 QRhiShadingRateMap *shadingRateMap)
1898 VkAttachmentDescription attDesc = {};
1899 attDesc.format = colorFormat;
1900 attDesc.samples = samples;
1901 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1902 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1903 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1904 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1905 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1906 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1907 rpD->attDescs.append(attDesc);
1909 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1914 rpD->multiViewCount = 0;
1916 if (hasDepthStencil) {
1920 attDesc.format = optimalDepthStencilFormat();
1921 attDesc.samples = samples;
1922 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1923 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1924 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1925 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1926 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1927 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1928 rpD->attDescs.append(attDesc);
1930 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1935 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1937 attDesc.format = colorFormat;
1938 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1939 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1940 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1941 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1942 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1943 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1944 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1945 rpD->attDescs.append(attDesc);
1947 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1950 rpD->dsResolveRef = {};
1952 rpD->shadingRateRef = {};
1953#ifdef VK_KHR_fragment_shading_rate
1954 if (shadingRateMap) {
1956 attDesc.format = VK_FORMAT_R8_UINT;
1957 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1958 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1959 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1960 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1961 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1962 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1963 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1964 rpD->attDescs.append(attDesc);
1966 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
1971 VkSubpassDependency subpassDep = {};
1972 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1973 subpassDep.dstSubpass = 0;
1974 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1975 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1976 subpassDep.srcAccessMask = 0;
1977 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1978 rpD->subpassDeps.append(subpassDep);
1979 if (hasDepthStencil) {
1980 memset(&subpassDep, 0,
sizeof(subpassDep));
1981 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1982 subpassDep.dstSubpass = 0;
1983 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1984 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1985 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1986 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1987 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1988 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
1989 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1990 rpD->subpassDeps.append(subpassDep);
1993 VkRenderPassCreateInfo rpInfo;
1994 VkSubpassDescription subpassDesc;
1995 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
1997#ifdef VK_KHR_create_renderpass2
1998 if (caps.renderPass2KHR) {
2000 VkRenderPassCreateInfo2KHR rpInfo2;
2001 RenderPass2SetupHelper rp2Helper(
this);
2002 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2004 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2005 if (err != VK_SUCCESS) {
2006 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2013 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2014 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2015 if (err != VK_SUCCESS) {
2016 qWarning(
"Failed to create renderpass: %d", err);
2025 const QRhiColorAttachment *colorAttachmentsBegin,
2026 const QRhiColorAttachment *colorAttachmentsEnd,
2030 QRhiRenderBuffer *depthStencilBuffer,
2031 QRhiTexture *depthTexture,
2032 QRhiTexture *depthResolveTexture,
2033 QRhiShadingRateMap *shadingRateMap)
2037 int multiViewCount = 0;
2038 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2041 Q_ASSERT(texD || rbD);
2042 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2043 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2045 VkAttachmentDescription attDesc = {};
2046 attDesc.format = vkformat;
2047 attDesc.samples = samples;
2048 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2049 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2050 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2051 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2053 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2054 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2055 rpD->attDescs.append(attDesc);
2057 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2058 rpD->colorRefs.append(ref);
2060 if (it->multiViewCount() >= 2) {
2061 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2062 qWarning(
"Inconsistent multiViewCount in color attachment set");
2064 multiViewCount = it->multiViewCount();
2065 }
else if (multiViewCount > 0) {
2066 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2069 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2070 rpD->multiViewCount = uint32_t(multiViewCount);
2074 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2075 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2076 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2077 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2078 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2079 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2080 VkAttachmentDescription attDesc = {};
2081 attDesc.format = dsFormat;
2082 attDesc.samples = samples;
2083 attDesc.loadOp = loadOp;
2084 attDesc.storeOp = storeOp;
2085 attDesc.stencilLoadOp = loadOp;
2086 attDesc.stencilStoreOp = storeOp;
2087 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2088 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2089 rpD->attDescs.append(attDesc);
2090 if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
2091 multiViewCount = depthTexture->arraySize();
2092 rpD->multiViewCount = multiViewCount;
2094 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2099 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2100 if (it->resolveTexture()) {
2102 const VkFormat dstFormat = rtexD->vkformat;
2103 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2104 qWarning(
"Resolving into a multisample texture is not supported");
2108 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2109 if (srcFormat != dstFormat) {
2113 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2114 int(srcFormat),
int(dstFormat));
2117 VkAttachmentDescription attDesc = {};
2118 attDesc.format = rtexD->viewFormat;
2119 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2120 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2121 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2122 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2123 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2124 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2125 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2126 rpD->attDescs.append(attDesc);
2128 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2129 rpD->resolveRefs.append(ref);
2131 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2132 rpD->resolveRefs.append(ref);
2135 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2140 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2141 qWarning(
"Resolving into a multisample depth texture is not supported");
2144 if (texD->vkformat != rtexD->vkformat) {
2145 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2146 int(texD->vkformat),
int(rtexD->vkformat));
2149 VkAttachmentDescription attDesc = {};
2150 attDesc.format = rtexD->viewFormat;
2151 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2152 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2153 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2154 attDesc.stencilLoadOp = attDesc.loadOp;
2155 attDesc.stencilStoreOp = attDesc.storeOp;
2156 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2157 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2158 rpD->attDescs.append(attDesc);
2159 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2161 rpD->dsResolveRef = {};
2165 rpD->shadingRateRef = {};
2166#ifdef VK_KHR_fragment_shading_rate
2167 if (shadingRateMap) {
2168 VkAttachmentDescription attDesc = {};
2169 attDesc.format = VK_FORMAT_R8_UINT;
2170 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2171 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2172 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2173 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2174 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2175 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2176 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2177 rpD->attDescs.append(attDesc);
2178 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2183 VkSubpassDependency selfDependency;
2184 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
2185 selfDependency.srcSubpass = 0;
2186 selfDependency.dstSubpass = 0;
2187 selfDependency.srcStageMask = stageMask;
2188 selfDependency.dstStageMask = stageMask;
2189 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2190 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2191#ifdef VK_VERSION_1_1
2192 selfDependency.dependencyFlags = rpD->multiViewCount >= 2 ? VK_DEPENDENCY_VIEW_LOCAL_BIT : 0;
2194 selfDependency.dependencyFlags = 0;
2196 rpD->subpassDeps.append(selfDependency);
2203 VkRenderPassCreateInfo rpInfo;
2204 VkSubpassDescription subpassDesc;
2205 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2208 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2211#ifdef VK_KHR_create_renderpass2
2212 if (caps.renderPass2KHR) {
2214 VkRenderPassCreateInfo2KHR rpInfo2;
2215 RenderPass2SetupHelper rp2Helper(
this);
2216 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2219 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2220 if (err != VK_SUCCESS) {
2221 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2228 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2229 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2232 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2233 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2234 if (err != VK_SUCCESS) {
2235 qWarning(
"Failed to create renderpass: %d", err);
2246 if (swapChainD->pixelSize.isEmpty()) {
2247 qWarning(
"Surface size is 0, cannot create swapchain");
2251 df->vkDeviceWaitIdle(dev);
2253 if (!vkCreateSwapchainKHR) {
2254 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2255 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2256 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2257 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2258 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2259 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2260 qWarning(
"Swapchain functions not available");
2265 VkSurfaceCapabilitiesKHR surfaceCaps;
2266 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2267 quint32 reqBufferCount;
2268 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2269 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2271 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2273 VkSurfaceTransformFlagBitsKHR preTransform =
2274 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2275 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2276 : surfaceCaps.currentTransform;
2302 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2303 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2304 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2305 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2307 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2308 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2309 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2310 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2311 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2312 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2313 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2314 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2315 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2316 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2319 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2320 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2321 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2322 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2324 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2325 && surfaceCaps.maxImageArrayLayers > 1;
2328 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2329 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2333 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2334 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2335 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2336 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2344 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2346 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2347 reuseExisting ?
"recycled" :
"new",
2348 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2350 VkSwapchainCreateInfoKHR swapChainInfo = {};
2351 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2352 swapChainInfo.surface = swapChainD->surface;
2353 swapChainInfo.minImageCount = reqBufferCount;
2354 swapChainInfo.imageFormat = swapChainD->colorFormat;
2355 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2356 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2357 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2358 swapChainInfo.imageUsage = usage;
2359 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2360 swapChainInfo.preTransform = preTransform;
2361 swapChainInfo.compositeAlpha = compositeAlpha;
2362 swapChainInfo.presentMode = presentMode;
2363 swapChainInfo.clipped =
true;
2364 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2366 VkSwapchainKHR newSwapChain;
2367 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2368 if (err != VK_SUCCESS) {
2369 qWarning(
"Failed to create swapchain: %d", err);
2376 swapChainD->sc = newSwapChain;
2377 swapChainD->lastConnectedSurface = swapChainD->surface;
2379 quint32 actualSwapChainBufferCount = 0;
2380 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2381 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2382 qWarning(
"Failed to get swapchain images: %d", err);
2386 if (actualSwapChainBufferCount != reqBufferCount)
2387 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2390 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2391 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2392 if (err != VK_SUCCESS) {
2393 qWarning(
"Failed to get swapchain images: %d", err);
2397 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2398 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2399 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2400 if (!createTransientImage(swapChainD->colorFormat,
2401 swapChainD->pixelSize,
2402 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2403 VK_IMAGE_ASPECT_COLOR_BIT,
2404 swapChainD->samples,
2405 &swapChainD->msaaImageMem,
2408 swapChainD->bufferCount))
2410 qWarning(
"Failed to create transient image for MSAA color buffer");
2415 VkFenceCreateInfo fenceInfo = {};
2416 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2417 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2420 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2424 image.image = swapChainImages[i];
2425 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2426 image.msaaImage = msaaImages[i];
2427 image.msaaImageView = msaaViews[i];
2430 VkImageViewCreateInfo imgViewInfo = {};
2431 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2432 imgViewInfo.image = swapChainImages[i];
2433 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2434 imgViewInfo.format = swapChainD->colorFormat;
2435 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2436 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2437 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2438 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2439 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2440 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2441 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2442 if (err != VK_SUCCESS) {
2443 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2449 VkSemaphoreCreateInfo semInfo = {};
2450 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2451 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2456 image.image = swapChainImages[i];
2457 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2458 image.msaaImage = msaaImages[i];
2459 image.msaaImageView = msaaViews[i];
2462 VkImageViewCreateInfo imgViewInfo = {};
2463 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2464 imgViewInfo.image = swapChainImages[i];
2465 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2466 imgViewInfo.format = swapChainD->colorFormat;
2467 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2468 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2469 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2470 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2471 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2472 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2473 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2474 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2475 if (err != VK_SUCCESS) {
2476 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2480 VkSemaphoreCreateInfo semInfo = {};
2481 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2482 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2488 swapChainD->currentImageIndex = 0;
2490 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2492 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2493 VkImageViewCreateInfo viewInfo = {};
2494 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2495 viewInfo.image = texD->image;
2496 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2497 viewInfo.format = texD->viewFormat;
2498 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2499 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2500 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2501 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2502 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2503 viewInfo.subresourceRange.baseMipLevel = 0;
2504 viewInfo.subresourceRange.levelCount = 1;
2505 viewInfo.subresourceRange.baseArrayLayer = 0;
2506 viewInfo.subresourceRange.layerCount = 1;
2507 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2508 if (err != VK_SUCCESS) {
2509 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2514 VkSemaphoreCreateInfo semInfo = {};
2515 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2523 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2525 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2526 if (err != VK_SUCCESS) {
2527 qWarning(
"Failed to create command buffer fence: %d", err);
2533 swapChainD->currentFrameSlot = 0;
2542 if (swapChainD->sc == VK_NULL_HANDLE)
2546 df->vkDeviceWaitIdle(dev);
2550 if (frame.cmdFence) {
2552 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2553 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2554 frame.cmdFence = VK_NULL_HANDLE;
2557 if (frame.imageSem) {
2558 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2559 frame.imageSem = VK_NULL_HANDLE;
2566 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2567 image.fb = VK_NULL_HANDLE;
2569 if (image.imageView) {
2570 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2571 image.imageView = VK_NULL_HANDLE;
2573 if (image.msaaImageView) {
2574 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2575 image.msaaImageView = VK_NULL_HANDLE;
2577 if (image.msaaImage) {
2578 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2579 image.msaaImage = VK_NULL_HANDLE;
2581 if (image.drawSem) {
2582 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2583 image.drawSem = VK_NULL_HANDLE;
2587 if (swapChainD->msaaImageMem) {
2588 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2589 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2592 if (swapChainD->shadingRateMapView) {
2593 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2594 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2597 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2598 swapChainD->sc = VK_NULL_HANDLE;
2605 VkCommandPoolResetFlags flags = 0;
2610 if (releaseCachedResourcesCalledBeforeFrameStart)
2611 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2614 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2620 for (quint64 i = 0; i < timestampValidBits; i += 8)
2621 mask |= 0xFFULL << i;
2622 const quint64 ts0 = timestamp[0] & mask;
2623 const quint64 ts1 = timestamp[1] & mask;
2624 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2625 if (!qFuzzyIsNull(nsecsPerTick)) {
2626 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2627 const double elapsedSec = elapsedMs / 1000.0;
2638 const int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2641 inst->handle()->beginFrame(swapChainD->window);
2651 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2652 if (waitResult != QRhi::FrameOpSuccess)
2657 uint32_t imageIndex = 0;
2658 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2659 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2661 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2662 swapChainD->currentImageIndex = imageIndex;
2665 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2666 return QRhi::FrameOpSwapChainOutOfDate;
2668 if (err == VK_ERROR_DEVICE_LOST) {
2669 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2670 printExtraErrorInfo(err);
2672 return QRhi::FrameOpDeviceLost;
2674 qWarning(
"Failed to acquire next swapchain image: %d", err);
2675 return QRhi::FrameOpError;
2679 currentFrameSlot =
int(swapChainD->currentFrameSlot);
2682 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2688 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2689 if (cbres != QRhi::FrameOpSuccess)
2692 swapChainD->cbWrapper.cb = frame.cmdBuf;
2695 swapChainD->rtWrapper.d.fb = image.fb;
2699 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2700 swapChainD->rtWrapperRight.d.fb = image.fb;
2707 quint64 timestamp[2] = { 0, 0 };
2708 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2709 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2710 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2711 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2713 if (err == VK_SUCCESS) {
2715 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2717 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2719 qWarning(
"Failed to query timestamp: %d", err);
2724 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2725 int timestampQueryIdx = -1;
2726 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2727 if (!timestampQueryPoolMap.testBit(i)) {
2728 timestampQueryPoolMap.setBit(i);
2729 timestampQueryIdx = i * 2;
2733 if (timestampQueryIdx >= 0) {
2734 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2736 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2737 timestampQueryPool, uint32_t(timestampQueryIdx));
2742 return QRhi::FrameOpSuccess;
2750 auto cleanup = qScopeGuard([
this, swapChainD] {
2751 inst->handle()->endFrame(swapChainD->window);
2756 int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2761 VkImageMemoryBarrier presTrans = {};
2762 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2763 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2764 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2765 presTrans.image = image.image;
2766 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2767 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2771 presTrans.srcAccessMask = 0;
2772 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2773 df->vkCmdPipelineBarrier(frame.cmdBuf,
2774 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2775 0, 0,
nullptr, 0,
nullptr,
2779 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2780 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2781 df->vkCmdPipelineBarrier(frame.cmdBuf,
2782 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2783 0, 0,
nullptr, 0,
nullptr,
2791 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2797 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2798 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2800 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2801 needsPresent ? &image.drawSem :
nullptr);
2802 if (submitres != QRhi::FrameOpSuccess)
2810 VkPresentInfoKHR presInfo = {};
2811 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2812 presInfo.swapchainCount = 1;
2813 presInfo.pSwapchains = &swapChainD->sc;
2814 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2815 waitSemaphoresForPresent.append(image.drawSem);
2816 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2817 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2821 inst->presentAboutToBeQueued(swapChainD->window);
2823 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2824 waitSemaphoresForPresent.clear();
2825 if (err != VK_SUCCESS) {
2826 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2827 return QRhi::FrameOpSwapChainOutOfDate;
2828 }
else if (err != VK_SUBOPTIMAL_KHR) {
2829 if (err == VK_ERROR_DEVICE_LOST) {
2830 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2831 printExtraErrorInfo(err);
2833 return QRhi::FrameOpDeviceLost;
2835 qWarning(
"Failed to present: %d", err);
2836 return QRhi::FrameOpError;
2842 inst->presentQueued(swapChainD->window);
2852 return QRhi::FrameOpSuccess;
2871 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2881 VkCommandBufferAllocateInfo cmdBufInfo = {};
2882 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2883 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2884 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2885 cmdBufInfo.commandBufferCount = 1;
2887 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2888 if (err != VK_SUCCESS) {
2889 if (err == VK_ERROR_DEVICE_LOST) {
2890 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2891 printExtraErrorInfo(err);
2893 return QRhi::FrameOpDeviceLost;
2895 qWarning(
"Failed to allocate frame command buffer: %d", err);
2896 return QRhi::FrameOpError;
2900 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2901 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2903 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2904 if (err != VK_SUCCESS) {
2905 if (err == VK_ERROR_DEVICE_LOST) {
2906 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2907 printExtraErrorInfo(err);
2909 return QRhi::FrameOpDeviceLost;
2911 qWarning(
"Failed to begin frame command buffer: %d", err);
2912 return QRhi::FrameOpError;
2915 return QRhi::FrameOpSuccess;
2919 VkSemaphore *waitSem, VkSemaphore *signalSem)
2921 VkResult err =
df->vkEndCommandBuffer(cb);
2922 if (err != VK_SUCCESS) {
2923 if (err == VK_ERROR_DEVICE_LOST) {
2924 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2925 printExtraErrorInfo(err);
2927 return QRhi::FrameOpDeviceLost;
2929 qWarning(
"Failed to end frame command buffer: %d", err);
2930 return QRhi::FrameOpError;
2933 VkSubmitInfo submitInfo = {};
2934 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2935 submitInfo.commandBufferCount = 1;
2936 submitInfo.pCommandBuffers = &cb;
2939 waitSemaphoresForQueueSubmit.append(*waitSem);
2941 signalSemaphoresForQueueSubmit.append(*signalSem);
2943 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2944 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2945 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2946 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2947 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2949 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
2950 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
2951 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
2954 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
2956 waitSemaphoresForQueueSubmit.clear();
2957 signalSemaphoresForQueueSubmit.clear();
2959 if (err != VK_SUCCESS) {
2960 if (err == VK_ERROR_DEVICE_LOST) {
2961 qWarning(
"Device loss detected in vkQueueSubmit()");
2962 printExtraErrorInfo(err);
2964 return QRhi::FrameOpDeviceLost;
2966 qWarning(
"Failed to submit to graphics queue: %d", err);
2967 return QRhi::FrameOpError;
2970 return QRhi::FrameOpSuccess;
2975 for (QVkSwapChain *sc : std::as_const(swapchains)) {
2976 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
2977 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
2978 if (frame.cmdFenceWaitable) {
2979 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2981 if (err != VK_SUCCESS) {
2982 if (err == VK_ERROR_DEVICE_LOST) {
2983 qWarning(
"Device loss detected in vkWaitForFences()");
2984 printExtraErrorInfo(err);
2986 return QRhi::FrameOpDeviceLost;
2988 qWarning(
"Failed to wait for fence: %d", err);
2989 return QRhi::FrameOpError;
2992 df->vkResetFences(dev, 1, &frame.cmdFence);
2993 frame.cmdFenceWaitable =
false;
2997 return QRhi::FrameOpSuccess;
3011 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3013 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3014 if (waitResult != QRhi::FrameOpSuccess)
3020 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3021 if (cbres != QRhi::FrameOpSuccess)
3027 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3028 int timestampQueryIdx = -1;
3029 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3030 if (!timestampQueryPoolMap.testBit(i)) {
3031 timestampQueryPoolMap.setBit(i);
3032 timestampQueryIdx = i * 2;
3036 if (timestampQueryIdx >= 0) {
3037 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3039 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3040 timestampQueryPool, uint32_t(timestampQueryIdx));
3041 ofr.timestampQueryIndex = timestampQueryIdx;
3046 return QRhi::FrameOpSuccess;
3052 Q_ASSERT(ofr.active);
3059 if (ofr.timestampQueryIndex >= 0) {
3060 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3061 timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
3064 if (!ofr.cmdFence) {
3065 VkFenceCreateInfo fenceInfo = {};
3066 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3067 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence);
3068 if (err != VK_SUCCESS) {
3069 qWarning(
"Failed to create command buffer fence: %d", err);
3070 return QRhi::FrameOpError;
3074 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence,
nullptr,
nullptr);
3075 if (submitres != QRhi::FrameOpSuccess)
3079 df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
3080 df->vkResetFences(dev, 1, &ofr.cmdFence);
3087 if (ofr.timestampQueryIndex >= 0) {
3088 quint64 timestamp[2] = { 0, 0 };
3089 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
3090 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3091 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3092 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
3093 ofr.timestampQueryIndex = -1;
3094 if (err == VK_SUCCESS) {
3096 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3100 qWarning(
"Failed to query timestamp: %d", err);
3104 return QRhi::FrameOpSuccess;
3126 swapChainD->cbWrapper.resetCommands();
3127 cb = swapChainD->cbWrapper.cb;
3129 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3130 if (submitres != QRhi::FrameOpSuccess)
3134 df->vkQueueWaitIdle(gfxQueue);
3141 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3144 startPrimaryCommandBuffer(&frame.cmdBuf);
3145 swapChainD->cbWrapper.cb = frame.cmdBuf;
3152 return QRhi::FrameOpSuccess;
3159 u
.access =
int(bufUsage.access);
3160 u
.stage =
int(bufUsage.stage);
3168 u
.access =
int(texUsage.access);
3169 u
.stage =
int(texUsage.stage);
3175 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3178 rtD->lastActiveFrameSlot = currentFrameSlot;
3179 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3181 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3189 texD->lastActiveFrameSlot = currentFrameSlot;
3194 rbD->lastActiveFrameSlot = currentFrameSlot;
3200 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3203 if (rtD->m_desc.depthStencilBuffer()) {
3205 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3212 rbD->lastActiveFrameSlot = currentFrameSlot;
3214 if (rtD->m_desc.depthTexture()) {
3219 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3221 if (rtD->m_desc.depthResolveTexture()) {
3226 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3228 if (rtD->m_desc.shadingRateMap()) {
3233 texD->lastActiveFrameSlot = currentFrameSlot;
3247 VkCommandBuffer secondaryCb;
3249 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3250 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3251 freeSecondaryCbs[currentFrameSlot].removeLast();
3253 VkCommandBufferAllocateInfo cmdBufInfo = {};
3254 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3255 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3256 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3257 cmdBufInfo.commandBufferCount = 1;
3259 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3260 if (err != VK_SUCCESS) {
3261 qWarning(
"Failed to create secondary command buffer: %d", err);
3262 return VK_NULL_HANDLE;
3266 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3267 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3268 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3269 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3270 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3271 cmdBufInheritInfo.subpass = 0;
3273 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3274 cmdBufInheritInfo.framebuffer = rtD->fb;
3276 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3278 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3279 if (err != VK_SUCCESS) {
3280 qWarning(
"Failed to begin secondary command buffer: %d", err);
3281 return VK_NULL_HANDLE;
3289 VkResult err =
df->vkEndCommandBuffer(cb);
3290 if (err != VK_SUCCESS)
3291 qWarning(
"Failed to end secondary command buffer: %d", err);
3295 cmd.args.executeSecondary.cb = cb;
3299 e.lastActiveFrameSlot = currentFrameSlot;
3300 e.secondaryCommandBuffer.cb = cb;
3301 releaseQueue.append(e);
3305 QRhiRenderTarget *rt,
3306 const QColor &colorClearValue,
3307 const QRhiDepthStencilClearValue &depthStencilClearValue,
3308 QRhiResourceUpdateBatch *resourceUpdates,
3309 QRhiCommandBuffer::BeginPassFlags flags)
3314 if (resourceUpdates)
3324 switch (rt->resourceType()) {
3325 case QRhiResource::SwapChainRenderTarget:
3327 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3337 texD->lastActiveFrameSlot = currentFrameSlot;
3340 case QRhiResource::TextureRenderTarget:
3354 cbD->currentTarget = rt;
3359 VkRenderPassBeginInfo rpBeginInfo = {};
3360 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3361 rpBeginInfo.renderPass = rtD
->rp->rp;
3362 rpBeginInfo.framebuffer = rtD->fb;
3363 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3364 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3366 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3367 [](
const VkAttachmentDescription &attDesc) {
3368 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3369 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3372 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3373 if (rpHasAnyClearOp) {
3376 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3377 colorClearValue.alphaF() } };
3382 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3387 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3388 colorClearValue.alphaF() } };
3393 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3398 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3402 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3403 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3407 cmd.args.beginRenderPass.desc = rpBeginInfo;
3408 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3410 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3413 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3418 rateCmd.args.setShadingRate.w = 1;
3419 rateCmd.args.setShadingRate.h = 1;
3431 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3432 cbD->activeSecondaryCbStack.removeLast();
3433 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3440 cbD->currentTarget =
nullptr;
3442 if (resourceUpdates)
3447 QRhiResourceUpdateBatch *resourceUpdates,
3448 QRhiCommandBuffer::BeginPassFlags flags)
3453 if (resourceUpdates)
3461 cbD->computePassState.reset();
3464 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3475 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3476 cbD->activeSecondaryCbStack.removeLast();
3477 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3482 if (resourceUpdates)
3489 Q_ASSERT(psD->pipeline);
3493 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3495 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3499 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3500 cmd.args.bindPipeline.pipeline = psD->pipeline;
3503 cbD->currentGraphicsPipeline =
nullptr;
3504 cbD->currentComputePipeline = ps;
3505 cbD->currentPipelineGeneration = psD->generation;
3508 psD->lastActiveFrameSlot = currentFrameSlot;
3513 QRhiShaderResourceBinding::Type bindingType,
3514 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3516 VkAccessFlags access = 0;
3517 if (bindingType == loadTypeVal) {
3518 access = VK_ACCESS_SHADER_READ_BIT;
3520 access = VK_ACCESS_SHADER_WRITE_BIT;
3521 if (bindingType == loadStoreTypeVal)
3522 access |= VK_ACCESS_SHADER_READ_BIT;
3524 auto it = writtenResources->find(resource);
3525 if (it != writtenResources->end())
3526 it->first |= access;
3527 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3528 writtenResources->insert(resource, { access,
true });
3538 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3539 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3540 if (cbD->currentComputeSrb) {
3544 for (
auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
3545 accessAndIsNewFlag = { 0,
false };
3548 const int bindingCount = srbD->m_bindings.size();
3549 for (
int i = 0; i < bindingCount; ++i) {
3550 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings.at(i));
3552 case QRhiShaderResourceBinding::ImageLoad:
3553 case QRhiShaderResourceBinding::ImageStore:
3554 case QRhiShaderResourceBinding::ImageLoadStore:
3555 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3558 QRhiShaderResourceBinding::ImageLoad,
3559 QRhiShaderResourceBinding::ImageStore,
3560 QRhiShaderResourceBinding::ImageLoadStore);
3562 case QRhiShaderResourceBinding::BufferLoad:
3563 case QRhiShaderResourceBinding::BufferStore:
3564 case QRhiShaderResourceBinding::BufferLoadStore:
3565 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3568 QRhiShaderResourceBinding::BufferLoad,
3569 QRhiShaderResourceBinding::BufferStore,
3570 QRhiShaderResourceBinding::BufferLoadStore);
3577 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3578 const int accessInThisDispatch = it->first;
3579 const bool isNewInThisDispatch = it->second;
3580 if (accessInThisDispatch && !isNewInThisDispatch) {
3581 if (it.key()->resourceType() == QRhiResource::Texture) {
3583 VkImageMemoryBarrier barrier = {};
3584 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3585 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3587 barrier.subresourceRange.baseMipLevel = 0;
3588 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3589 barrier.subresourceRange.baseArrayLayer = 0;
3590 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3591 barrier.oldLayout = texD->usageState.layout;
3592 barrier.newLayout = texD->usageState.layout;
3593 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3594 barrier.dstAccessMask = accessInThisDispatch;
3595 barrier.image = texD->image;
3596 imageBarriers.append(barrier);
3599 VkBufferMemoryBarrier barrier = {};
3600 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3601 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3602 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3603 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3604 barrier.dstAccessMask = accessInThisDispatch;
3605 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3606 barrier.size = VK_WHOLE_SIZE;
3607 bufferBarriers.append(barrier);
3613 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3614 it = cbD->computePassState.writtenResources.erase(it);
3621 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3622 if (!imageBarriers.isEmpty()) {
3623 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3626 imageBarriers.size(), imageBarriers.constData());
3628 if (!bufferBarriers.isEmpty()) {
3629 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3631 bufferBarriers.size(), bufferBarriers.constData(),
3634 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3636 if (!imageBarriers.isEmpty()) {
3639 cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3640 cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3641 cmd.args.imageBarrier.count = imageBarriers.size();
3642 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3643 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3645 if (!bufferBarriers.isEmpty()) {
3648 cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3649 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3650 cmd.args.bufferBarrier.count = bufferBarriers.size();
3651 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3652 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3656 cmd.args.dispatch.x = x;
3657 cmd.args.dispatch.y = y;
3658 cmd.args.dispatch.z = z;
3664 VkShaderModuleCreateInfo shaderInfo = {};
3665 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3666 shaderInfo.codeSize = size_t(spirv.size());
3667 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3668 VkShaderModule shaderModule;
3669 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3670 if (err != VK_SUCCESS) {
3671 qWarning(
"Failed to create shader module: %d", err);
3672 return VK_NULL_HANDLE;
3674 return shaderModule;
3682 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3683 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3684 pipelineCacheInfo.initialDataSize = initialDataSize;
3685 pipelineCacheInfo.pInitialData = initialData;
3686 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3687 if (err != VK_SUCCESS) {
3688 qWarning(
"Failed to create pipeline cache: %d", err);
3698 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3699 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3700 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3701 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3702 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3704 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3705 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3708 VkWriteDescriptorSet writeInfo = {};
3709 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3710 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3711 writeInfo.dstBinding = uint32_t(b->binding);
3712 writeInfo.descriptorCount = 1;
3714 int bufferInfoIndex = -1;
3715 int imageInfoIndex = -1;
3718 case QRhiShaderResourceBinding::UniformBuffer:
3720 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3721 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3722 QRhiBuffer *buf = b->u.ubuf.buf;
3724 bd.ubuf.id = bufD->m_id;
3725 bd.ubuf.generation = bufD->generation;
3726 VkDescriptorBufferInfo bufInfo;
3727 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3728 bufInfo.offset = b->u.ubuf.offset;
3729 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3731 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3732 bufferInfoIndex = bufferInfos.size();
3733 bufferInfos.append(bufInfo);
3736 case QRhiShaderResourceBinding::SampledTexture:
3738 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3739 writeInfo.descriptorCount = data->count;
3740 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3741 ArrayOfImageDesc imageInfo(data->count);
3742 for (
int elem = 0; elem < data->count; ++elem) {
3745 bd.stex.d[elem].texId = texD->m_id;
3746 bd.stex.d[elem].texGeneration = texD->generation;
3747 bd.stex.d[elem].samplerId = samplerD->m_id;
3748 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3749 imageInfo[elem].sampler = samplerD->sampler;
3750 imageInfo[elem].imageView = texD->imageView;
3751 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3753 bd.stex.count = data->count;
3754 imageInfoIndex = imageInfos.size();
3755 imageInfos.append(imageInfo);
3758 case QRhiShaderResourceBinding::Texture:
3760 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3761 writeInfo.descriptorCount = data->count;
3762 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3763 ArrayOfImageDesc imageInfo(data->count);
3764 for (
int elem = 0; elem < data->count; ++elem) {
3766 bd.stex.d[elem].texId = texD->m_id;
3767 bd.stex.d[elem].texGeneration = texD->generation;
3768 bd.stex.d[elem].samplerId = 0;
3769 bd.stex.d[elem].samplerGeneration = 0;
3770 imageInfo[elem].sampler = VK_NULL_HANDLE;
3771 imageInfo[elem].imageView = texD->imageView;
3772 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3774 bd.stex.count = data->count;
3775 imageInfoIndex = imageInfos.size();
3776 imageInfos.append(imageInfo);
3779 case QRhiShaderResourceBinding::Sampler:
3782 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3783 bd.stex.d[0].texId = 0;
3784 bd.stex.d[0].texGeneration = 0;
3785 bd.stex.d[0].samplerId = samplerD->m_id;
3786 bd.stex.d[0].samplerGeneration = samplerD->generation;
3787 ArrayOfImageDesc imageInfo(1);
3788 imageInfo[0].sampler = samplerD->sampler;
3789 imageInfo[0].imageView = VK_NULL_HANDLE;
3790 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3791 imageInfoIndex = imageInfos.size();
3792 imageInfos.append(imageInfo);
3795 case QRhiShaderResourceBinding::ImageLoad:
3796 case QRhiShaderResourceBinding::ImageStore:
3797 case QRhiShaderResourceBinding::ImageLoadStore:
3800 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3802 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3803 bd.simage.id = texD->m_id;
3804 bd.simage.generation = texD->generation;
3805 ArrayOfImageDesc imageInfo(1);
3806 imageInfo[0].sampler = VK_NULL_HANDLE;
3807 imageInfo[0].imageView = view;
3808 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3809 imageInfoIndex = imageInfos.size();
3810 imageInfos.append(imageInfo);
3814 case QRhiShaderResourceBinding::BufferLoad:
3815 case QRhiShaderResourceBinding::BufferStore:
3816 case QRhiShaderResourceBinding::BufferLoadStore:
3819 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3820 bd.sbuf.id = bufD->m_id;
3821 bd.sbuf.generation = bufD->generation;
3822 VkDescriptorBufferInfo bufInfo;
3823 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3824 bufInfo.offset = b->u.sbuf.offset;
3825 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3826 bufferInfoIndex = bufferInfos.size();
3827 bufferInfos.append(bufInfo);
3834 writeInfos.append(writeInfo);
3835 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3838 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3839 const int bufferInfoIndex = infoIndices[i].first;
3840 const int imageInfoIndex = infoIndices[i].second;
3841 if (bufferInfoIndex >= 0)
3842 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3843 else if (imageInfoIndex >= 0)
3844 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3847 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3852 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3853 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3854 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3855 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3856 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3857 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3861 VkAccessFlags access, VkPipelineStageFlags stage)
3864 Q_ASSERT(access && stage);
3872 if (s.access == access && s.stage == stage) {
3875 if (!accessIsWrite(access))
3879 VkBufferMemoryBarrier bufMemBarrier = {};
3880 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3881 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3882 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3883 bufMemBarrier.srcAccessMask = s.access;
3884 bufMemBarrier.dstAccessMask = access;
3885 bufMemBarrier.buffer = bufD->buffers[slot];
3886 bufMemBarrier.size = VK_WHOLE_SIZE;
3890 cmd.args.bufferBarrier.srcStageMask = s.stage;
3891 cmd.args.bufferBarrier.dstStageMask = stage;
3892 cmd.args.bufferBarrier.count = 1;
3893 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3894 cbD->pools.bufferBarrier.append(bufMemBarrier);
3901 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3904 Q_ASSERT(layout && access && stage);
3906 if (s.access == access && s.stage == stage && s.layout == layout) {
3907 if (!accessIsWrite(access))
3911 VkImageMemoryBarrier barrier = {};
3912 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3913 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3914 barrier.subresourceRange.baseMipLevel = 0;
3915 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3916 barrier.subresourceRange.baseArrayLayer = 0;
3917 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3918 barrier.oldLayout = s.layout;
3919 barrier.newLayout = layout;
3920 barrier.srcAccessMask = s.access;
3921 barrier.dstAccessMask = access;
3922 barrier.image = texD->image;
3924 VkPipelineStageFlags srcStage = s.stage;
3927 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3931 cmd.args.imageBarrier.srcStageMask = srcStage;
3932 cmd.args.imageBarrier.dstStageMask = stage;
3933 cmd.args.imageBarrier.count = 1;
3934 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3935 cbD->pools.imageBarrier.append(barrier);
3946 VkImageMemoryBarrier barrier = {};
3947 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3948 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
3949 barrier.subresourceRange.baseMipLevel = 0;
3950 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3951 barrier.subresourceRange.baseArrayLayer = 0;
3952 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3953 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3954 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
3955 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3956 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
3957 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3958 barrier.image = rbD->image;
3960 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
3961 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
3965 cmd.args.imageBarrier.srcStageMask = stages;
3966 cmd.args.imageBarrier.dstStageMask = stages;
3967 cmd.args.imageBarrier.count = 1;
3968 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3969 cbD->pools.imageBarrier.append(barrier);
3973 VkImageLayout oldLayout, VkImageLayout newLayout,
3974 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
3975 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
3976 int startLayer,
int layerCount,
3977 int startLevel,
int levelCount)
3980 VkImageMemoryBarrier barrier = {};
3981 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3982 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3983 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
3984 barrier.subresourceRange.levelCount = uint32_t(levelCount);
3985 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
3986 barrier.subresourceRange.layerCount = uint32_t(layerCount);
3987 barrier.oldLayout = oldLayout;
3988 barrier.newLayout = newLayout;
3989 barrier.srcAccessMask = srcAccess;
3990 barrier.dstAccessMask = dstAccess;
3991 barrier.image = image;
3995 cmd.args.imageBarrier.srcStageMask = srcStage;
3996 cmd.args.imageBarrier.dstStageMask = dstStage;
3997 cmd.args.imageBarrier.count = 1;
3998 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3999 cbD->pools.imageBarrier.append(barrier);
4004 VkDeviceSize size = 0;
4005 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4006 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4007 if (imageSizeBytes > 0)
4008 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4013 const QRhiTextureSubresourceUploadDescription &subresDesc,
4014 size_t *curOfs,
void *mp,
4015 BufferImageCopyList *copyInfos)
4017 qsizetype copySizeBytes = 0;
4018 qsizetype imageSizeBytes = 0;
4019 const void *src =
nullptr;
4020 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4021 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4023 VkBufferImageCopy copyInfo = {};
4024 copyInfo.bufferOffset = *curOfs;
4025 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4026 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4027 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4028 copyInfo.imageSubresource.layerCount = 1;
4029 copyInfo.imageExtent.depth = 1;
4031 copyInfo.imageOffset.z = uint32_t(layer);
4033 copyInfo.imageOffset.y = uint32_t(layer);
4035 const QByteArray rawData = subresDesc.data();
4036 const QPoint dp = subresDesc.destinationTopLeft();
4037 QImage image = subresDesc.image();
4038 if (!image.isNull()) {
4039 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4040 QSize size = image.size();
4041 src = image.constBits();
4044 int bpc = qMax(1, image.depth() / 8);
4046 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4047 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4048 const int sx = subresDesc.sourceTopLeft().x();
4049 const int sy = subresDesc.sourceTopLeft().y();
4050 if (!subresDesc.sourceSize().isEmpty())
4051 size = subresDesc.sourceSize();
4052 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4053 if (size.width() == image.width()) {
4056 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4057 copySizeBytes = size.height() * image.bytesPerLine();
4059 image = image.copy(sx, sy, size.width(), size.height());
4060 src = image.constBits();
4063 copySizeBytes = image.sizeInBytes();
4064 bpc = qMax(1, image.depth() / 8);
4065 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4068 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4070 copyInfo.imageOffset.x = dp.x();
4071 copyInfo.imageOffset.y = dp.y();
4072 copyInfo.imageExtent.width = uint32_t(size.width());
4073 copyInfo.imageExtent.height = uint32_t(size.height());
4074 copyInfos->append(copyInfo);
4075 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4076 copySizeBytes = imageSizeBytes = rawData.size();
4077 src = rawData.constData();
4078 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4079 const int subresw = size.width();
4080 const int subresh = size.height();
4081 if (!subresDesc.sourceSize().isEmpty())
4082 size = subresDesc.sourceSize();
4083 const int w = size.width();
4084 const int h = size.height();
4086 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4088 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4089 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4092 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4093 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4094 copyInfos->append(copyInfo);
4095 }
else if (!rawData.isEmpty()) {
4096 copySizeBytes = imageSizeBytes = rawData.size();
4097 src = rawData.constData();
4098 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4099 if (subresDesc.dataStride()) {
4100 quint32 bytesPerPixel = 0;
4101 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4103 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4105 if (!subresDesc.sourceSize().isEmpty())
4106 size = subresDesc.sourceSize();
4107 copyInfo.imageOffset.x = dp.x();
4108 copyInfo.imageOffset.y = dp.y();
4109 copyInfo.imageExtent.width = uint32_t(size.width());
4110 copyInfo.imageExtent.height = uint32_t(size.height());
4111 copyInfos->append(copyInfo);
4113 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4117 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4118 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4124 if (err == VK_ERROR_DEVICE_LOST)
4126 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4127 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4132#ifdef VK_EXT_device_fault
4133 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4136 VkDeviceFaultCountsEXT faultCounts{};
4137 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4138 faultCounts.pNext =
nullptr;
4140 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4141 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4142 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4145 faultCounts.vendorBinarySize = 0;
4147 QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
4148 addressInfos.resize(faultCounts.addressInfoCount);
4150 QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
4151 vendorInfos.resize(faultCounts.vendorInfoCount);
4153 VkDeviceFaultInfoEXT info{};
4154 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4155 info.pNext =
nullptr;
4156 info.pAddressInfos = addressInfos.isEmpty() ?
nullptr : addressInfos.data();
4157 info.pVendorInfos = vendorInfos.isEmpty() ?
nullptr : vendorInfos.data();
4158 info.pVendorBinaryData =
nullptr;
4160 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4161 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4162 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4166 const char *desc = info.description[0] ? info.description :
"n/a";
4167 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4168 faultCounts.addressInfoCount,
4169 faultCounts.vendorInfoCount,
4170 (
unsigned long long)faultCounts.vendorBinarySize,
4173 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4174 const auto &a = addressInfos[i];
4175 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4177 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4178 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4179 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4180 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4181 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4182 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4183 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4184 default:
return "UNKNOWN";
4187 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4189 addressTypeString(a.addressType),
4190 (
unsigned long long)a.reportedAddress,
4191 (
unsigned long long)a.addressPrecision);
4194 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4195 const auto &v = vendorInfos[i];
4196 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4198 (
unsigned long long)v.vendorFaultCode,
4199 (
unsigned long long)v.vendorFaultData,
4213 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4215 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4216 bufD->pendingDynamicUpdates[i].clear();
4217 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4221 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4222 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4224 if (!bufD->stagingBuffers[currentFrameSlot]) {
4225 VkBufferCreateInfo bufferInfo = {};
4226 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4229 bufferInfo.size = bufD->m_size;
4230 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4232 VmaAllocationCreateInfo allocInfo = {};
4233 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4235 VmaAllocation allocation;
4236 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4237 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4238 if (err == VK_SUCCESS) {
4239 bufD->stagingAllocations[currentFrameSlot] = allocation;
4240 setAllocationName(allocation, bufD->name());
4242 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4243 printExtraErrorInfo(err);
4248 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4249 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4250 u.offset, u
.data.size());
4251 if (err != VK_SUCCESS) {
4252 qWarning(
"Failed to copy memory to buffer: %d", err);
4256 trackedBufferBarrier(cbD, bufD, 0,
4257 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4259 VkBufferCopy copyInfo = {};
4260 copyInfo.srcOffset = u.offset;
4261 copyInfo.dstOffset = u.offset;
4262 copyInfo.size = u
.data.size();
4266 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4267 cmd.args.copyBuffer.dst = bufD->buffers[0];
4268 cmd.args.copyBuffer.desc = copyInfo;
4277 bufD->lastActiveFrameSlot = currentFrameSlot;
4279 if (bufD->m_type == QRhiBuffer::Immutable) {
4282 e.lastActiveFrameSlot = currentFrameSlot;
4283 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4284 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4285 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4286 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4287 releaseQueue.append(e);
4291 if (bufD->m_type == QRhiBuffer::Dynamic) {
4293 u.result->data.resizeForOverwrite(u.readSize);
4294 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4295 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4296 u.offset, u.result->data.data(), u.readSize);
4297 if (err != VK_SUCCESS) {
4298 qWarning(
"Failed to copy memory from buffer: %d", err);
4299 u.result->data.clear();
4301 if (u.result->completed)
4302 u.result->completed();
4311 readback.activeFrameSlot = currentFrameSlot;
4312 readback.result = u.result;
4313 readback.byteSize = u.readSize;
4315 VkBufferCreateInfo bufferInfo = {};
4316 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4317 bufferInfo.size = readback.byteSize;
4318 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4320 VmaAllocationCreateInfo allocInfo = {};
4321 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4323 VmaAllocation allocation;
4324 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4325 if (err == VK_SUCCESS) {
4327 setAllocationName(allocation, bufD->name());
4329 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4330 printExtraErrorInfo(err);
4334 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4336 VkBufferCopy copyInfo = {};
4337 copyInfo.srcOffset = u.offset;
4338 copyInfo.size = u.readSize;
4342 cmd.args.copyBuffer.src = bufD->buffers[0];
4343 cmd.args.copyBuffer.dst = readback.stagingBuf;
4344 cmd.args.copyBuffer.desc = copyInfo;
4346 bufD->lastActiveFrameSlot = currentFrameSlot;
4348 activeBufferReadbacks.append(readback);
4358 VkDeviceSize stagingSize = 0;
4359 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4360 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4361 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4362 stagingSize += subresUploadByteSize(subresDesc);
4366 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4367 VkBufferCreateInfo bufferInfo = {};
4368 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4369 bufferInfo.size = stagingSize;
4370 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4372 VmaAllocationCreateInfo allocInfo = {};
4373 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4375 VmaAllocation allocation;
4376 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4377 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4378 if (err != VK_SUCCESS) {
4379 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4380 printExtraErrorInfo(err);
4383 utexD->stagingAllocations[currentFrameSlot] = allocation;
4384 setAllocationName(allocation, utexD->name());
4386 BufferImageCopyList copyInfos;
4389 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4390 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4391 if (err != VK_SUCCESS) {
4392 qWarning(
"Failed to map image data: %d", err);
4396 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4397 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4398 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4401 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4402 prepareUploadSubres(utexD, layer, level,
4403 subresDesc, &curOfs, mp, ©Infos);
4407 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4408 vmaUnmapMemory(toVmaAllocator(allocator), a);
4410 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4411 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4415 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4416 cmd.args.copyBufferToImage.dst = utexD->image;
4417 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4418 cmd.args.copyBufferToImage.count = copyInfos.size();
4419 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4420 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4425 e.lastActiveFrameSlot = currentFrameSlot;
4426 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4427 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4428 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4429 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4430 releaseQueue.append(e);
4435 utexD->lastActiveFrameSlot = currentFrameSlot;
4439 qWarning(
"Texture copy with matching source and destination is not supported");
4444 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4445 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4447 VkImageCopy region = {};
4448 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4449 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4450 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4451 region.srcSubresource.layerCount = 1;
4453 region.srcOffset.x = u.desc.sourceTopLeft().x();
4454 region.srcOffset.y = u.desc.sourceTopLeft().y();
4456 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4458 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4459 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4460 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4461 region.dstSubresource.layerCount = 1;
4463 region.dstOffset.x = u.desc.destinationTopLeft().x();
4464 region.dstOffset.y = u.desc.destinationTopLeft().y();
4466 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4468 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4469 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4470 region.extent.width = uint32_t(copySize.width());
4471 region.extent.height = uint32_t(copySize.height());
4472 region.extent.depth = 1;
4474 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4475 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4476 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4477 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4481 cmd.args.copyImage.src = srcD->image;
4482 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4483 cmd.args.copyImage.dst = dstD->image;
4484 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4485 cmd.args.copyImage.desc = region;
4487 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4490 readback.activeFrameSlot = currentFrameSlot;
4491 readback.desc = u.rb;
4492 readback.result = u.result;
4498 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4499 qWarning(
"Multisample texture cannot be read back");
4502 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4503 if (u.rb.rect().isValid())
4504 readback.rect = u.rb.rect();
4506 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4507 readback.format = texD->m_format;
4508 texD->lastActiveFrameSlot = currentFrameSlot;
4513 qWarning(
"Swapchain does not support readback");
4516 if (u.rb.rect().isValid())
4517 readback.rect = u.rb.rect();
4519 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4520 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4521 if (readback.format == QRhiTexture::UnknownFormat)
4527 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4530 VkBufferCreateInfo bufferInfo = {};
4531 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4532 bufferInfo.size = readback.byteSize;
4533 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4535 VmaAllocationCreateInfo allocInfo = {};
4536 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4538 VmaAllocation allocation;
4539 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4540 if (err == VK_SUCCESS) {
4542 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4544 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4545 printExtraErrorInfo(err);
4550 VkBufferImageCopy copyDesc = {};
4551 copyDesc.bufferOffset = 0;
4552 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4553 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4554 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4555 copyDesc.imageSubresource.layerCount = 1;
4556 copyDesc.imageOffset.x = readback.rect.x();
4557 copyDesc.imageOffset.y = readback.rect.y();
4559 copyDesc.imageOffset.z = u.rb.layer();
4560 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4561 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4562 copyDesc.imageExtent.depth = 1;
4565 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4566 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4569 cmd.args.copyImageToBuffer.src = texD->image;
4570 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4571 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4572 cmd.args.copyImageToBuffer.desc = copyDesc;
4576 VkImage image = imageRes.image;
4579 qWarning(
"Attempted to read back undefined swapchain image content, "
4580 "results are undefined. (do a render pass first)");
4582 subresourceBarrier(cbD, image,
4583 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4584 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4585 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4593 cmd.args.copyImageToBuffer.src = image;
4594 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4595 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4596 cmd.args.copyImageToBuffer.desc = copyDesc;
4599 activeTextureReadbacks.append(readback);
4602 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4603 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4604 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4605 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4607 VkImageLayout origLayout = utexD->usageState.layout;
4608 VkAccessFlags origAccess = utexD->usageState.access;
4609 VkPipelineStageFlags origStage = utexD->usageState.stage;
4611 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4613 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4614 int w = utexD->m_pixelSize.width();
4615 int h = utexD->m_pixelSize.height();
4616 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4617 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4619 subresourceBarrier(cbD, utexD->image,
4620 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4621 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4622 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4626 subresourceBarrier(cbD, utexD->image,
4627 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4628 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4629 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4634 subresourceBarrier(cbD, utexD->image,
4635 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4636 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4637 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4641 VkImageBlit region = {};
4642 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4643 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4644 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4645 region.srcSubresource.layerCount = 1;
4647 region.srcOffsets[1].x = qMax(1, w);
4648 region.srcOffsets[1].y = qMax(1, h);
4649 region.srcOffsets[1].z = qMax(1, depth);
4651 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4652 region.dstSubresource.mipLevel = uint32_t(level);
4653 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4654 region.dstSubresource.layerCount = 1;
4656 region.dstOffsets[1].x = qMax(1, w >> 1);
4657 region.dstOffsets[1].y = qMax(1, h >> 1);
4658 region.dstOffsets[1].z = qMax(1, depth >> 1);
4662 cmd.args.blitImage.src = utexD->image;
4663 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4664 cmd.args.blitImage.dst = utexD->image;
4665 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4666 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4667 cmd.args.blitImage.desc = region;
4674 if (utexD->mipLevelCount > 1) {
4675 subresourceBarrier(cbD, utexD->image,
4676 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4677 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4678 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4680 0,
int(utexD->mipLevelCount) - 1);
4681 subresourceBarrier(cbD, utexD->image,
4682 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4683 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4684 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4686 int(utexD->mipLevelCount) - 1, 1);
4689 utexD->lastActiveFrameSlot = currentFrameSlot;
4698 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4701 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4703 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4707 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4708 if (err != VK_SUCCESS) {
4709 qWarning(
"Failed to map buffer: %d", err);
4712 quint32 changeBegin = UINT32_MAX;
4713 quint32 changeEnd = 0;
4714 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4715 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4716 if (u.offset < changeBegin)
4717 changeBegin = u.offset;
4718 if (u.offset + u.data.size() > changeEnd)
4719 changeEnd = u.offset + u.data.size();
4721 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4722 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4723 vmaUnmapMemory(toVmaAllocator(allocator), a);
4725 bufD->pendingDynamicUpdates[slot].clear();
4731 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4732 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4738 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4739 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4740 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4745 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4746 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4748 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4749 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4750 if (e.texture.extraImageViews[i])
4751 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4757 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4762 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4764 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4767 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4768 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4771 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4772 if (e.shaderResourceBindings.poolIndex >= 0) {
4773 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4774 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4781 qrhivk_releaseRenderBuffer(e, dev,
df);
4787 qrhivk_releaseSampler(e, dev,
df);
4790 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4792 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4793 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4795 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4796 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4797 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4800 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4803 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4805 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4806 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4812 releaseQueue.removeAt(i);
4819 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4821 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4823 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4824 readback.result->format = readback.format;
4825 readback.result->pixelSize = readback.rect.size();
4826 readback.result->data.resizeForOverwrite(readback.byteSize);
4827 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4828 toVmaAllocation(readback.stagingAlloc),
4829 0, readback.result->data.data(), readback.byteSize);
4830 if (err != VK_SUCCESS) {
4831 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4832 readback.result->data.clear();
4835 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4837 if (readback.result->completed)
4838 completedCallbacks.append(readback.result->completed);
4840 activeTextureReadbacks.remove(i);
4844 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4846 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4847 readback.result->data.resizeForOverwrite(readback.byteSize);
4848 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4849 toVmaAllocation(readback.stagingAlloc),
4850 0, readback.result->data.data(), readback.byteSize);
4851 if (err != VK_SUCCESS) {
4852 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4853 readback.result->data.clear();
4856 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4858 if (readback.result->completed)
4859 completedCallbacks.append(readback.result->completed);
4861 activeBufferReadbacks.remove(i);
4865 for (
auto f : completedCallbacks)
4872} qvk_sampleCounts[] = {
4874 { VK_SAMPLE_COUNT_1_BIT, 1 },
4875 { VK_SAMPLE_COUNT_2_BIT, 2 },
4876 { VK_SAMPLE_COUNT_4_BIT, 4 },
4877 { VK_SAMPLE_COUNT_8_BIT, 8 },
4878 { VK_SAMPLE_COUNT_16_BIT, 16 },
4879 { VK_SAMPLE_COUNT_32_BIT, 32 },
4880 { VK_SAMPLE_COUNT_64_BIT, 64 }
4885 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4886 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4887 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4888 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4891 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4892 if ((color & qvk_sampleCount.mask)
4893 && (depth & qvk_sampleCount.mask)
4894 && (stencil & qvk_sampleCount.mask))
4896 result.append(qvk_sampleCount.count);
4905 const int s = effectiveSampleCount(sampleCount);
4907 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4908 if (qvk_sampleCount.count == s)
4909 return qvk_sampleCount.mask;
4912 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4917 QList<QSize> result;
4918#ifdef VK_KHR_fragment_shading_rate
4919 sampleCount = qMax(1, sampleCount);
4920 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4921 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4922 if (qvk_sampleCount.count == sampleCount) {
4923 mask = qvk_sampleCount.mask;
4927 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4928 if (s.sampleCounts & mask)
4929 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4932 Q_UNUSED(sampleCount);
4933 result.append(QSize(1, 1));
4940 cbD->passResTrackers.emplace_back();
4945 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
4952 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
4956 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
4957 1, &cmd.args.copyBuffer.desc);
4960 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
4961 cmd.args.copyBufferToImage.dstLayout,
4962 uint32_t(cmd.args.copyBufferToImage.count),
4963 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
4966 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
4967 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
4968 1, &cmd.args.copyImage.desc);
4971 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
4972 cmd.args.copyImageToBuffer.dst,
4973 1, &cmd.args.copyImageToBuffer.desc);
4976 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
4977 0, 0,
nullptr, 0,
nullptr,
4978 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
4981 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
4983 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
4987 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
4988 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
4989 1, &cmd.args.blitImage.desc,
4990 cmd.args.blitImage.filter);
4993 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
4994 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
4995 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
4996 : VK_SUBPASS_CONTENTS_INLINE);
4999 VkMemoryBarrier barrier;
5000 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5001 barrier.pNext =
nullptr;
5002 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5003 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5004 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5010 df->vkCmdEndRenderPass(cbD->cb);
5013 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5017 const uint32_t *offsets =
nullptr;
5018 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5019 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5020 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5021 cmd.args.bindDescriptorSet.pipelineLayout,
5022 0, 1, &cmd.args.bindDescriptorSet.descSet,
5023 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5028 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5029 uint32_t(cmd.args.bindVertexBuffer.count),
5030 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5031 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5034 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5035 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5038 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5041 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5044 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5047 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5050 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5051 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5054 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5055 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5056 cmd.args.drawIndexed.firstInstance);
5059#ifdef VK_EXT_debug_utils
5060 cmd.args.debugMarkerBegin.label.pLabelName =
5061 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5062 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5066#ifdef VK_EXT_debug_utils
5067 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5071#ifdef VK_EXT_debug_utils
5072 cmd.args.debugMarkerInsert.label.pLabelName =
5073 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5074 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5081 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5084 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5088#ifdef VK_KHR_fragment_shading_rate
5089 VkFragmentShadingRateCombinerOpKHR op[2] = {
5090 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5091 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5093 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5094 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5107 case QRhiPassResourceTracker::BufVertexInput:
5108 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5109 case QRhiPassResourceTracker::BufIndexRead:
5110 return VK_ACCESS_INDEX_READ_BIT;
5111 case QRhiPassResourceTracker::BufUniformRead:
5112 return VK_ACCESS_UNIFORM_READ_BIT;
5113 case QRhiPassResourceTracker::BufStorageLoad:
5114 return VK_ACCESS_SHADER_READ_BIT;
5115 case QRhiPassResourceTracker::BufStorageStore:
5116 return VK_ACCESS_SHADER_WRITE_BIT;
5117 case QRhiPassResourceTracker::BufStorageLoadStore:
5118 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5129 case QRhiPassResourceTracker::BufVertexInputStage:
5130 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5131 case QRhiPassResourceTracker::BufVertexStage:
5132 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5133 case QRhiPassResourceTracker::BufTCStage:
5134 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5135 case QRhiPassResourceTracker::BufTEStage:
5136 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5137 case QRhiPassResourceTracker::BufFragmentStage:
5138 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5139 case QRhiPassResourceTracker::BufComputeStage:
5140 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5141 case QRhiPassResourceTracker::BufGeometryStage:
5142 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5153 u.access = VkAccessFlags(usage
.access);
5154 u.stage = VkPipelineStageFlags(usage
.stage);
5161 case QRhiPassResourceTracker::TexSample:
5162 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5163 case QRhiPassResourceTracker::TexColorOutput:
5164 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5165 case QRhiPassResourceTracker::TexDepthOutput:
5166 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5167 case QRhiPassResourceTracker::TexStorageLoad:
5168 case QRhiPassResourceTracker::TexStorageStore:
5169 case QRhiPassResourceTracker::TexStorageLoadStore:
5170 return VK_IMAGE_LAYOUT_GENERAL;
5171 case QRhiPassResourceTracker::TexShadingRate:
5172#ifdef VK_KHR_fragment_shading_rate
5173 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5175 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5181 return VK_IMAGE_LAYOUT_GENERAL;
5187 case QRhiPassResourceTracker::TexSample:
5188 return VK_ACCESS_SHADER_READ_BIT;
5189 case QRhiPassResourceTracker::TexColorOutput:
5190 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5191 case QRhiPassResourceTracker::TexDepthOutput:
5192 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5193 case QRhiPassResourceTracker::TexStorageLoad:
5194 return VK_ACCESS_SHADER_READ_BIT;
5195 case QRhiPassResourceTracker::TexStorageStore:
5196 return VK_ACCESS_SHADER_WRITE_BIT;
5197 case QRhiPassResourceTracker::TexStorageLoadStore:
5198 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5211 case QRhiPassResourceTracker::TexVertexStage:
5212 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5213 case QRhiPassResourceTracker::TexTCStage:
5214 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5215 case QRhiPassResourceTracker::TexTEStage:
5216 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5217 case QRhiPassResourceTracker::TexFragmentStage:
5218 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5219 case QRhiPassResourceTracker::TexColorOutputStage:
5220 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5221 case QRhiPassResourceTracker::TexDepthOutputStage:
5222 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5223 case QRhiPassResourceTracker::TexComputeStage:
5224 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5225 case QRhiPassResourceTracker::TexGeometryStage:
5226 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5237 u.layout = VkImageLayout(usage
.layout);
5238 u.access = VkAccessFlags(usage
.access);
5239 u.stage = VkPipelineStageFlags(usage
.stage);
5250 const VkAccessFlags newAccess = toVkAccess(access);
5251 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5252 if (u.access == newAccess && u.stage == newStage) {
5253 if (!accessIsWrite(access))
5257 u.access = newAccess;
5267 const VkAccessFlags newAccess = toVkAccess(access);
5268 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5269 const VkImageLayout newLayout = toVkLayout(access);
5270 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5271 if (!accessIsWrite(access))
5275 u.layout = newLayout;
5276 u.access = newAccess;
5285 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5286 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5287 VkAccessFlags access = toVkAccess(trackedB.access);
5288 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5289 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5292 if (s.access == access && s.stage == stage) {
5293 if (!accessIsWrite(access))
5296 VkBufferMemoryBarrier bufMemBarrier = {};
5297 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5298 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5299 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5300 bufMemBarrier.srcAccessMask = s.access;
5301 bufMemBarrier.dstAccessMask = access;
5302 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5303 bufMemBarrier.size = VK_WHOLE_SIZE;
5304 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5310 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5311 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5312 VkImageLayout layout = toVkLayout(trackedT.access);
5313 VkAccessFlags access = toVkAccess(trackedT.access);
5314 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5315 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5316 if (s.access == access && s.stage == stage && s.layout == layout) {
5317 if (!accessIsWrite(access))
5320 VkImageMemoryBarrier barrier = {};
5321 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5322 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5323 barrier.subresourceRange.baseMipLevel = 0;
5324 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5325 barrier.subresourceRange.baseArrayLayer = 0;
5326 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5327 barrier.oldLayout = s.layout;
5328 barrier.newLayout = layout;
5329 barrier.srcAccessMask = s.access;
5330 barrier.dstAccessMask = access;
5331 barrier.image = texD->image;
5332 VkPipelineStageFlags srcStage = s.stage;
5335 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5336 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5345 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5346 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5347 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5349 qWarning(
"Physical device surface queries not available");
5353 return new QVkSwapChain(
this);
5356QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5358 return new QVkBuffer(
this, type, usage, size);
5363 return int(ubufAlign);
5385 static QMatrix4x4 m;
5386 if (m.isIdentity()) {
5388 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5389 0.0f, -1.0f, 0.0f, 0.0f,
5390 0.0f, 0.0f, 0.5f, 0.5f,
5391 0.0f, 0.0f, 0.0f, 1.0f);
5401 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5402 if (!physDevFeatures.textureCompressionBC)
5406 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5407 if (!physDevFeatures.textureCompressionETC2)
5411 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5412 if (!physDevFeatures.textureCompressionASTC_LDR)
5416 VkFormat vkformat = toVkTextureFormat(format, flags);
5417 VkFormatProperties props;
5418 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5419 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5425 case QRhi::MultisampleTexture:
5427 case QRhi::MultisampleRenderBuffer:
5429 case QRhi::DebugMarkers:
5430 return caps.debugUtils;
5431 case QRhi::Timestamps:
5432 return timestampValidBits != 0;
5433 case QRhi::Instancing:
5435 case QRhi::CustomInstanceStepRate:
5436 return caps.vertexAttribDivisor;
5437 case QRhi::PrimitiveRestart:
5439 case QRhi::NonDynamicUniformBuffers:
5441 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5443 case QRhi::NPOTTextureRepeat:
5445 case QRhi::RedOrAlpha8IsRed:
5447 case QRhi::ElementIndexUint:
5450 return caps.compute;
5451 case QRhi::WideLines:
5452 return caps.wideLines;
5453 case QRhi::VertexShaderPointSize:
5455 case QRhi::BaseVertex:
5457 case QRhi::BaseInstance:
5459 case QRhi::TriangleFanTopology:
5461 case QRhi::ReadBackNonUniformBuffer:
5463 case QRhi::ReadBackNonBaseMipLevel:
5465 case QRhi::TexelFetch:
5467 case QRhi::RenderToNonBaseMipLevel:
5469 case QRhi::IntAttributes:
5471 case QRhi::ScreenSpaceDerivatives:
5473 case QRhi::ReadBackAnyTextureFormat:
5475 case QRhi::PipelineCacheDataLoadSave:
5477 case QRhi::ImageDataStride:
5479 case QRhi::RenderBufferImport:
5481 case QRhi::ThreeDimensionalTextures:
5483 case QRhi::RenderTo3DTextureSlice:
5484 return caps.texture3DSliceAs2D;
5485 case QRhi::TextureArrays:
5487 case QRhi::Tessellation:
5488 return caps.tessellation;
5489 case QRhi::GeometryShader:
5490 return caps.geometryShader;
5491 case QRhi::TextureArrayRange:
5493 case QRhi::NonFillPolygonMode:
5494 return caps.nonFillPolygonMode;
5495 case QRhi::OneDimensionalTextures:
5497 case QRhi::OneDimensionalTextureMipmaps:
5499 case QRhi::HalfAttributes:
5501 case QRhi::RenderToOneDimensionalTexture:
5503 case QRhi::ThreeDimensionalTextureMipmaps:
5505 case QRhi::MultiView:
5506 return caps.multiView;
5507 case QRhi::TextureViewFormat:
5509 case QRhi::ResolveDepthStencil:
5510 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5511 case QRhi::VariableRateShading:
5512 return caps.renderPass2KHR && caps.perDrawShadingRate;
5513 case QRhi::VariableRateShadingMap:
5514 case QRhi::VariableRateShadingMapWithTexture:
5515 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5516 case QRhi::PerRenderTargetBlending:
5517 case QRhi::SampleVariables:
5519 case QRhi::InstanceIndexIncludesBaseInstance:
5522 Q_UNREACHABLE_RETURN(
false);
5529 case QRhi::TextureSizeMin:
5531 case QRhi::TextureSizeMax:
5532 return int(physDevProperties.limits.maxImageDimension2D);
5533 case QRhi::MaxColorAttachments:
5534 return int(physDevProperties.limits.maxColorAttachments);
5535 case QRhi::FramesInFlight:
5537 case QRhi::MaxAsyncReadbackFrames:
5539 case QRhi::MaxThreadGroupsPerDimension:
5540 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5541 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5542 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5543 case QRhi::MaxThreadsPerThreadGroup:
5544 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5545 case QRhi::MaxThreadGroupX:
5546 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5547 case QRhi::MaxThreadGroupY:
5548 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5549 case QRhi::MaxThreadGroupZ:
5550 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5551 case QRhi::TextureArraySizeMax:
5552 return int(physDevProperties.limits.maxImageArrayLayers);
5553 case QRhi::MaxUniformBufferRange:
5554 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5555 case QRhi::MaxVertexInputs:
5556 return physDevProperties.limits.maxVertexInputAttributes;
5557 case QRhi::MaxVertexOutputs:
5558 return physDevProperties.limits.maxVertexOutputComponents / 4;
5559 case QRhi::ShadingRateImageTileSize:
5560 return caps.imageBasedShadingRateTileSize;
5562 Q_UNREACHABLE_RETURN(0);
5568 return &nativeHandlesStruct;
5573 return driverInfoStruct;
5579 result.totalPipelineCreationTime = totalPipelineCreationTime();
5581 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5582 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5584 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5585 for (uint32_t i = 0; i < count; ++i) {
5586 const VmaStatistics &stats(budgets[i].statistics);
5587 result.blockCount += stats.blockCount;
5588 result.allocCount += stats.allocationCount;
5589 result.usedBytes += stats.allocationBytes;
5590 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5604 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5608 waitSemaphoresForQueueSubmit.clear();
5609 if (sp->waitSemaphoreCount)
5610 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5612 signalSemaphoresForQueueSubmit.clear();
5613 if (sp->signalSemaphoreCount)
5614 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5616 waitSemaphoresForPresent.clear();
5617 if (sp->presentWaitSemaphoreCount)
5618 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5648 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5651 size_t dataSize = 0;
5652 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5653 if (err != VK_SUCCESS) {
5654 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5655 return QByteArray();
5658 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5659 data.resize(dataOffset + dataSize);
5660 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5661 if (err != VK_SUCCESS) {
5662 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5663 return QByteArray();
5667 header.rhiId = pipelineCacheRhiId();
5668 header.arch = quint32(
sizeof(
void*));
5669 header.driverVersion = physDevProperties.driverVersion;
5670 header.vendorId = physDevProperties.vendorID;
5671 header.deviceId = physDevProperties.deviceID;
5672 header.dataSize = quint32(dataSize);
5673 header.uuidSize = VK_UUID_SIZE;
5674 header.reserved = 0;
5675 memcpy(data.data(), &header, headerSize);
5676 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5687 if (data.size() < qsizetype(headerSize)) {
5688 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5692 memcpy(&header, data.constData(), headerSize);
5694 const quint32 rhiId = pipelineCacheRhiId();
5695 if (header.rhiId != rhiId) {
5696 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5697 rhiId, header.rhiId);
5700 const quint32 arch = quint32(
sizeof(
void*));
5701 if (header.arch != arch) {
5702 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5706 if (header.driverVersion != physDevProperties.driverVersion) {
5707 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5708 physDevProperties.driverVersion, header.driverVersion);
5711 if (header.vendorId != physDevProperties.vendorID) {
5712 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5713 physDevProperties.vendorID, header.vendorId);
5716 if (header.deviceId != physDevProperties.deviceID) {
5717 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5718 physDevProperties.deviceID, header.deviceId);
5721 if (header.uuidSize != VK_UUID_SIZE) {
5722 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5723 quint32(VK_UUID_SIZE), header.uuidSize);
5727 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5728 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5731 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5732 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5736 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5737 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5738 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5742 if (pipelineCache) {
5743 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5744 pipelineCache = VK_NULL_HANDLE;
5747 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5748 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5749 int(header.dataSize));
5751 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5755QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5756 int sampleCount, QRhiRenderBuffer::Flags flags,
5757 QRhiTexture::Format backingFormatHint)
5759 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5763 const QSize &pixelSize,
int depth,
int arraySize,
5764 int sampleCount, QRhiTexture::Flags flags)
5766 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5770 QRhiSampler::Filter mipmapMode,
5771 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5773 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5778 return new QVkShadingRateMap(
this);
5782 QRhiTextureRenderTarget::Flags flags)
5789 return new QVkGraphicsPipeline(
this);
5794 return new QVkComputePipeline(
this);
5799 return new QVkShaderResourceBindings(
this);
5805 Q_ASSERT(psD->pipeline);
5809 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5811 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5815 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5816 cmd.args.bindPipeline.pipeline = psD->pipeline;
5819 cbD->currentGraphicsPipeline = ps;
5820 cbD->currentComputePipeline =
nullptr;
5821 cbD->currentPipelineGeneration = psD->generation;
5824 psD->lastActiveFrameSlot = currentFrameSlot;
5828 int dynamicOffsetCount,
5829 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5839 srb = gfxPsD->m_shaderResourceBindings;
5841 srb = compPsD->m_shaderResourceBindings;
5845 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5846 bool rewriteDescSet =
false;
5847 bool addWriteBarrier =
false;
5848 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5849 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5853 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5854 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5857 case QRhiShaderResourceBinding::UniformBuffer:
5860 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5862 if (bufD->m_type == QRhiBuffer::Dynamic)
5865 bufD->lastActiveFrameSlot = currentFrameSlot;
5866 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5868 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5874 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5875 rewriteDescSet =
true;
5876 bd.ubuf.id = bufD->m_id;
5877 bd.ubuf.generation = bufD->generation;
5881 case QRhiShaderResourceBinding::SampledTexture:
5882 case QRhiShaderResourceBinding::Texture:
5883 case QRhiShaderResourceBinding::Sampler:
5885 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5886 if (bd.stex.count != data->count) {
5887 bd.stex.count = data->count;
5888 rewriteDescSet =
true;
5890 for (
int elem = 0; elem < data->count; ++elem) {
5896 Q_ASSERT(texD || samplerD);
5898 texD->lastActiveFrameSlot = currentFrameSlot;
5904 samplerD->lastActiveFrameSlot = currentFrameSlot;
5905 const quint64 texId = texD ? texD->m_id : 0;
5906 const uint texGen = texD ? texD->generation : 0;
5907 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
5908 const uint samplerGen = samplerD ? samplerD->generation : 0;
5909 if (texGen != bd.stex.d[elem].texGeneration
5910 || texId != bd.stex.d[elem].texId
5911 || samplerGen != bd.stex.d[elem].samplerGeneration
5912 || samplerId != bd.stex.d[elem].samplerId)
5914 rewriteDescSet =
true;
5915 bd.stex.d[elem].texId = texId;
5916 bd.stex.d[elem].texGeneration = texGen;
5917 bd.stex.d[elem].samplerId = samplerId;
5918 bd.stex.d[elem].samplerGeneration = samplerGen;
5923 case QRhiShaderResourceBinding::ImageLoad:
5924 case QRhiShaderResourceBinding::ImageStore:
5925 case QRhiShaderResourceBinding::ImageLoadStore:
5928 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
5929 texD->lastActiveFrameSlot = currentFrameSlot;
5931 if (b->type == QRhiShaderResourceBinding::ImageLoad)
5933 else if (b->type == QRhiShaderResourceBinding::ImageStore)
5938 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
5939 const auto prevAccess = passResTracker.textures().find(texD);
5940 if (prevAccess != passResTracker.textures().end()) {
5944 addWriteBarrier =
true;
5945 writeBarrierDstStageMask |= toVkPipelineStage(stage);
5946 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
5954 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
5955 rewriteDescSet =
true;
5956 bd.simage.id = texD->m_id;
5957 bd.simage.generation = texD->generation;
5961 case QRhiShaderResourceBinding::BufferLoad:
5962 case QRhiShaderResourceBinding::BufferStore:
5963 case QRhiShaderResourceBinding::BufferLoadStore:
5966 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
5968 if (bufD->m_type == QRhiBuffer::Dynamic)
5971 bufD->lastActiveFrameSlot = currentFrameSlot;
5973 if (b->type == QRhiShaderResourceBinding::BufferLoad)
5975 else if (b->type == QRhiShaderResourceBinding::BufferStore)
5980 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
5981 const auto prevAccess = passResTracker.buffers().find(bufD);
5982 if (prevAccess != passResTracker.buffers().end()) {
5986 addWriteBarrier =
true;
5987 writeBarrierDstStageMask |= toVkPipelineStage(stage);
5988 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
5991 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5995 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
5996 rewriteDescSet =
true;
5997 bd.sbuf.id = bufD->m_id;
5998 bd.sbuf.generation = bufD->generation;
6008 if (addWriteBarrier) {
6010 VkMemoryBarrier barrier;
6011 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6012 barrier.pNext =
nullptr;
6013 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6014 barrier.srcAccessMask = barrier.dstAccessMask;
6015 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6022 cmd.args.memoryBarrier.dependencyFlags = 0;
6023 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6024 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6025 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6026 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6032 updateShaderResourceBindings(srb);
6036 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot || srbD->hasDynamicOffset;
6038 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6040 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6041 QVarLengthArray<uint32_t, 4> dynOfs;
6047 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
6048 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
6049 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
6050 uint32_t offset = 0;
6051 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6052 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6053 if (bindingOffsetPair.first == b->binding) {
6054 offset = bindingOffsetPair.second;
6058 dynOfs.append(offset);
6064 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6065 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6066 gfxPsD ? gfxPsD->layout : compPsD->layout,
6067 0, 1, &srbD->descSets[currentFrameSlot],
6068 uint32_t(dynOfs.size()),
6069 dynOfs.size() ? dynOfs.constData() :
nullptr);
6073 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6074 : VK_PIPELINE_BIND_POINT_COMPUTE;
6075 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6076 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6077 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6078 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6079 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6083 cbD->currentGraphicsSrb = srb;
6084 cbD->currentComputeSrb =
nullptr;
6086 cbD->currentGraphicsSrb =
nullptr;
6087 cbD->currentComputeSrb = srb;
6089 cbD->currentSrbGeneration = srbD->generation;
6090 cbD->currentDescSetSlot = currentFrameSlot;
6093 srbD->lastActiveFrameSlot = currentFrameSlot;
6097 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6098 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6104 bool needsBindVBuf =
false;
6105 for (
int i = 0; i < bindingCount; ++i) {
6106 const int inputSlot = startBinding + i;
6108 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6109 bufD->lastActiveFrameSlot = currentFrameSlot;
6110 if (bufD->m_type == QRhiBuffer::Dynamic)
6113 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6114 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6115 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6117 needsBindVBuf =
true;
6118 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6119 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6123 if (needsBindVBuf) {
6124 QVarLengthArray<VkBuffer, 4> bufs;
6125 QVarLengthArray<VkDeviceSize, 4> ofs;
6126 for (
int i = 0; i < bindingCount; ++i) {
6128 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6129 bufs.append(bufD->buffers[slot]);
6130 ofs.append(bindings[i].second);
6137 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6138 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6142 cmd.args.bindVertexBuffer.startBinding = startBinding;
6143 cmd.args.bindVertexBuffer.count = bufs.size();
6144 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6145 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6146 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6147 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6153 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6154 ibufD->lastActiveFrameSlot = currentFrameSlot;
6155 if (ibufD->m_type == QRhiBuffer::Dynamic)
6158 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6159 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6160 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6161 : VK_INDEX_TYPE_UINT32;
6163 if (cbD->currentIndexBuffer != vkindexbuf
6164 || cbD->currentIndexOffset != indexOffset
6165 || cbD->currentIndexFormat != type)
6167 cbD->currentIndexBuffer = vkindexbuf;
6168 cbD->currentIndexOffset = indexOffset;
6169 cbD->currentIndexFormat = type;
6172 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6176 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6177 cmd.args.bindIndexBuffer.ofs = indexOffset;
6178 cmd.args.bindIndexBuffer.type = type;
6192 const QSize outputSize = cbD->currentTarget->pixelSize();
6196 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6200 VkViewport *vp = &cmd.args.setViewport.viewport;
6205 vp->minDepth = viewport.minDepth();
6206 vp->maxDepth = viewport.maxDepth();
6209 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6210 cbD->commands.unget();
6215 if (cbD->currentGraphicsPipeline
6219 VkRect2D *s = &cmd.args.setScissor.scissor;
6220 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
6221 s->offset.x = int32_t(x);
6222 s->offset.y = int32_t(y);
6223 s->extent.width = uint32_t(w);
6224 s->extent.height = uint32_t(h);
6226 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6227 cbD->commands.unget();
6238 Q_ASSERT(!cbD->currentGraphicsPipeline
6240 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6241 const QSize outputSize = cbD->currentTarget->pixelSize();
6245 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6249 VkRect2D *s = &cmd.args.setScissor.scissor;
6252 s->extent.width = uint32_t(w);
6253 s->extent.height = uint32_t(h);
6256 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6257 cbD->commands.unget();
6269 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6270 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6274 cmd.args.setBlendConstants.c[0] = c.redF();
6275 cmd.args.setBlendConstants.c[1] = c.greenF();
6276 cmd.args.setBlendConstants.c[2] = c.blueF();
6277 cmd.args.setBlendConstants.c[3] = c.alphaF();
6287 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6291 cmd.args.setStencilRef.ref = refValue;
6297#ifdef VK_KHR_fragment_shading_rate
6298 if (!vkCmdSetFragmentShadingRateKHR)
6301 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6302 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6303 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6305 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6306 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6307 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6309 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6310 if (cbD->passUsesSecondaryCb) {
6311 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6313 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6314 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6315 cmd.args.setShadingRate.w = size.width;
6316 cmd.args.setShadingRate.h = size.height;
6318 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6319 cbD->hasShadingRateSet =
true;
6322 Q_UNUSED(coarsePixelSize);
6327 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6333 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6337 cmd.args.draw.vertexCount = vertexCount;
6338 cmd.args.draw.instanceCount = instanceCount;
6339 cmd.args.draw.firstVertex = firstVertex;
6340 cmd.args.draw.firstInstance = firstInstance;
6345 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6351 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6352 firstIndex, vertexOffset, firstInstance);
6356 cmd.args.drawIndexed.indexCount = indexCount;
6357 cmd.args.drawIndexed.instanceCount = instanceCount;
6358 cmd.args.drawIndexed.firstIndex = firstIndex;
6359 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6360 cmd.args.drawIndexed.firstInstance = firstInstance;
6366#ifdef VK_EXT_debug_utils
6367 if (!debugMarkers || !caps.debugUtils)
6370 VkDebugUtilsLabelEXT label = {};
6371 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6373 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6374 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6375 label.pLabelName = name.constData();
6376 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6378 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6379 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6380 cmd.args.debugMarkerBegin.label = label;
6381 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6382 cbD->pools.debugMarkerData.append(name);
6392#ifdef VK_EXT_debug_utils
6393 if (!debugMarkers || !caps.debugUtils)
6396 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6397 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6398 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6400 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6401 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6410#ifdef VK_EXT_debug_utils
6411 if (!debugMarkers || !caps.debugUtils)
6414 VkDebugUtilsLabelEXT label = {};
6415 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6417 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6418 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6419 label.pLabelName = msg.constData();
6420 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6422 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6423 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6424 cmd.args.debugMarkerInsert.label = label;
6425 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6426 cbD->pools.debugMarkerData.append(msg);
6436 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6441 Q_ASSERT(cbD->currentTarget);
6444 switch (cbD->currentTarget->resourceType()) {
6445 case QRhiResource::SwapChainRenderTarget:
6448 case QRhiResource::TextureRenderTarget:
6480 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6481 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6485 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6486 cbD->activeSecondaryCbStack.removeLast();
6487 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6489 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6491 cbD->activeSecondaryCbStack.append(extCb);
6503 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6504 cbD->activeSecondaryCbStack.removeLast();
6505 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6506 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6520 if (!debugMarkers || name.isEmpty())
6523 QByteArray decoratedName = name;
6525 decoratedName +=
'/';
6526 decoratedName += QByteArray::number(slot);
6528 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6533#ifdef VK_EXT_debug_utils
6534 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6537 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6538 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6539 nameInfo.objectType = type;
6540 nameInfo.objectHandle = object;
6541 QByteArray decoratedName = name;
6543 decoratedName +=
'/';
6544 decoratedName += QByteArray::number(slot);
6546 nameInfo.pObjectName = decoratedName.constData();
6547 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6559 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6560 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6561 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6562 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6563 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6564 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6565 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6566 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6567 return VkBufferUsageFlagBits(u);
6573 case QRhiSampler::Nearest:
6574 return VK_FILTER_NEAREST;
6575 case QRhiSampler::Linear:
6576 return VK_FILTER_LINEAR;
6578 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6585 case QRhiSampler::None:
6586 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6587 case QRhiSampler::Nearest:
6588 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6589 case QRhiSampler::Linear:
6590 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6592 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6599 case QRhiSampler::Repeat:
6600 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6601 case QRhiSampler::ClampToEdge:
6602 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6603 case QRhiSampler::Mirror:
6604 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6606 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6613 case QRhiShaderStage::Vertex:
6614 return VK_SHADER_STAGE_VERTEX_BIT;
6615 case QRhiShaderStage::TessellationControl:
6616 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6617 case QRhiShaderStage::TessellationEvaluation:
6618 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6619 case QRhiShaderStage::Fragment:
6620 return VK_SHADER_STAGE_FRAGMENT_BIT;
6621 case QRhiShaderStage::Compute:
6622 return VK_SHADER_STAGE_COMPUTE_BIT;
6623 case QRhiShaderStage::Geometry:
6624 return VK_SHADER_STAGE_GEOMETRY_BIT;
6626 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6633 case QRhiVertexInputAttribute::Float4:
6634 return VK_FORMAT_R32G32B32A32_SFLOAT;
6635 case QRhiVertexInputAttribute::Float3:
6636 return VK_FORMAT_R32G32B32_SFLOAT;
6637 case QRhiVertexInputAttribute::Float2:
6638 return VK_FORMAT_R32G32_SFLOAT;
6639 case QRhiVertexInputAttribute::Float:
6640 return VK_FORMAT_R32_SFLOAT;
6641 case QRhiVertexInputAttribute::UNormByte4:
6642 return VK_FORMAT_R8G8B8A8_UNORM;
6643 case QRhiVertexInputAttribute::UNormByte2:
6644 return VK_FORMAT_R8G8_UNORM;
6645 case QRhiVertexInputAttribute::UNormByte:
6646 return VK_FORMAT_R8_UNORM;
6647 case QRhiVertexInputAttribute::UInt4:
6648 return VK_FORMAT_R32G32B32A32_UINT;
6649 case QRhiVertexInputAttribute::UInt3:
6650 return VK_FORMAT_R32G32B32_UINT;
6651 case QRhiVertexInputAttribute::UInt2:
6652 return VK_FORMAT_R32G32_UINT;
6653 case QRhiVertexInputAttribute::UInt:
6654 return VK_FORMAT_R32_UINT;
6655 case QRhiVertexInputAttribute::SInt4:
6656 return VK_FORMAT_R32G32B32A32_SINT;
6657 case QRhiVertexInputAttribute::SInt3:
6658 return VK_FORMAT_R32G32B32_SINT;
6659 case QRhiVertexInputAttribute::SInt2:
6660 return VK_FORMAT_R32G32_SINT;
6661 case QRhiVertexInputAttribute::SInt:
6662 return VK_FORMAT_R32_SINT;
6663 case QRhiVertexInputAttribute::Half4:
6664 return VK_FORMAT_R16G16B16A16_SFLOAT;
6665 case QRhiVertexInputAttribute::Half3:
6666 return VK_FORMAT_R16G16B16_SFLOAT;
6667 case QRhiVertexInputAttribute::Half2:
6668 return VK_FORMAT_R16G16_SFLOAT;
6669 case QRhiVertexInputAttribute::Half:
6670 return VK_FORMAT_R16_SFLOAT;
6671 case QRhiVertexInputAttribute::UShort4:
6672 return VK_FORMAT_R16G16B16A16_UINT;
6673 case QRhiVertexInputAttribute::UShort3:
6674 return VK_FORMAT_R16G16B16_UINT;
6675 case QRhiVertexInputAttribute::UShort2:
6676 return VK_FORMAT_R16G16_UINT;
6677 case QRhiVertexInputAttribute::UShort:
6678 return VK_FORMAT_R16_UINT;
6679 case QRhiVertexInputAttribute::SShort4:
6680 return VK_FORMAT_R16G16B16A16_SINT;
6681 case QRhiVertexInputAttribute::SShort3:
6682 return VK_FORMAT_R16G16B16_SINT;
6683 case QRhiVertexInputAttribute::SShort2:
6684 return VK_FORMAT_R16G16_SINT;
6685 case QRhiVertexInputAttribute::SShort:
6686 return VK_FORMAT_R16_SINT;
6688 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6695 case QRhiGraphicsPipeline::Triangles:
6696 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6697 case QRhiGraphicsPipeline::TriangleStrip:
6698 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6699 case QRhiGraphicsPipeline::TriangleFan:
6700 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6701 case QRhiGraphicsPipeline::Lines:
6702 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6703 case QRhiGraphicsPipeline::LineStrip:
6704 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6705 case QRhiGraphicsPipeline::Points:
6706 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6707 case QRhiGraphicsPipeline::Patches:
6708 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6710 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6717 case QRhiGraphicsPipeline::None:
6718 return VK_CULL_MODE_NONE;
6719 case QRhiGraphicsPipeline::Front:
6720 return VK_CULL_MODE_FRONT_BIT;
6721 case QRhiGraphicsPipeline::Back:
6722 return VK_CULL_MODE_BACK_BIT;
6724 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6731 case QRhiGraphicsPipeline::CCW:
6732 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6733 case QRhiGraphicsPipeline::CW:
6734 return VK_FRONT_FACE_CLOCKWISE;
6736 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6743 if (c.testFlag(QRhiGraphicsPipeline::R))
6744 f |= VK_COLOR_COMPONENT_R_BIT;
6745 if (c.testFlag(QRhiGraphicsPipeline::G))
6746 f |= VK_COLOR_COMPONENT_G_BIT;
6747 if (c.testFlag(QRhiGraphicsPipeline::B))
6748 f |= VK_COLOR_COMPONENT_B_BIT;
6749 if (c.testFlag(QRhiGraphicsPipeline::A))
6750 f |= VK_COLOR_COMPONENT_A_BIT;
6751 return VkColorComponentFlags(f);
6757 case QRhiGraphicsPipeline::Zero:
6758 return VK_BLEND_FACTOR_ZERO;
6759 case QRhiGraphicsPipeline::One:
6760 return VK_BLEND_FACTOR_ONE;
6761 case QRhiGraphicsPipeline::SrcColor:
6762 return VK_BLEND_FACTOR_SRC_COLOR;
6763 case QRhiGraphicsPipeline::OneMinusSrcColor:
6764 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6765 case QRhiGraphicsPipeline::DstColor:
6766 return VK_BLEND_FACTOR_DST_COLOR;
6767 case QRhiGraphicsPipeline::OneMinusDstColor:
6768 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6769 case QRhiGraphicsPipeline::SrcAlpha:
6770 return VK_BLEND_FACTOR_SRC_ALPHA;
6771 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6772 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6773 case QRhiGraphicsPipeline::DstAlpha:
6774 return VK_BLEND_FACTOR_DST_ALPHA;
6775 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6776 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
6777 case QRhiGraphicsPipeline::ConstantColor:
6778 return VK_BLEND_FACTOR_CONSTANT_COLOR;
6779 case QRhiGraphicsPipeline::OneMinusConstantColor:
6780 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
6781 case QRhiGraphicsPipeline::ConstantAlpha:
6782 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
6783 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6784 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
6785 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6786 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
6787 case QRhiGraphicsPipeline::Src1Color:
6788 return VK_BLEND_FACTOR_SRC1_COLOR;
6789 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6790 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
6791 case QRhiGraphicsPipeline::Src1Alpha:
6792 return VK_BLEND_FACTOR_SRC1_ALPHA;
6793 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6794 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
6796 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
6803 case QRhiGraphicsPipeline::Add:
6804 return VK_BLEND_OP_ADD;
6805 case QRhiGraphicsPipeline::Subtract:
6806 return VK_BLEND_OP_SUBTRACT;
6807 case QRhiGraphicsPipeline::ReverseSubtract:
6808 return VK_BLEND_OP_REVERSE_SUBTRACT;
6809 case QRhiGraphicsPipeline::Min:
6810 return VK_BLEND_OP_MIN;
6811 case QRhiGraphicsPipeline::Max:
6812 return VK_BLEND_OP_MAX;
6814 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
6821 case QRhiGraphicsPipeline::Never:
6822 return VK_COMPARE_OP_NEVER;
6823 case QRhiGraphicsPipeline::Less:
6824 return VK_COMPARE_OP_LESS;
6825 case QRhiGraphicsPipeline::Equal:
6826 return VK_COMPARE_OP_EQUAL;
6827 case QRhiGraphicsPipeline::LessOrEqual:
6828 return VK_COMPARE_OP_LESS_OR_EQUAL;
6829 case QRhiGraphicsPipeline::Greater:
6830 return VK_COMPARE_OP_GREATER;
6831 case QRhiGraphicsPipeline::NotEqual:
6832 return VK_COMPARE_OP_NOT_EQUAL;
6833 case QRhiGraphicsPipeline::GreaterOrEqual:
6834 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6835 case QRhiGraphicsPipeline::Always:
6836 return VK_COMPARE_OP_ALWAYS;
6838 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
6845 case QRhiGraphicsPipeline::StencilZero:
6846 return VK_STENCIL_OP_ZERO;
6847 case QRhiGraphicsPipeline::Keep:
6848 return VK_STENCIL_OP_KEEP;
6849 case QRhiGraphicsPipeline::Replace:
6850 return VK_STENCIL_OP_REPLACE;
6851 case QRhiGraphicsPipeline::IncrementAndClamp:
6852 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
6853 case QRhiGraphicsPipeline::DecrementAndClamp:
6854 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
6855 case QRhiGraphicsPipeline::Invert:
6856 return VK_STENCIL_OP_INVERT;
6857 case QRhiGraphicsPipeline::IncrementAndWrap:
6858 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
6859 case QRhiGraphicsPipeline::DecrementAndWrap:
6860 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
6862 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
6869 case QRhiGraphicsPipeline::Fill:
6870 return VK_POLYGON_MODE_FILL;
6871 case QRhiGraphicsPipeline::Line:
6872 return VK_POLYGON_MODE_LINE;
6874 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
6880 dst->failOp = toVkStencilOp(src.failOp);
6881 dst->passOp = toVkStencilOp(src.passOp);
6882 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
6883 dst->compareOp = toVkCompareOp(src.compareOp);
6889 case QRhiShaderResourceBinding::UniformBuffer:
6890 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
6891 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
6893 case QRhiShaderResourceBinding::SampledTexture:
6894 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6896 case QRhiShaderResourceBinding::Texture:
6897 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
6899 case QRhiShaderResourceBinding::Sampler:
6900 return VK_DESCRIPTOR_TYPE_SAMPLER;
6902 case QRhiShaderResourceBinding::ImageLoad:
6903 case QRhiShaderResourceBinding::ImageStore:
6904 case QRhiShaderResourceBinding::ImageLoadStore:
6905 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
6907 case QRhiShaderResourceBinding::BufferLoad:
6908 case QRhiShaderResourceBinding::BufferStore:
6909 case QRhiShaderResourceBinding::BufferLoadStore:
6910 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
6913 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
6920 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
6921 s |= VK_SHADER_STAGE_VERTEX_BIT;
6922 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
6923 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
6924 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
6925 s |= VK_SHADER_STAGE_COMPUTE_BIT;
6926 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
6927 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6928 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
6929 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6930 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
6931 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
6932 return VkShaderStageFlags(s);
6938 case QRhiSampler::Never:
6939 return VK_COMPARE_OP_NEVER;
6940 case QRhiSampler::Less:
6941 return VK_COMPARE_OP_LESS;
6942 case QRhiSampler::Equal:
6943 return VK_COMPARE_OP_EQUAL;
6944 case QRhiSampler::LessOrEqual:
6945 return VK_COMPARE_OP_LESS_OR_EQUAL;
6946 case QRhiSampler::Greater:
6947 return VK_COMPARE_OP_GREATER;
6948 case QRhiSampler::NotEqual:
6949 return VK_COMPARE_OP_NOT_EQUAL;
6950 case QRhiSampler::GreaterOrEqual:
6951 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6952 case QRhiSampler::Always:
6953 return VK_COMPARE_OP_ALWAYS;
6955 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
6963 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
6983 e.buffer.buffers[i] = buffers[i];
6985 e.buffer.stagingBuffers[i] = stagingBuffers[i];
6988 buffers[i] = VK_NULL_HANDLE;
6990 stagingBuffers[i] = VK_NULL_HANDLE;
6992 pendingDynamicUpdates[i].clear();
7000 rhiD->releaseQueue.append(e);
7001 rhiD->unregisterResource(
this);
7010 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7011 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7015 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7017 VkBufferCreateInfo bufferInfo = {};
7018 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7019 bufferInfo.size = nonZeroSize;
7020 bufferInfo.usage = toVkBufferUsage(m_usage);
7022 VmaAllocationCreateInfo allocInfo = {};
7024 if (m_type == Dynamic) {
7029 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7032 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7034 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7035 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7039 VkResult err = VK_SUCCESS;
7041 buffers[i] = VK_NULL_HANDLE;
7043 usageState[i].access = usageState[i].stage = 0;
7044 if (i == 0 || m_type == Dynamic) {
7045 VmaAllocation allocation;
7046 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7047 if (err != VK_SUCCESS)
7050 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7051 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7052 m_type == Dynamic ? i : -1);
7056 if (err != VK_SUCCESS) {
7057 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7058 rhiD->printExtraErrorInfo(err);
7064 rhiD->registerResource(
this);
7070 if (m_type == Dynamic) {
7076 b.objects[i] = &buffers[i];
7081 return { { &buffers[0] }, 1 };
7091 Q_ASSERT(m_type == Dynamic);
7093 Q_ASSERT(rhiD->inFrame);
7094 const int slot = rhiD->currentFrameSlot;
7096 VmaAllocation a = toVmaAllocation(allocations[slot]);
7097 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7098 if (err != VK_SUCCESS) {
7099 qWarning(
"Failed to map buffer: %d", err);
7102 return static_cast<
char *>(p);
7108 const int slot = rhiD->currentFrameSlot;
7109 VmaAllocation a = toVmaAllocation(allocations[slot]);
7110 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7111 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7115 int sampleCount, Flags flags,
7116 QRhiTexture::Format backingFormatHint)
7129 if (!memory && !backingTexture)
7136 e.renderBuffer.memory = memory;
7137 e.renderBuffer.image = image;
7138 e.renderBuffer.imageView = imageView;
7140 memory = VK_NULL_HANDLE;
7141 image = VK_NULL_HANDLE;
7142 imageView = VK_NULL_HANDLE;
7152 rhiD->releaseQueue.append(e);
7153 rhiD->unregisterResource(
this);
7159 if (memory || backingTexture)
7162 if (m_pixelSize.isEmpty())
7166 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7169 case QRhiRenderBuffer::Color:
7177 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7185 vkformat = backingTexture->vkformat;
7188 case QRhiRenderBuffer::DepthStencil:
7189 vkformat = rhiD->optimalDepthStencilFormat();
7190 if (!rhiD->createTransientImage(vkformat,
7192 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7193 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7202 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7211 rhiD->registerResource(
this);
7217 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7218 return m_backingFormatHint;
7220 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7224 int arraySize,
int sampleCount, Flags flags)
7228 stagingBuffers[i] = VK_NULL_HANDLE;
7231 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7232 perLevelImageViews[i] = VK_NULL_HANDLE;
7249 e.texture.image = owns ? image : VK_NULL_HANDLE;
7250 e.texture.imageView = imageView;
7254 e.texture.stagingBuffers[i] = stagingBuffers[i];
7257 stagingBuffers[i] = VK_NULL_HANDLE;
7261 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7262 e.texture.extraImageViews[i] = perLevelImageViews[i];
7263 perLevelImageViews[i] = VK_NULL_HANDLE;
7266 image = VK_NULL_HANDLE;
7267 imageView = VK_NULL_HANDLE;
7272 rhiD->releaseQueue.append(e);
7273 rhiD->unregisterResource(
this);
7283 vkformat = toVkTextureFormat(m_format, m_flags);
7284 if (m_writeViewFormat.format != UnknownFormat)
7285 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7287 viewFormat = vkformat;
7288 if (m_readViewFormat.format != UnknownFormat)
7289 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7291 viewFormatForSampling = vkformat;
7293 VkFormatProperties props;
7294 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7295 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7296 if (!canSampleOptimal) {
7297 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7301 const bool isCube = m_flags.testFlag(CubeMap);
7302 const bool isArray = m_flags.testFlag(TextureArray);
7303 const bool is3D = m_flags.testFlag(ThreeDimensional);
7304 const bool is1D = m_flags.testFlag(OneDimensional);
7305 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7307 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7308 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7310 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7311 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7312 if (mipLevelCount > maxLevels) {
7313 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7314 mipLevelCount = maxLevels;
7316 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7317 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7319 qWarning(
"Cubemap texture cannot be multisample");
7323 qWarning(
"3D texture cannot be multisample");
7327 qWarning(
"Multisample texture cannot have mipmaps");
7331 if (isCube && is3D) {
7332 qWarning(
"Texture cannot be both cube and 3D");
7335 if (isArray && is3D) {
7336 qWarning(
"Texture cannot be both array and 3D");
7339 if (isCube && is1D) {
7340 qWarning(
"Texture cannot be both cube and 1D");
7344 qWarning(
"Texture cannot be both 1D and 3D");
7347 if (m_depth > 1 && !is3D) {
7348 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7351 if (m_arraySize > 0 && !isArray) {
7352 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7355 if (m_arraySize < 1 && isArray) {
7356 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7360 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7361 usageState.access = 0;
7362 usageState.stage = 0;
7365 *adjustedSize = size;
7374 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7375 const bool isCube = m_flags.testFlag(CubeMap);
7376 const bool isArray = m_flags.testFlag(TextureArray);
7377 const bool is3D = m_flags.testFlag(ThreeDimensional);
7378 const bool is1D = m_flags.testFlag(OneDimensional);
7380 VkImageViewCreateInfo viewInfo = {};
7381 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7382 viewInfo.image = image;
7383 viewInfo.viewType = isCube
7384 ? VK_IMAGE_VIEW_TYPE_CUBE
7385 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7386 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7387 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7388 viewInfo.format = viewFormatForSampling;
7389 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7390 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7391 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7392 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7393 viewInfo.subresourceRange.aspectMask = aspectMask;
7396 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7397 viewInfo.subresourceRange.levelCount = mipLevelCount;
7398 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7399 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7400 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7402 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7405 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7406 if (err != VK_SUCCESS) {
7407 qWarning(
"Failed to create image view: %d", err);
7420 if (!prepareCreate(&size))
7424 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7425 const bool isDepth = isDepthTextureFormat(m_format);
7426 const bool isCube = m_flags.testFlag(CubeMap);
7427 const bool isArray = m_flags.testFlag(TextureArray);
7428 const bool is3D = m_flags.testFlag(ThreeDimensional);
7429 const bool is1D = m_flags.testFlag(OneDimensional);
7431 VkImageCreateInfo imageInfo = {};
7432 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7433 imageInfo.flags = 0;
7435 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7437 if (is3D && isRenderTarget) {
7443 if (!rhiD->caps.texture3DSliceAs2D)
7444 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7445#ifdef VK_VERSION_1_1
7446 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7448 imageInfo.flags |= 0x00000020;
7452 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7453 imageInfo.format = vkformat;
7454 imageInfo.extent.width = uint32_t(size.width());
7455 imageInfo.extent.height = uint32_t(size.height());
7456 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7457 imageInfo.mipLevels = mipLevelCount;
7458 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7459 imageInfo.samples = samples;
7460 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7461 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7463 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7464 if (isRenderTarget) {
7466 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7468 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7470 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7471 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7472 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7473 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7474 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7475 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7476#ifdef VK_KHR_fragment_shading_rate
7477 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7478 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7481 VmaAllocationCreateInfo allocInfo = {};
7482 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7484 VmaAllocation allocation;
7485 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7486 if (err != VK_SUCCESS) {
7487 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7488 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7489 int(imageInfo.format),
7490 imageInfo.mipLevels,
7491 imageInfo.arrayLayers,
7492 int(imageInfo.samples),
7494 rhiD->printExtraErrorInfo(err);
7498 rhiD->setAllocationName(allocation, m_objectName);
7503 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7506 rhiD->registerResource(
this);
7512 VkImage img = VkImage(src.object);
7516 if (!prepareCreate())
7524 usageState.layout = VkImageLayout(src.layout);
7528 rhiD->registerResource(
this);
7534 return {quint64(image), usageState.layout};
7539 usageState.layout = VkImageLayout(layout);
7544 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7545 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7546 return perLevelImageViews[level];
7548 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7549 const bool isCube = m_flags.testFlag(CubeMap);
7550 const bool isArray = m_flags.testFlag(TextureArray);
7551 const bool is3D = m_flags.testFlag(ThreeDimensional);
7552 const bool is1D = m_flags.testFlag(OneDimensional);
7554 VkImageViewCreateInfo viewInfo = {};
7555 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7556 viewInfo.image = image;
7557 viewInfo.viewType = isCube
7558 ? VK_IMAGE_VIEW_TYPE_CUBE
7559 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7560 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7561 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7562 viewInfo.format = viewFormat;
7563 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7564 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7565 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7566 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7567 viewInfo.subresourceRange.aspectMask = aspectMask;
7568 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7569 viewInfo.subresourceRange.levelCount = 1;
7570 viewInfo.subresourceRange.baseArrayLayer = 0;
7571 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7573 VkImageView v = VK_NULL_HANDLE;
7575 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7576 if (err != VK_SUCCESS) {
7577 qWarning(
"Failed to create image view: %d", err);
7578 return VK_NULL_HANDLE;
7581 perLevelImageViews[level] = v;
7586 AddressMode u, AddressMode v, AddressMode w)
7605 e.sampler.sampler = sampler;
7606 sampler = VK_NULL_HANDLE;
7610 rhiD->releaseQueue.append(e);
7611 rhiD->unregisterResource(
this);
7620 VkSamplerCreateInfo samplerInfo = {};
7621 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7622 samplerInfo.magFilter = toVkFilter(m_magFilter);
7623 samplerInfo.minFilter = toVkFilter(m_minFilter);
7624 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7625 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7626 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7627 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7628 samplerInfo.maxAnisotropy = 1.0f;
7629 samplerInfo.compareEnable = m_compareOp != Never;
7630 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7631 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7634 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7635 if (err != VK_SUCCESS) {
7636 qWarning(
"Failed to create sampler: %d", err);
7642 rhiD->registerResource(
this);
7649 serializedFormatData.reserve(64);
7663 rp = VK_NULL_HANDLE;
7671 e.renderPass.rp = rp;
7673 rp = VK_NULL_HANDLE;
7677 rhiD->releaseQueue.append(e);
7678 rhiD->unregisterResource(
this);
7684 return a.format == b.format
7685 && a.samples == b.samples
7686 && a.loadOp == b.loadOp
7687 && a.storeOp == b.storeOp
7688 && a.stencilLoadOp == b.stencilLoadOp
7689 && a.stencilStoreOp == b.stencilStoreOp
7690 && a.initialLayout == b.initialLayout
7691 && a.finalLayout == b.finalLayout;
7704 if (attDescs.size() != o->attDescs.size())
7706 if (colorRefs.size() != o->colorRefs.size())
7708 if (resolveRefs.size() != o->resolveRefs.size())
7714 if (multiViewCount != o->multiViewCount)
7719 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7720 const uint32_t attIdx = colorRefs[i].attachment;
7721 if (attIdx != o->colorRefs[i].attachment)
7723 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7728 const uint32_t attIdx = dsRef.attachment;
7729 if (attIdx != o->dsRef.attachment)
7731 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7735 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7736 const uint32_t attIdx = resolveRefs[i].attachment;
7737 if (attIdx != o->resolveRefs[i].attachment)
7739 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7744 const uint32_t attIdx = dsResolveRef.attachment;
7745 if (attIdx != o->dsResolveRef.attachment)
7747 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7752 const uint32_t attIdx = shadingRateRef.attachment;
7753 if (attIdx != o->shadingRateRef.attachment)
7755 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7766 serializedFormatData.clear();
7767 auto p =
std::back_inserter(serializedFormatData);
7769 *p++ = attDescs.size();
7770 *p++ = colorRefs.size();
7771 *p++ = resolveRefs.size();
7775 *p++ = multiViewCount;
7777 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
7778 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
7779 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
7780 *p++ = used ? a->format : 0;
7781 *p++ = used ? a->samples : 0;
7782 *p++ = used ? a->loadOp : 0;
7783 *p++ = used ? a->storeOp : 0;
7784 *p++ = used ? a->stencilLoadOp : 0;
7785 *p++ = used ? a->stencilStoreOp : 0;
7786 *p++ = used ? a->initialLayout : 0;
7787 *p++ = used ? a->finalLayout : 0;
7790 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7791 const uint32_t attIdx = colorRefs[i].attachment;
7793 serializeAttachmentData(attIdx);
7797 const uint32_t attIdx = dsRef.attachment;
7799 serializeAttachmentData(attIdx);
7802 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7803 const uint32_t attIdx = resolveRefs[i].attachment;
7805 serializeAttachmentData(attIdx);
7809 const uint32_t attIdx = dsResolveRef.attachment;
7811 serializeAttachmentData(attIdx);
7815 const uint32_t attIdx = shadingRateRef.attachment;
7817 serializeAttachmentData(attIdx);
7826 rpD->attDescs = attDescs;
7827 rpD->colorRefs = colorRefs;
7828 rpD->resolveRefs = resolveRefs;
7829 rpD->subpassDeps = subpassDeps;
7833 rpD->multiViewCount = multiViewCount;
7835 rpD->dsResolveRef = dsResolveRef;
7836 rpD->shadingRateRef = shadingRateRef;
7838 VkRenderPassCreateInfo rpInfo;
7839 VkSubpassDescription subpassDesc;
7840 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
7844 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
7849#ifdef VK_KHR_create_renderpass2
7850 if (rhiD->caps.renderPass2KHR) {
7852 VkRenderPassCreateInfo2KHR rpInfo2;
7853 RenderPass2SetupHelper rp2Helper(rhiD);
7854 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
7858 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
7859 if (err != VK_SUCCESS) {
7860 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
7867 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
7868 if (err != VK_SUCCESS) {
7869 qWarning(
"Failed to create renderpass: %d", err);
7876 rhiD->registerResource(rpD);
7882 return serializedFormatData;
7887 nativeHandlesStruct.renderPass = rp;
7888 return &nativeHandlesStruct;
7914 texture =
QRHI_RES(QVkTexture, src);
7946 return d.sampleCount;
7950 const QRhiTextureRenderTargetDescription &desc,
7955 rtv[att] = VK_NULL_HANDLE;
7956 resrtv[att] = VK_NULL_HANDLE;
7974 e.textureRenderTarget.fb = d.fb;
7975 d.fb = VK_NULL_HANDLE;
7978 e.textureRenderTarget.rtv[att] = rtv[att];
7979 e.textureRenderTarget.resrtv[att] = resrtv[att];
7980 rtv[att] = VK_NULL_HANDLE;
7981 resrtv[att] = VK_NULL_HANDLE;
7984 e.textureRenderTarget.dsv = dsv;
7985 dsv = VK_NULL_HANDLE;
7986 e.textureRenderTarget.resdsv = resdsv;
7987 resdsv = VK_NULL_HANDLE;
7989 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
7990 shadingRateMapView = VK_NULL_HANDLE;
7994 rhiD->releaseQueue.append(e);
7995 rhiD->unregisterResource(
this);
8005 if (!rhiD->createOffscreenRenderPass(rp,
8006 m_desc.cbeginColorAttachments(),
8007 m_desc.cendColorAttachments(),
8008 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8009 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8010 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8011 m_desc.depthStencilBuffer(),
8012 m_desc.depthTexture(),
8013 m_desc.depthResolveTexture(),
8014 m_desc.shadingRateMap()))
8022 rhiD->registerResource(rp);
8031 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8032 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8033 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8036 QVarLengthArray<VkImageView, 8> views;
8037 d.multiViewCount = 0;
8039 d.colorAttCount = 0;
8041 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8042 d.colorAttCount += 1;
8045 Q_ASSERT(texD || rbD);
8047 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8048 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8049 const bool isMultiView = it->multiViewCount() >= 2;
8050 if (isMultiView && d.multiViewCount == 0)
8051 d.multiViewCount = it->multiViewCount();
8052 VkImageViewCreateInfo viewInfo = {};
8053 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8054 viewInfo.image = texD->image;
8055 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8056 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8057 : VK_IMAGE_VIEW_TYPE_2D);
8058 viewInfo.format = texD->viewFormat;
8059 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8060 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8061 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8062 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8063 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8064 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8065 viewInfo.subresourceRange.levelCount = 1;
8066 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8067 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8068 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8069 if (err != VK_SUCCESS) {
8070 qWarning(
"Failed to create render target image view: %d", err);
8073 views.append(rtv[attIndex]);
8074 if (attIndex == 0) {
8075 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8076 d.sampleCount = texD->samples;
8081 if (attIndex == 0) {
8082 d.pixelSize = rbD->pixelSize();
8083 d.sampleCount = rbD->samples;
8089 if (hasDepthStencil) {
8090 if (m_desc.depthTexture()) {
8093 VkImageViewCreateInfo viewInfo = {};
8094 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8095 viewInfo.image = depthTexD->image;
8096 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8097 viewInfo.format = depthTexD->viewFormat;
8098 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8099 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8100 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8101 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8102 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8103 viewInfo.subresourceRange.levelCount = 1;
8104 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8105 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8106 if (err != VK_SUCCESS) {
8107 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8111 if (d.colorAttCount == 0) {
8112 d.pixelSize = depthTexD->pixelSize();
8113 d.sampleCount = depthTexD->samples;
8117 views.append(depthRbD->imageView);
8118 if (d.colorAttCount == 0) {
8119 d.pixelSize = depthRbD->pixelSize();
8120 d.sampleCount = depthRbD->samples;
8128 d.resolveAttCount = 0;
8130 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8131 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8132 if (it->resolveTexture()) {
8134 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8135 d.resolveAttCount += 1;
8137 VkImageViewCreateInfo viewInfo = {};
8138 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8139 viewInfo.image = resTexD->image;
8140 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8141 : VK_IMAGE_VIEW_TYPE_2D;
8142 viewInfo.format = resTexD->viewFormat;
8143 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8144 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8145 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8146 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8147 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8148 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8149 viewInfo.subresourceRange.levelCount = 1;
8150 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8151 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8152 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8153 if (err != VK_SUCCESS) {
8154 qWarning(
"Failed to create render target resolve image view: %d", err);
8157 views.append(resrtv[attIndex]);
8161 if (m_desc.depthResolveTexture()) {
8163 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8165 VkImageViewCreateInfo viewInfo = {};
8166 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8167 viewInfo.image = resTexD->image;
8168 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8169 : VK_IMAGE_VIEW_TYPE_2D;
8170 viewInfo.format = resTexD->viewFormat;
8171 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8172 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8173 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8174 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8175 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8176 viewInfo.subresourceRange.baseMipLevel = 0;
8177 viewInfo.subresourceRange.levelCount = 1;
8178 viewInfo.subresourceRange.baseArrayLayer = 0;
8179 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8180 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8181 if (err != VK_SUCCESS) {
8182 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8185 views.append(resdsv);
8186 d.dsResolveAttCount = 1;
8188 d.dsResolveAttCount = 0;
8191 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8193 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8195 VkImageViewCreateInfo viewInfo = {};
8196 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8197 viewInfo.image = texD->image;
8198 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8199 : VK_IMAGE_VIEW_TYPE_2D;
8200 viewInfo.format = texD->viewFormat;
8201 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8202 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8203 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8204 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8205 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8206 viewInfo.subresourceRange.baseMipLevel = 0;
8207 viewInfo.subresourceRange.levelCount = 1;
8208 viewInfo.subresourceRange.baseArrayLayer = 0;
8209 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8210 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8211 if (err != VK_SUCCESS) {
8212 qWarning(
"Failed to create render target shading rate map view: %d", err);
8215 views.append(shadingRateMapView);
8216 d.shadingRateAttCount = 1;
8218 d.shadingRateAttCount = 0;
8221 if (!m_renderPassDesc)
8222 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8224 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8225 Q_ASSERT(d.rp && d.rp->rp);
8227 VkFramebufferCreateInfo fbInfo = {};
8228 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8229 fbInfo.renderPass = d.rp->rp;
8230 fbInfo.attachmentCount = uint32_t(views.count());
8231 fbInfo.pAttachments = views.constData();
8232 fbInfo.width = uint32_t(d.pixelSize.width());
8233 fbInfo.height = uint32_t(d.pixelSize.height());
8236 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8237 if (err != VK_SUCCESS) {
8238 qWarning(
"Failed to create framebuffer: %d", err);
8242 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8245 rhiD->registerResource(
this);
8251 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8264 return d.sampleCount;
8282 sortedBindings.clear();
8288 e.shaderResourceBindings.poolIndex =
poolIndex;
8289 e.shaderResourceBindings.layout = layout;
8292 layout = VK_NULL_HANDLE;
8293 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8294 descSets[i] = VK_NULL_HANDLE;
8298 rhiD->releaseQueue.append(e);
8299 rhiD->unregisterResource(
this);
8309 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8312 rhiD->updateLayoutDesc(
this);
8314 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8315 descSets[i] = VK_NULL_HANDLE;
8317 sortedBindings.clear();
8318 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8319 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8322 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8323 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8324 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8325 if (b->u.ubuf.hasDynamicOffset)
8326 hasDynamicOffset =
true;
8330 QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
8331 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8332 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8333 VkDescriptorSetLayoutBinding vkbinding = {};
8334 vkbinding.binding = uint32_t(b->binding);
8335 vkbinding.descriptorType = toVkDescriptorType(b);
8336 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8337 vkbinding.descriptorCount = b->u.stex.count;
8339 vkbinding.descriptorCount = 1;
8340 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8341 vkbindings.append(vkbinding);
8344 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8345 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8346 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8347 layoutInfo.pBindings = vkbindings.constData();
8349 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8350 if (err != VK_SUCCESS) {
8351 qWarning(
"Failed to create descriptor set layout: %d", err);
8355 VkDescriptorSetAllocateInfo allocInfo = {};
8356 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8359 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8360 layouts[i] = layout;
8361 allocInfo.pSetLayouts = layouts;
8362 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8366 boundResourceData[i].resize(sortedBindings.size());
8367 for (BoundResourceData &bd : boundResourceData[i])
8368 memset(&bd, 0,
sizeof(BoundResourceData));
8373 rhiD->registerResource(
this);
8379 sortedBindings.clear();
8380 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8381 if (!flags.testFlag(BindingsAreSorted))
8382 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8394 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8395 for (BoundResourceData &bd : boundResourceData[i])
8396 memset(&bd, 0,
sizeof(BoundResourceData));
8414 if (!pipeline && !layout)
8421 e.pipelineState.pipeline = pipeline;
8422 e.pipelineState.layout = layout;
8424 pipeline = VK_NULL_HANDLE;
8425 layout = VK_NULL_HANDLE;
8429 rhiD->releaseQueue.append(e);
8430 rhiD->unregisterResource(
this);
8440 rhiD->pipelineCreationStart();
8441 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8444 if (!rhiD->ensurePipelineCache())
8447 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8448 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8449 pipelineLayoutInfo.setLayoutCount = 1;
8451 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8452 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8453 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8454 if (err != VK_SUCCESS) {
8455 qWarning(
"Failed to create pipeline layout: %d", err);
8459 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8460 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8462 QVarLengthArray<VkShaderModule, 4> shaders;
8463 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8464 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8465 const QShader bakedShader = shaderStage.shader();
8466 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8467 if (spirv.shader().isEmpty()) {
8468 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8471 VkShaderModule shader = rhiD->createShader(spirv.shader());
8473 shaders.append(shader);
8474 VkPipelineShaderStageCreateInfo shaderInfo = {};
8475 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8476 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8477 shaderInfo.module = shader;
8478 shaderInfo.pName = spirv.entryPoint().constData();
8479 shaderStageCreateInfos.append(shaderInfo);
8482 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8483 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8485 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8486#ifdef VK_EXT_vertex_attribute_divisor
8487 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8489 int bindingIndex = 0;
8490 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8491 it != itEnd; ++it, ++bindingIndex)
8493 VkVertexInputBindingDescription bindingInfo = {
8494 uint32_t(bindingIndex),
8496 it->classification() == QRhiVertexInputBinding::PerVertex
8497 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8499 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8500#ifdef VK_EXT_vertex_attribute_divisor
8501 if (rhiD->caps.vertexAttribDivisor) {
8502 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8506 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8507 "VK_EXT_vertex_attribute_divisor on the device and "
8508 "VK_KHR_get_physical_device_properties2 on the instance");
8511 vertexBindings.append(bindingInfo);
8513 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8514 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8517 VkVertexInputAttributeDescription attributeInfo = {
8518 uint32_t(it->location()),
8519 uint32_t(it->binding()),
8520 toVkAttributeFormat(it->format()),
8523 vertexAttributes.append(attributeInfo);
8525 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8526 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8527 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8528 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8529 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8530 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8531#ifdef VK_EXT_vertex_attribute_divisor
8532 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8533 if (!nonOneStepRates.isEmpty()) {
8534 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8535 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8536 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8537 vertexInputInfo.pNext = &divisorInfo;
8540 pipelineInfo.pVertexInputState = &vertexInputInfo;
8542 QVarLengthArray<VkDynamicState, 8> dynEnable;
8543 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8544 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8545 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8546 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8547 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8548 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8549#ifdef VK_KHR_fragment_shading_rate
8550 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8551 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8554 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8555 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8556 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8557 dynamicInfo.pDynamicStates = dynEnable.constData();
8558 pipelineInfo.pDynamicState = &dynamicInfo;
8560 VkPipelineViewportStateCreateInfo viewportInfo = {};
8561 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8562 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8563 pipelineInfo.pViewportState = &viewportInfo;
8565 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8566 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8567 inputAsmInfo.topology = toVkTopology(m_topology);
8568 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8569 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8571 VkPipelineTessellationStateCreateInfo tessInfo = {};
8572#ifdef VK_VERSION_1_1
8573 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8575 if (m_topology == Patches) {
8576 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8577 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8584#ifdef VK_VERSION_1_1
8585 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8586 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8587 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8588 tessInfo.pNext = &originInfo;
8590 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8593 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8596 pipelineInfo.pTessellationState = &tessInfo;
8599 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8600 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8601 if (m_depthClamp && rhiD->caps.depthClamp)
8602 rastInfo.depthClampEnable = m_depthClamp;
8603 rastInfo.cullMode = toVkCullMode(m_cullMode);
8604 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8605 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8606 rastInfo.depthBiasEnable =
true;
8607 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8608 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8610 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8611 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8612 pipelineInfo.pRasterizationState = &rastInfo;
8614 VkPipelineMultisampleStateCreateInfo msInfo = {};
8615 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8616 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8617 pipelineInfo.pMultisampleState = &msInfo;
8619 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8620 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8621 dsInfo.depthTestEnable = m_depthTest;
8622 dsInfo.depthWriteEnable = m_depthWrite;
8623 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8624 dsInfo.stencilTestEnable = m_stencilTest;
8625 if (m_stencilTest) {
8626 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8627 dsInfo.front.compareMask = m_stencilReadMask;
8628 dsInfo.front.writeMask = m_stencilWriteMask;
8629 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8630 dsInfo.back.compareMask = m_stencilReadMask;
8631 dsInfo.back.writeMask = m_stencilWriteMask;
8633 pipelineInfo.pDepthStencilState = &dsInfo;
8635 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8636 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8637 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8638 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8639 VkPipelineColorBlendAttachmentState blend = {};
8640 blend.blendEnable = b.enable;
8641 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8642 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8643 blend.colorBlendOp = toVkBlendOp(b.opColor);
8644 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8645 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8646 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8647 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8648 vktargetBlends.append(blend);
8650 if (vktargetBlends.isEmpty()) {
8651 VkPipelineColorBlendAttachmentState blend = {};
8652 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8653 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8654 vktargetBlends.append(blend);
8656 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8657 blendInfo.pAttachments = vktargetBlends.constData();
8658 pipelineInfo.pColorBlendState = &blendInfo;
8660 pipelineInfo.layout = layout;
8662 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8663 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8665 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8667 for (VkShaderModule shader : shaders)
8668 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8670 if (err != VK_SUCCESS) {
8671 qWarning(
"Failed to create graphics pipeline: %d", err);
8675 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8677 rhiD->pipelineCreationEnd();
8680 rhiD->registerResource(
this);
8696 if (!pipeline && !layout)
8703 e.pipelineState.pipeline = pipeline;
8704 e.pipelineState.layout = layout;
8706 pipeline = VK_NULL_HANDLE;
8707 layout = VK_NULL_HANDLE;
8711 rhiD->releaseQueue.append(e);
8712 rhiD->unregisterResource(
this);
8722 rhiD->pipelineCreationStart();
8723 if (!rhiD->ensurePipelineCache())
8726 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8727 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8728 pipelineLayoutInfo.setLayoutCount = 1;
8730 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8731 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8732 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8733 if (err != VK_SUCCESS) {
8734 qWarning(
"Failed to create pipeline layout: %d", err);
8738 VkComputePipelineCreateInfo pipelineInfo = {};
8739 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8740 pipelineInfo.layout = layout;
8742 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
8743 qWarning(
"Compute pipeline requires a compute shader stage");
8746 const QShader bakedShader = m_shaderStage.shader();
8747 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
8748 if (spirv.shader().isEmpty()) {
8749 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8752 if (bakedShader.stage() != QShader::ComputeStage) {
8753 qWarning() << bakedShader <<
"is not a compute shader";
8756 VkShaderModule shader = rhiD->createShader(spirv.shader());
8757 VkPipelineShaderStageCreateInfo shaderInfo = {};
8758 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8759 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8760 shaderInfo.module = shader;
8761 shaderInfo.pName = spirv.entryPoint().constData();
8762 pipelineInfo.stage = shaderInfo;
8764 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8765 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8766 if (err != VK_SUCCESS) {
8767 qWarning(
"Failed to create graphics pipeline: %d", err);
8771 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8773 rhiD->pipelineCreationEnd();
8776 rhiD->registerResource(
this);
8805 nativeHandlesStruct.commandBuffer = cb;
8807 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
8808 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
8810 nativeHandlesStruct.commandBuffer = cb;
8813 return &nativeHandlesStruct;
8831 if (sc == VK_NULL_HANDLE)
8836 rhiD->swapchains.remove(
this);
8842 frame.cmdBuf = VK_NULL_HANDLE;
8846 surface = lastConnectedSurface = VK_NULL_HANDLE;
8849 rhiD->unregisterResource(
this);
8864 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
8874 VkSurfaceCapabilitiesKHR surfaceCaps = {};
8876 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
8877 VkExtent2D bufferSize = surfaceCaps.currentExtent;
8878 if (bufferSize.width == uint32_t(-1)) {
8879 Q_ASSERT(bufferSize.height == uint32_t(-1));
8880 return m_window->size() * m_window->devicePixelRatio();
8882 return QSize(
int(bufferSize.width),
int(bufferSize.height));
8888 case QRhiSwapChain::HDRExtendedSrgbLinear:
8889 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8890 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
8891 case QRhiSwapChain::HDR10:
8892 return (s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || s.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32)
8893 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
8894 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
8895 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8896 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
8909 qWarning(
"Attempted to call isFormatSupported() without a window set");
8914 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8917 uint32_t formatCount = 0;
8918 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
8919 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
8921 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
8922 for (uint32_t i = 0; i < formatCount; ++i) {
8923 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
8935 QRHI_RES_RHI(QRhiVulkan);
8937 if (m_window && rhiD->adapterLuidValid)
8938 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
8952 if (!rhiD->createDefaultRenderPass(rp,
8953 m_depthStencil !=
nullptr,
8964 rhiD->registerResource(rp);
8971 case VK_FORMAT_R8_SRGB:
8972 case VK_FORMAT_R8G8_SRGB:
8973 case VK_FORMAT_R8G8B8_SRGB:
8974 case VK_FORMAT_B8G8R8_SRGB:
8975 case VK_FORMAT_R8G8B8A8_SRGB:
8976 case VK_FORMAT_B8G8R8A8_SRGB:
8977 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
8992 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8994 qWarning(
"Failed to get surface for window");
8997 if (surface == surf)
9003 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9004 qWarning(
"Presenting not supported on this window");
9008 quint32 formatCount = 0;
9009 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9010 QList<VkSurfaceFormatKHR> formats(formatCount);
9012 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, formats.data());
9016 const bool srgbRequested = m_flags.testFlag(sRGB);
9017 for (
int i = 0; i <
int(formatCount); ++i) {
9018 if (formats[i].format != VK_FORMAT_UNDEFINED) {
9019 bool ok = srgbRequested == isSrgbFormat(formats[i].format);
9020 if (m_format != SDR)
9021 ok &= hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9023 colorFormat = formats[i].format;
9024 colorSpace = formats[i].colorSpace;
9025#if QT_CONFIG(wayland)
9030 const bool hasPassThrough = std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9031 return fmt.format == colorFormat && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9033 if (hasPassThrough) {
9034 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9042 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9044 quint32 presModeCount = 0;
9045 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9046 supportedPresentationModes.resize(presModeCount);
9047 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9048 supportedPresentationModes.data());
9056 const bool needsRegistration = !window || window != m_window;
9063 if (window && window != m_window)
9067 m_currentPixelSize = surfacePixelSize();
9068 pixelSize = m_currentPixelSize;
9071 qWarning(
"Failed to create new swapchain");
9075 if (needsRegistration || !rhiD->swapchains.contains(
this))
9076 rhiD->swapchains.insert(
this);
9078 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9079 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9080 m_depthStencil->sampleCount(), m_sampleCount);
9082 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9083 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9084 m_depthStencil->setPixelSize(pixelSize);
9085 if (!m_depthStencil->create())
9086 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9087 pixelSize.width(), pixelSize.height());
9089 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9090 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9091 pixelSize.width(), pixelSize.height());
9095 if (!m_renderPassDesc)
9096 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9098 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9099 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9100 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9102 rtWrapper.d.pixelSize = pixelSize;
9103 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9104 rtWrapper.d.sampleCount = samples;
9105 rtWrapper.d.colorAttCount = 1;
9106 if (m_depthStencil) {
9107 rtWrapper.d.dsAttCount = 1;
9108 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9110 rtWrapper.d.dsAttCount = 0;
9113 rtWrapper.d.dsResolveAttCount = 0;
9114 if (samples > VK_SAMPLE_COUNT_1_BIT)
9115 rtWrapper.d.resolveAttCount = 1;
9117 rtWrapper.d.resolveAttCount = 0;
9119 if (shadingRateMapView)
9120 rtWrapper.d.shadingRateAttCount = 1;
9122 rtWrapper.d.shadingRateAttCount = 0;
9127 QVarLengthArray<VkImageView, 4> views;
9128 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9130 views.append(
ds->imageView);
9131 if (samples > VK_SAMPLE_COUNT_1_BIT)
9132 views.append(image.imageView);
9133 if (shadingRateMapView)
9134 views.append(shadingRateMapView);
9136 VkFramebufferCreateInfo fbInfo = {};
9137 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9138 fbInfo.renderPass = rtWrapper.d.rp->rp;
9139 fbInfo.attachmentCount = uint32_t(views.count());
9140 fbInfo.pAttachments = views.constData();
9141 fbInfo.width = uint32_t(pixelSize.width());
9142 fbInfo.height = uint32_t(pixelSize.height());
9145 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9146 if (err != VK_SUCCESS) {
9147 qWarning(
"Failed to create framebuffer: %d", err);
9153 rtWrapperRight.setRenderPassDescriptor(
9155 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9156 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9158 rtWrapperRight.d.pixelSize = pixelSize;
9159 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9160 rtWrapperRight.d.sampleCount = samples;
9161 rtWrapperRight.d.colorAttCount = 1;
9162 if (m_depthStencil) {
9163 rtWrapperRight.d.dsAttCount = 1;
9164 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9166 rtWrapperRight.d.dsAttCount = 0;
9169 rtWrapperRight.d.dsResolveAttCount = 0;
9170 if (samples > VK_SAMPLE_COUNT_1_BIT)
9171 rtWrapperRight.d.resolveAttCount = 1;
9173 rtWrapperRight.d.resolveAttCount = 0;
9178 QVarLengthArray<VkImageView, 4> views;
9179 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9181 views.append(
ds->imageView);
9182 if (samples > VK_SAMPLE_COUNT_1_BIT)
9183 views.append(image.imageView);
9184 if (shadingRateMapView)
9185 views.append(shadingRateMapView);
9187 VkFramebufferCreateInfo fbInfo = {};
9188 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9189 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9190 fbInfo.attachmentCount = uint32_t(views.count());
9191 fbInfo.pAttachments = views.constData();
9192 fbInfo.width = uint32_t(pixelSize.width());
9193 fbInfo.height = uint32_t(pixelSize.height());
9196 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9197 if (err != VK_SUCCESS) {
9198 qWarning(
"Failed to create framebuffer: %d", err);
9206 if (needsRegistration)
9207 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
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, QRhiShadingRateMap *shadingRateMap)
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
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)
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)
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 activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD)
void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
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)