6#include <qpa/qplatformvulkaninstance.h>
8#define VMA_IMPLEMENTATION
9#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
10#define VMA_STATIC_VULKAN_FUNCTIONS 0
11#define VMA_RECORDING_ENABLED 0
12#define VMA_DEDICATED_ALLOCATION 0
14Q_STATIC_LOGGING_CATEGORY(QRHI_LOG_VMA,
"qt.rhi.vma")
16#define VMA_ASSERT(expr) Q_ASSERT(expr)
18#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1
19#define VMA_DEBUG_LOG(str) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), (str))
20#define VMA_DEBUG_LOG_FORMAT(format, ...) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, __VA_ARGS__)
22template<
typename... Args>
23static void debugVmaLeak(
const char *format, Args&&... args)
27 static bool leakCheck =
true;
30 static bool leakCheck = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)(
"QT_RHI_LEAK_CHECK");
33 QT_PREPEND_NAMESPACE(qWarning)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, std::forward<Args>(args)...);
35#define VMA_LEAK_LOG_FORMAT(format, ...) debugVmaLeak(format, __VA_ARGS__)
37QT_WARNING_DISABLE_GCC(
"-Wsuggest-override")
38QT_WARNING_DISABLE_GCC(
"-Wundef")
39QT_WARNING_DISABLE_CLANG(
"-Wundef")
40#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1100
41QT_WARNING_DISABLE_CLANG(
"-Wdeprecated-copy")
43#include "vk_mem_alloc.h"
47#include <QVulkanFunctions>
48#include <QtGui/qwindow.h>
49#include <private/qvulkandefaultinstance_p.h>
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
82
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
193
196
197
198
199
200
203
204
205
206
209
210
211
212
213
217
218
219
220
221
222
223
224
225
226
229
230
231
232
235
236
237
238
239
242
243
244
245
248
249
250
251
254
255
256
257
258
261
262
263
264
265
268
269
270
271
272
276
277
278
279
280
281
282
283
284
285
286
287
288
289
292
293
294
295
299
300
301
302
303
304
305
306
309
310
311
312
316
317
318
319
320
321
322
325
326
327
328
329
330
333
334
335
336
337
338
341
342
343
344
345
346
349
350
351
352
353
354
357
358
359
360
361
362
365
366
367
368
369
370
373inline Int aligned(Int v, Int byteAlign)
375 return (v + byteAlign - 1) & ~(byteAlign - 1);
380static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
382 return globalVulkanInstance->getInstanceProcAddr(pName);
385static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
387 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
392 return reinterpret_cast<VmaAllocation>(a);
397 return reinterpret_cast<VmaAllocator>(a);
401
402
403
404
405
406
407QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
410 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"),
412 QByteArrayLiteral(
"VK_EXT_swapchain_colorspace")
417
418
419
420
421QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
424 QByteArrayLiteral(
"VK_KHR_swapchain"),
425 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
426 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
427 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
428 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
441 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
442 inst = QVulkanDefaultInstance::instance();
446 requestedDeviceExtensions = params->deviceExtensions;
449 physDev = importParams->physDev;
450 dev = importParams->dev;
451 if (dev && physDev) {
453 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
454 gfxQueueIdx = importParams->gfxQueueIdx;
456 if (importParams->vmemAllocator) {
465 QVulkanInstance::DebugMessageTypeFlags type,
466 const void *callbackData)
470#ifdef VK_EXT_debug_utils
471 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
475 if (strstr(d->pMessage,
"Mapping an image with layout")
476 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
487 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
490 Q_UNUSED(callbackData);
498 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
499 return QRhiDriverInfo::UnknownDevice;
500 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
501 return QRhiDriverInfo::IntegratedDevice;
502 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
503 return QRhiDriverInfo::DiscreteDevice;
504 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
505 return QRhiDriverInfo::VirtualDevice;
506 case VK_PHYSICAL_DEVICE_TYPE_CPU:
507 return QRhiDriverInfo::CpuDevice;
509 return QRhiDriverInfo::UnknownDevice;
513static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
515 info->deviceName = QByteArray(physDevProperties.deviceName);
516 info->deviceId = physDevProperties.deviceID;
517 info->vendorId = physDevProperties.vendorID;
518 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
524 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
526 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
532 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
538 if (!inst->isValid()) {
539 qWarning(
"Vulkan instance is not valid");
544 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
546 globalVulkanInstance = inst;
547 f = inst->functions();
548 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
549 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
550 const QByteArrayList extensions = inst->extensions();
551 for (
const char *ext : extensions)
552 qCDebug(QRHI_LOG_INFO,
" %s", ext);
556 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
558 QList<VkQueueFamilyProperties> queueFamilyProps;
559 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
560 uint32_t queueCount = 0;
561 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
562 queueFamilyProps.resize(
int(queueCount));
563 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
568 uint32_t physDevCount = 0;
569 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
571 qWarning(
"No physical devices");
574 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
575 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
576 if (err != VK_SUCCESS || !physDevCount) {
577 qWarning(
"Failed to enumerate physical devices: %d", err);
581 int physDevIndex = -1;
582 int requestedPhysDevIndex = -1;
583 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
584 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
586 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
587 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
588 for (
int i = 0; i <
int(physDevCount); ++i) {
589 if (physDevs[i] == requestedPhysDev) {
590 requestedPhysDevIndex = i;
596 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
597 for (
int i = 0; i <
int(physDevCount); ++i) {
598 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
599 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
600 requestedPhysDevIndex = i;
606 for (
int i = 0; i <
int(physDevCount); ++i) {
607 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
608 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
610 physDevProperties.deviceName,
611 VK_VERSION_MAJOR(physDevProperties.driverVersion),
612 VK_VERSION_MINOR(physDevProperties.driverVersion),
613 VK_VERSION_PATCH(physDevProperties.driverVersion),
614 VK_VERSION_MAJOR(physDevProperties.apiVersion),
615 VK_VERSION_MINOR(physDevProperties.apiVersion),
616 VK_VERSION_PATCH(physDevProperties.apiVersion),
617 physDevProperties.vendorID,
618 physDevProperties.deviceID,
619 physDevProperties.deviceType);
620 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
622 qCDebug(QRHI_LOG_INFO,
" using this physical device");
626 if (physDevIndex < 0) {
627 qWarning(
"No matching physical device");
630 physDev = physDevs[physDevIndex];
631 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
633 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
634 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
635 physDevProperties.deviceName,
636 VK_VERSION_MAJOR(physDevProperties.driverVersion),
637 VK_VERSION_MINOR(physDevProperties.driverVersion),
638 VK_VERSION_PATCH(physDevProperties.driverVersion),
639 VK_VERSION_MAJOR(physDevProperties.apiVersion),
640 VK_VERSION_MINOR(physDevProperties.apiVersion),
641 VK_VERSION_PATCH(physDevProperties.apiVersion),
642 physDevProperties.vendorID,
643 physDevProperties.deviceID,
644 physDevProperties.deviceType);
647 caps.apiVersion = inst->apiVersion();
653 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
654 VK_VERSION_MINOR(physDevProperties.apiVersion));
655 if (physDevApiVersion < caps.apiVersion) {
656 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
657 <<
"whereas the chosen physical device has" << physDevApiVersion
658 <<
"- restricting to the latter";
659 caps.apiVersion = physDevApiVersion;
664 QVulkanInfoVector<QVulkanExtension> devExts;
665 uint32_t devExtCount = 0;
666 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
668 QList<VkExtensionProperties> extProps(devExtCount);
669 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
670 for (
const VkExtensionProperties &p : std::as_const(extProps))
671 devExts.append({ p.extensionName, p.specVersion });
673 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
675 bool featuresQueried =
false;
677 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
678 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
681#ifdef VK_KHR_fragment_shading_rate
682 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
683 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
684 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
685 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
687#ifdef VK_EXT_device_fault
688 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
689 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
690 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
691 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
697 if (!featuresQueried) {
699 if (caps.apiVersion >= QVersionNumber(1, 2)) {
700 physDevFeatures11IfApi12OrNewer = {};
701 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
702 physDevFeatures12 = {};
703 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
705 physDevFeatures13 = {};
706 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
708 physDevFeatures14 = {};
709 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
712 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
713 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
715 if (caps.apiVersion >= QVersionNumber(1, 3))
716 physDevFeatures12.pNext = &physDevFeatures13;
718 if (caps.apiVersion >= QVersionNumber(1, 4))
719 physDevFeatures13.pNext = &physDevFeatures14;
722 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
723 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
724 featuresQueried =
true;
731 if (!featuresQueried) {
739 if (caps.apiVersion == QVersionNumber(1, 1)) {
741 multiviewFeaturesIfApi11 = {};
742 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
743 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
746 shaderDrawParametersFeaturesIfApi11 = {};
747 shaderDrawParametersFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
748 addToChain(&physDevFeaturesChainable, &shaderDrawParametersFeaturesIfApi11);
750 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
751 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
752 featuresQueried =
true;
757 if (!featuresQueried) {
760 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
761 featuresQueried =
true;
769 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
770 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
771 queryQueueFamilyProps();
772 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
773 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
774 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
775 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
776 if (!gfxQueueFamilyIdxOpt.has_value()
777 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
778 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
780 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
781 gfxQueueFamilyIdxOpt = i;
782 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
783 computelessGfxQueueCandidateIdxOpt = i;
786 if (gfxQueueFamilyIdxOpt.has_value()) {
787 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
789 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
790 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
792 qWarning(
"No graphics (or no graphics+present) queue family found");
797 VkDeviceQueueCreateInfo queueInfo = {};
798 const float prio[] = { 0 };
799 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
800 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
801 queueInfo.queueCount = 1;
802 queueInfo.pQueuePriorities = prio;
804 QList<
const char *> devLayers;
805 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
806 devLayers.append(
"VK_LAYER_KHRONOS_validation");
808 QList<
const char *> requestedDevExts;
809 requestedDevExts.append(
"VK_KHR_swapchain");
811 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
813 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
814 if (hasPhysDevProp2) {
815 requestedDevExts.append(
"VK_KHR_portability_subset");
817 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
818 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
823#ifdef VK_EXT_vertex_attribute_divisor
824 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
825 if (hasPhysDevProp2) {
826 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
827 caps.vertexAttribDivisor =
true;
832#ifdef VK_KHR_create_renderpass2
833 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
834 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
835 caps.renderPass2KHR =
true;
839#ifdef VK_KHR_depth_stencil_resolve
840 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
841 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
842 caps.depthStencilResolveKHR =
true;
846#ifdef VK_KHR_fragment_shading_rate
847 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
848 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
851#ifdef VK_EXT_device_fault
852 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
853 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
854 caps.deviceFault =
true;
858 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
859 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
860 if (devExts.contains(ext)) {
861 requestedDevExts.append(ext.constData());
863 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
869 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
870 for (
const QByteArray &ext : envExtList) {
871 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
872 if (devExts.contains(ext)) {
873 requestedDevExts.append(ext.constData());
875 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
881 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
882 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
883 for (
const char *ext : std::as_const(requestedDevExts))
884 qCDebug(QRHI_LOG_INFO,
" %s", ext);
887 VkDeviceCreateInfo devInfo = {};
888 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
889 devInfo.queueCreateInfoCount = 1;
890 devInfo.pQueueCreateInfos = &queueInfo;
891 devInfo.enabledLayerCount = uint32_t(devLayers.size());
892 devInfo.ppEnabledLayerNames = devLayers.constData();
893 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
894 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
910 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
913 physDevFeatures13.robustImageAccess = VK_FALSE;
917 if (caps.apiVersion >= QVersionNumber(1, 1)) {
924 devInfo.pNext = &physDevFeaturesChainable;
928 physDevFeatures.robustBufferAccess = VK_FALSE;
929 devInfo.pEnabledFeatures = &physDevFeatures;
932 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
933 if (err != VK_SUCCESS) {
934 qWarning(
"Failed to create device: %d", err);
938 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
943 caps.deviceFault =
true;
944 caps.vertexAttribDivisor =
true;
945 caps.renderPass2KHR =
true;
946 caps.depthStencilResolveKHR =
true;
949 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
950 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
951 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
952 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
953 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
954 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
956 df = inst->deviceFunctions(dev);
958 VkCommandPoolCreateInfo poolInfo = {};
959 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
960 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
962 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
963 if (err != VK_SUCCESS) {
964 qWarning(
"Failed to create command pool: %d", err);
969 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
970 gfxQueueFamilyIdx, gfxQueueIdx);
972 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
974 if (queueFamilyProps.isEmpty())
975 queryQueueFamilyProps();
977 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
978 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
980 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
983 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
985 caps.depthClamp = physDevFeatures.depthClamp;
987 caps.wideLines = physDevFeatures.wideLines;
989 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
991 caps.tessellation = physDevFeatures.tessellationShader;
992 caps.geometryShader = physDevFeatures.geometryShader;
994 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
996 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
999 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1000 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1001 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
1005#ifdef VK_VERSION_1_1
1006 if (caps.apiVersion == QVersionNumber(1, 1)) {
1007 caps.multiView = multiviewFeaturesIfApi11.multiview;
1008 caps.shaderDrawParameters = shaderDrawParametersFeaturesIfApi11.shaderDrawParameters;
1012#ifdef VK_KHR_fragment_shading_rate
1013 fragmentShadingRates.clear();
1014 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1015 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1016 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1017 if (caps.imageBasedShadingRate) {
1018 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1019 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1020 VkPhysicalDeviceProperties2 props2 = {};
1021 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1022 props2.pNext = &shadingRateProps;
1023 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1024 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1027 if (caps.perDrawShadingRate) {
1028 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1029 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1030 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1031 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1033 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1034 fragmentShadingRates.resize(count);
1035 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1037 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1039 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1041 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1042 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1051#ifdef VK_KHR_create_renderpass2
1052 if (caps.renderPass2KHR) {
1053 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1054 if (!vkCreateRenderPass2KHR)
1055 caps.renderPass2KHR =
false;
1061 adapterLuidValid =
false;
1063#ifdef VK_VERSION_1_2
1064 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1065 VkPhysicalDeviceVulkan11Properties v11props = {};
1066 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1067 VkPhysicalDeviceProperties2 props2 = {};
1068 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1069 props2.pNext = &v11props;
1070 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1071 if (v11props.deviceLUIDValid) {
1072 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1073 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1074 adapterLuidValid =
true;
1075 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1076 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1077 adapterLuid.LowPart, adapterLuid.HighPart);
1084 VmaVulkanFunctions funcs = {};
1085 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1086 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1088 VmaAllocatorCreateInfo allocatorInfo = {};
1091 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1092 allocatorInfo.physicalDevice = physDev;
1093 allocatorInfo.device = dev;
1094 allocatorInfo.pVulkanFunctions = &funcs;
1095 allocatorInfo.instance = inst->vkInstance();
1103#ifdef VK_VERSION_1_4
1104 if (caps.apiVersion >= QVersionNumber(1, 4))
1105 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1108#ifdef VK_VERSION_1_3
1109 if (caps.apiVersion >= QVersionNumber(1, 3))
1110 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1113#ifdef VK_VERSION_1_2
1114 if (caps.apiVersion >= QVersionNumber(1, 2))
1115 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1118#ifdef VK_VERSION_1_1
1119 if (caps.apiVersion >= QVersionNumber(1, 1))
1120 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1123#ifdef VK_VERSION_1_0
1124 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1127 VmaAllocator vmaallocator;
1128 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1129 if (err != VK_SUCCESS) {
1130 qWarning(
"Failed to create allocator: %d", err);
1136 inst->installDebugOutputFilter(qvk_debug_filter);
1138 VkDescriptorPool pool;
1139 VkResult err = createDescriptorPool(&pool);
1140 if (err == VK_SUCCESS)
1141 descriptorPools.append(pool);
1143 qWarning(
"Failed to create initial descriptor pool: %d", err);
1145 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1146 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1147 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1149 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1150 if (err != VK_SUCCESS) {
1151 qWarning(
"Failed to create timestamp query pool: %d", err);
1154 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1155 timestampQueryPoolMap.fill(
false);
1157#ifdef VK_EXT_debug_utils
1158 if (caps.debugUtils) {
1159 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1160 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1161 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1162 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1166#ifdef VK_EXT_device_fault
1167 if (caps.deviceFault) {
1168 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1174 nativeHandlesStruct.physDev = physDev;
1175 nativeHandlesStruct.dev = dev;
1176 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1177 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1178 nativeHandlesStruct.gfxQueue = gfxQueue;
1179 nativeHandlesStruct.vmemAllocator = allocator;
1180 nativeHandlesStruct.inst = inst;
1191 df->vkDeviceWaitIdle(dev);
1198 dxgiHdrInfo =
nullptr;
1202 if (ofr.cmdFence[i]) {
1203 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1204 ofr.cmdFence[i] = VK_NULL_HANDLE;
1206 ofr.cmdFenceWaitable[i] =
false;
1209 if (pipelineCache) {
1210 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1211 pipelineCache = VK_NULL_HANDLE;
1214 for (
const DescriptorPoolData &pool : descriptorPools)
1215 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1217 descriptorPools.clear();
1219 if (timestampQueryPool) {
1220 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1221 timestampQueryPool = VK_NULL_HANDLE;
1225 vmaDestroyAllocator(toVmaAllocator(allocator));
1231 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1232 cmdPool[i] = VK_NULL_HANDLE;
1234 freeSecondaryCbs[i].clear();
1235 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1238 if (!importedDevice && dev) {
1239 df->vkDestroyDevice(dev,
nullptr);
1240 inst->resetDeviceFunctions(dev);
1241 dev = VK_NULL_HANDLE;
1251QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1253 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1254 if (nativeHandles) {
1255 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1256 requestedPhysDev = h->physDev;
1259 QRhi::AdapterList list;
1260 QVulkanFunctions *f = inst->functions();
1261 uint32_t physDevCount = 0;
1262 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1266 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1267 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1268 if (err != VK_SUCCESS || !physDevCount)
1271 VkPhysicalDeviceProperties physDevProperties = {};
1272 for (uint32_t i = 0; i < physDevCount; ++i) {
1273 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1276 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1277 QVulkanAdapter *a =
new QVulkanAdapter;
1278 a->physDev = physDevs[i];
1279 fillDriverInfo(&a->adapterInfo, physDevProperties);
1293 VkDescriptorPoolSize descPoolSizes[] = {
1294 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1295 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1296 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1297 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1298 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1299 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1300 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1302 VkDescriptorPoolCreateInfo descPoolInfo = {};
1303 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1307 descPoolInfo.flags = 0;
1309 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1310 descPoolInfo.pPoolSizes = descPoolSizes;
1311 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1316 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1317 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1318 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1319 if (r == VK_SUCCESS)
1320 descriptorPools[poolIndex].refCount += 1;
1324 int lastPoolIdx = descriptorPools.size() - 1;
1325 for (
int i = lastPoolIdx; i >= 0; --i) {
1326 if (descriptorPools[i].refCount == 0) {
1327 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1328 descriptorPools[i].allocedDescSets = 0;
1330 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1331 VkResult err = tryAllocate(i);
1332 if (err == VK_SUCCESS) {
1333 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1334 *resultPoolIndex = i;
1340 VkDescriptorPool newPool;
1341 VkResult poolErr = createDescriptorPool(&newPool);
1342 if (poolErr == VK_SUCCESS) {
1343 descriptorPools.append(newPool);
1344 lastPoolIdx = descriptorPools.size() - 1;
1345 VkResult err = tryAllocate(lastPoolIdx);
1346 if (err != VK_SUCCESS) {
1347 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1350 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1351 *resultPoolIndex = lastPoolIdx;
1354 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1361 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1363 case QRhiTexture::RGBA8:
1364 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1365 case QRhiTexture::BGRA8:
1366 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1367 case QRhiTexture::R8:
1368 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1369 case QRhiTexture::RG8:
1370 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1371 case QRhiTexture::R16:
1372 return VK_FORMAT_R16_UNORM;
1373 case QRhiTexture::RG16:
1374 return VK_FORMAT_R16G16_UNORM;
1375 case QRhiTexture::RED_OR_ALPHA8:
1376 return VK_FORMAT_R8_UNORM;
1378 case QRhiTexture::RGBA16F:
1379 return VK_FORMAT_R16G16B16A16_SFLOAT;
1380 case QRhiTexture::RGBA32F:
1381 return VK_FORMAT_R32G32B32A32_SFLOAT;
1382 case QRhiTexture::R16F:
1383 return VK_FORMAT_R16_SFLOAT;
1384 case QRhiTexture::R32F:
1385 return VK_FORMAT_R32_SFLOAT;
1387 case QRhiTexture::RGB10A2:
1389 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1391 case QRhiTexture::R8SI:
1392 return VK_FORMAT_R8_SINT;
1393 case QRhiTexture::R32SI:
1394 return VK_FORMAT_R32_SINT;
1395 case QRhiTexture::RG32SI:
1396 return VK_FORMAT_R32G32_SINT;
1397 case QRhiTexture::RGBA32SI:
1398 return VK_FORMAT_R32G32B32A32_SINT;
1400 case QRhiTexture::R8UI:
1401 return VK_FORMAT_R8_UINT;
1402 case QRhiTexture::R32UI:
1403 return VK_FORMAT_R32_UINT;
1404 case QRhiTexture::RG32UI:
1405 return VK_FORMAT_R32G32_UINT;
1406 case QRhiTexture::RGBA32UI:
1407 return VK_FORMAT_R32G32B32A32_UINT;
1409 case QRhiTexture::D16:
1410 return VK_FORMAT_D16_UNORM;
1411 case QRhiTexture::D24:
1412 return VK_FORMAT_X8_D24_UNORM_PACK32;
1413 case QRhiTexture::D24S8:
1414 return VK_FORMAT_D24_UNORM_S8_UINT;
1415 case QRhiTexture::D32F:
1416 return VK_FORMAT_D32_SFLOAT;
1417 case QRhiTexture::D32FS8:
1418 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1420 case QRhiTexture::BC1:
1421 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1422 case QRhiTexture::BC2:
1423 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1424 case QRhiTexture::BC3:
1425 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1426 case QRhiTexture::BC4:
1427 return VK_FORMAT_BC4_UNORM_BLOCK;
1428 case QRhiTexture::BC5:
1429 return VK_FORMAT_BC5_UNORM_BLOCK;
1430 case QRhiTexture::BC6H:
1431 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1432 case QRhiTexture::BC7:
1433 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1435 case QRhiTexture::ETC2_RGB8:
1436 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1437 case QRhiTexture::ETC2_RGB8A1:
1438 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1439 case QRhiTexture::ETC2_RGBA8:
1440 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1442 case QRhiTexture::ASTC_4x4:
1443 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1444 case QRhiTexture::ASTC_5x4:
1445 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1446 case QRhiTexture::ASTC_5x5:
1447 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1448 case QRhiTexture::ASTC_6x5:
1449 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1450 case QRhiTexture::ASTC_6x6:
1451 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1452 case QRhiTexture::ASTC_8x5:
1453 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1454 case QRhiTexture::ASTC_8x6:
1455 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1456 case QRhiTexture::ASTC_8x8:
1457 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1458 case QRhiTexture::ASTC_10x5:
1459 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1460 case QRhiTexture::ASTC_10x6:
1461 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1462 case QRhiTexture::ASTC_10x8:
1463 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1464 case QRhiTexture::ASTC_10x10:
1465 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1466 case QRhiTexture::ASTC_12x10:
1467 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1468 case QRhiTexture::ASTC_12x12:
1469 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1472 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1479 case VK_FORMAT_R8G8B8A8_UNORM:
1480 return QRhiTexture::RGBA8;
1481 case VK_FORMAT_R8G8B8A8_SRGB:
1483 (*flags) |= QRhiTexture::sRGB;
1484 return QRhiTexture::RGBA8;
1485 case VK_FORMAT_B8G8R8A8_UNORM:
1486 return QRhiTexture::BGRA8;
1487 case VK_FORMAT_B8G8R8A8_SRGB:
1489 (*flags) |= QRhiTexture::sRGB;
1490 return QRhiTexture::BGRA8;
1491 case VK_FORMAT_R16G16B16A16_SFLOAT:
1492 return QRhiTexture::RGBA16F;
1493 case VK_FORMAT_R32G32B32A32_SFLOAT:
1494 return QRhiTexture::RGBA32F;
1495 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1496 return QRhiTexture::RGB10A2;
1498 qWarning(
"VkFormat %d cannot be read back", format);
1501 return QRhiTexture::UnknownFormat;
1507 case QRhiTexture::Format::D16:
1508 case QRhiTexture::Format::D24:
1509 case QRhiTexture::Format::D24S8:
1510 case QRhiTexture::Format::D32F:
1511 case QRhiTexture::Format::D32FS8:
1522 case QRhiTexture::Format::D24S8:
1523 case QRhiTexture::Format::D32FS8:
1533 if (isDepthTextureFormat(format)) {
1534 if (isStencilTextureFormat(format))
1535 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1537 return VK_IMAGE_ASPECT_DEPTH_BIT;
1539 return VK_IMAGE_ASPECT_COLOR_BIT;
1550 VkPhysicalDeviceMemoryProperties physDevMemProps;
1551 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1553 VkMemoryRequirements memReq;
1554 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1555 uint32_t memTypeIndex = uint32_t(-1);
1557 if (memReq.memoryTypeBits) {
1559 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1560 bool foundDevLocal =
false;
1561 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1562 if (memReq.memoryTypeBits & (1 << i)) {
1563 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1564 if (!foundDevLocal) {
1565 foundDevLocal =
true;
1568 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1577 return memTypeIndex;
1581 const QSize &pixelSize,
1582 VkImageUsageFlags usage,
1583 VkImageAspectFlags aspectMask,
1584 VkSampleCountFlagBits samples,
1585 VkDeviceMemory *mem,
1590 VkMemoryRequirements memReq;
1593 *mem = VK_NULL_HANDLE;
1594 for (
int i = 0; i < count; ++i) {
1595 images[i] = VK_NULL_HANDLE;
1596 views[i] = VK_NULL_HANDLE;
1599 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1600 for (
int i = 0; i < count; ++i) {
1602 df->vkDestroyImageView(dev, views[i],
nullptr);
1603 views[i] = VK_NULL_HANDLE;
1606 df->vkDestroyImage(dev, images[i],
nullptr);
1607 images[i] = VK_NULL_HANDLE;
1611 df->vkFreeMemory(dev, *mem,
nullptr);
1612 *mem = VK_NULL_HANDLE;
1616 for (
int i = 0; i < count; ++i) {
1617 VkImageCreateInfo imgInfo = {};
1618 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1619 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1620 imgInfo.format = format;
1621 imgInfo.extent.width = uint32_t(pixelSize.width());
1622 imgInfo.extent.height = uint32_t(pixelSize.height());
1623 imgInfo.extent.depth = 1;
1624 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1625 imgInfo.samples = samples;
1626 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1627 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1628 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1630 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1631 if (err != VK_SUCCESS) {
1632 qWarning(
"Failed to create image: %d", err);
1639 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1642 VkMemoryAllocateInfo memInfo = {};
1643 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1644 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1646 uint32_t startIndex = 0;
1648 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1649 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1650 qWarning(
"No suitable memory type found");
1653 startIndex = memInfo.memoryTypeIndex + 1;
1654 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1655 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1656 qWarning(
"Failed to allocate image memory: %d", err);
1659 }
while (err != VK_SUCCESS);
1661 VkDeviceSize ofs = 0;
1662 for (
int i = 0; i < count; ++i) {
1663 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1664 if (err != VK_SUCCESS) {
1665 qWarning(
"Failed to bind image memory: %d", err);
1668 ofs += aligned(memReq.size, memReq.alignment);
1670 VkImageViewCreateInfo imgViewInfo = {};
1671 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1672 imgViewInfo.image = images[i];
1673 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1674 imgViewInfo.format = format;
1675 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1676 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1677 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1678 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1679 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1680 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1682 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1683 if (err != VK_SUCCESS) {
1684 qWarning(
"Failed to create image view: %d", err);
1695 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1696 return optimalDsFormat;
1698 const VkFormat dsFormatCandidates[] = {
1699 VK_FORMAT_D24_UNORM_S8_UINT,
1700 VK_FORMAT_D32_SFLOAT_S8_UINT,
1701 VK_FORMAT_D16_UNORM_S8_UINT
1703 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1704 int dsFormatIdx = 0;
1705 while (dsFormatIdx < dsFormatCandidateCount) {
1706 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1707 VkFormatProperties fmtProp;
1708 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1709 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1713 if (dsFormatIdx == dsFormatCandidateCount)
1714 qWarning(
"Failed to find an optimal depth-stencil format");
1716 return optimalDsFormat;
1721 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1723 if (multiViewCount < 2)
1725 if (!multiViewCap) {
1726 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1729#ifdef VK_VERSION_1_1
1730 uint32_t allViewsMask = 0;
1731 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1732 allViewsMask |= (1 << i);
1733 multiViewMask = allViewsMask;
1734 multiViewCorrelationMask = allViewsMask;
1735 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1736 multiViewInfo.subpassCount = 1;
1737 multiViewInfo.pViewMasks = &multiViewMask;
1738 multiViewInfo.correlationMaskCount = 1;
1739 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1740 rpInfo->pNext = &multiViewInfo;
1745#ifdef VK_VERSION_1_1
1752#ifdef VK_KHR_create_renderpass2
1756struct RenderPass2SetupHelper
1758 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1760 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1764 if (multiViewCount >= 2) {
1765 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1766 viewMask |= (1 << i);
1769 attDescs2.resize(rpInfo->attachmentCount);
1770 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1771 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1772 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1774 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1775 att2.flags = att.flags;
1776 att2.format = att.format;
1777 att2.samples = att.samples;
1778 att2.loadOp = att.loadOp;
1779 att2.storeOp = att.storeOp;
1780 att2.stencilLoadOp = att.stencilLoadOp;
1781 att2.stencilStoreOp = att.stencilStoreOp;
1782 att2.initialLayout = att.initialLayout;
1783 att2.finalLayout = att.finalLayout;
1788 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1789 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1790 subpass2.flags = subpassDesc.flags;
1791 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1792 if (multiViewCount >= 2)
1793 subpass2.viewMask = viewMask;
1796 qsizetype startIndex = attRefs2.count();
1797 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1798 attRefs2.append({});
1799 VkAttachmentReference2KHR &attref2(attRefs2.last());
1800 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1801 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1802 attref2.attachment = attref.attachment;
1803 attref2.layout = attref.layout;
1804 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1806 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1807 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1810 if (subpassDesc.pResolveAttachments) {
1811 startIndex = attRefs2.count();
1812 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1813 attRefs2.append({});
1814 VkAttachmentReference2KHR &attref2(attRefs2.last());
1815 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1816 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1817 attref2.attachment = attref.attachment;
1818 attref2.layout = attref.layout;
1819 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1821 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1825 if (subpassDesc.pDepthStencilAttachment) {
1826 startIndex = attRefs2.count();
1827 attRefs2.append({});
1828 VkAttachmentReference2KHR &attref2(attRefs2.last());
1829 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1830 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1831 attref2.attachment = attref.attachment;
1832 attref2.layout = attref.layout;
1833 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1834 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1838#ifdef VK_KHR_depth_stencil_resolve
1840 if (rpD->hasDepthStencilResolve) {
1841 startIndex = attRefs2.count();
1842 attRefs2.append({});
1843 VkAttachmentReference2KHR &attref2(attRefs2.last());
1844 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1845 attref2.attachment = rpD->dsResolveRef.attachment;
1846 attref2.layout = rpD->dsResolveRef.layout;
1847 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1848 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1849 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1850 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1851 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1852 addToChain(&subpass2, &dsResolveDesc);
1856#ifdef VK_KHR_fragment_shading_rate
1857 shadingRateAttInfo = {};
1858 if (rpD->hasShadingRateMap) {
1859 startIndex = attRefs2.count();
1860 attRefs2.append({});
1861 VkAttachmentReference2KHR &attref2(attRefs2.last());
1862 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1863 attref2.attachment = rpD->shadingRateRef.attachment;
1864 attref2.layout = rpD->shadingRateRef.layout;
1865 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1866 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1867 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1868 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1869 addToChain(&subpass2, &shadingRateAttInfo);
1875 subpassDeps2.clear();
1876 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1877 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1878 subpassDeps2.append({});
1879 VkSubpassDependency2 &dep2(subpassDeps2.last());
1880 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1881 dep2.srcSubpass = dep.srcSubpass;
1882 dep2.dstSubpass = dep.dstSubpass;
1883 dep2.srcStageMask = dep.srcStageMask;
1884 dep2.dstStageMask = dep.dstStageMask;
1885 dep2.srcAccessMask = dep.srcAccessMask;
1886 dep2.dstAccessMask = dep.dstAccessMask;
1887 dep2.dependencyFlags = dep.dependencyFlags;
1890 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1891 rpInfo2->pNext =
nullptr;
1892 rpInfo2->flags = rpInfo->flags;
1893 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1894 rpInfo2->pAttachments = attDescs2.constData();
1895 rpInfo2->subpassCount = 1;
1896 rpInfo2->pSubpasses = &subpass2;
1897 rpInfo2->dependencyCount = subpassDeps2.count();
1898 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1899 if (multiViewCount >= 2) {
1900 rpInfo2->correlatedViewMaskCount = 1;
1901 rpInfo2->pCorrelatedViewMasks = &viewMask;
1907 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1908 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1909 VkSubpassDescription2KHR subpass2;
1910 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1911#ifdef VK_KHR_depth_stencil_resolve
1912 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1914#ifdef VK_KHR_fragment_shading_rate
1915 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1922 VkSubpassDescription *subpassDesc,
1925 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1926 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1927 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1928 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1929 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1930 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1932 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1933 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1934 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1935 rpInfo->pAttachments = rpD->attDescs.constData();
1936 rpInfo->subpassCount = 1;
1937 rpInfo->pSubpasses = subpassDesc;
1938 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1939 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1943 bool hasDepthStencil,
1944 VkSampleCountFlagBits samples,
1945 VkFormat colorFormat,
1946 QRhiShadingRateMap *shadingRateMap)
1950 VkAttachmentDescription attDesc = {};
1951 attDesc.format = colorFormat;
1952 attDesc.samples = samples;
1953 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1954 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1955 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1956 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1957 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1958 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1959 rpD->attDescs.append(attDesc);
1961 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1966 rpD->multiViewCount = 0;
1968 if (hasDepthStencil) {
1972 attDesc.format = optimalDepthStencilFormat();
1973 attDesc.samples = samples;
1974 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1975 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1976 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1977 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1978 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1979 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1980 rpD->attDescs.append(attDesc);
1982 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1987 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1989 attDesc.format = colorFormat;
1990 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1991 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1992 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1993 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1994 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1995 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1996 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1997 rpD->attDescs.append(attDesc);
1999 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2002 rpD->dsResolveRef = {};
2004 rpD->shadingRateRef = {};
2005#ifdef VK_KHR_fragment_shading_rate
2006 if (shadingRateMap) {
2008 attDesc.format = VK_FORMAT_R8_UINT;
2009 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2010 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2011 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2012 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2013 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2014 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2015 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2016 rpD->attDescs.append(attDesc);
2018 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2023 VkSubpassDependency subpassDep = {};
2024 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2025 subpassDep.dstSubpass = 0;
2026 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2027 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2028 subpassDep.srcAccessMask = 0;
2029 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2030 rpD->subpassDeps.append(subpassDep);
2031 if (hasDepthStencil) {
2032 memset(&subpassDep, 0,
sizeof(subpassDep));
2033 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2034 subpassDep.dstSubpass = 0;
2035 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2036 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2037 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2038 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2039 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2040 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2041 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2042 rpD->subpassDeps.append(subpassDep);
2045 VkRenderPassCreateInfo rpInfo;
2046 VkSubpassDescription subpassDesc;
2047 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2049#ifdef VK_KHR_create_renderpass2
2050 if (caps.renderPass2KHR) {
2052 VkRenderPassCreateInfo2KHR rpInfo2;
2053 RenderPass2SetupHelper rp2Helper(
this);
2054 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2056 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2057 if (err != VK_SUCCESS) {
2058 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2065 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2066 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2067 if (err != VK_SUCCESS) {
2068 qWarning(
"Failed to create renderpass: %d", err);
2077 const QRhiColorAttachment *colorAttachmentsBegin,
2078 const QRhiColorAttachment *colorAttachmentsEnd,
2082 QRhiRenderBuffer *depthStencilBuffer,
2083 QRhiTexture *depthTexture,
2084 QRhiTexture *depthResolveTexture,
2086 QRhiShadingRateMap *shadingRateMap)
2090 int multiViewCount = 0;
2091 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2094 Q_ASSERT(texD || rbD);
2095 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2096 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2098 VkAttachmentDescription attDesc = {};
2099 attDesc.format = vkformat;
2100 attDesc.samples = samples;
2101 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2102 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2103 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2104 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2106 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2107 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2108 rpD->attDescs.append(attDesc);
2110 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2111 rpD->colorRefs.append(ref);
2113 if (it->multiViewCount() >= 2) {
2114 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2115 qWarning(
"Inconsistent multiViewCount in color attachment set");
2117 multiViewCount = it->multiViewCount();
2118 }
else if (multiViewCount > 0) {
2119 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2122 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2123 rpD->multiViewCount = uint32_t(multiViewCount);
2127 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2128 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2129 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2130 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2131 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2132 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2133 VkAttachmentDescription attDesc = {};
2134 attDesc.format = dsFormat;
2135 attDesc.samples = samples;
2136 attDesc.loadOp = loadOp;
2137 attDesc.storeOp = storeOp;
2138 attDesc.stencilLoadOp = loadOp;
2139 attDesc.stencilStoreOp = storeOp;
2140 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2141 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2142 rpD->attDescs.append(attDesc);
2143 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2144 multiViewCount = depthTexture->arraySize();
2145 rpD->multiViewCount = multiViewCount;
2147 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2152 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2153 if (it->resolveTexture()) {
2155 const VkFormat dstFormat = rtexD->vkformat;
2156 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2157 qWarning(
"Resolving into a multisample texture is not supported");
2161 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2162 if (srcFormat != dstFormat) {
2166 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2167 int(srcFormat),
int(dstFormat));
2170 VkAttachmentDescription attDesc = {};
2171 attDesc.format = rtexD->viewFormat;
2172 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2173 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2174 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2175 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2176 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2177 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2178 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2179 rpD->attDescs.append(attDesc);
2181 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2182 rpD->resolveRefs.append(ref);
2184 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2185 rpD->resolveRefs.append(ref);
2188 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2193 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2194 qWarning(
"Resolving into a multisample depth texture is not supported");
2197 if (texD->vkformat != rtexD->vkformat) {
2198 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2199 int(texD->vkformat),
int(rtexD->vkformat));
2202 VkAttachmentDescription attDesc = {};
2203 attDesc.format = rtexD->viewFormat;
2204 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2205 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2206 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2207 attDesc.stencilLoadOp = attDesc.loadOp;
2208 attDesc.stencilStoreOp = attDesc.storeOp;
2209 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2210 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2211 rpD->attDescs.append(attDesc);
2212 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2214 rpD->dsResolveRef = {};
2218 rpD->shadingRateRef = {};
2219#ifdef VK_KHR_fragment_shading_rate
2220 if (shadingRateMap) {
2221 VkAttachmentDescription attDesc = {};
2222 attDesc.format = VK_FORMAT_R8_UINT;
2223 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2224 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2225 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2226 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2227 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2228 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2229 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2230 rpD->attDescs.append(attDesc);
2231 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2236 VkSubpassDependency selfDependency;
2237 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2238 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2239 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2240 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2241 selfDependency.srcSubpass = 0;
2242 selfDependency.dstSubpass = 0;
2243 selfDependency.srcStageMask = stageMask;
2244 selfDependency.dstStageMask = stageMask;
2245 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2246 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2247 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2248#ifdef VK_VERSION_1_1
2249 if (rpD->multiViewCount >= 2)
2250 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2252 selfDependency.dependencyFlags = depFlags;
2253 rpD->subpassDeps.append(selfDependency);
2260 VkRenderPassCreateInfo rpInfo;
2261 VkSubpassDescription subpassDesc;
2262 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2265 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2268#ifdef VK_KHR_create_renderpass2
2269 if (caps.renderPass2KHR) {
2271 VkRenderPassCreateInfo2KHR rpInfo2;
2272 RenderPass2SetupHelper rp2Helper(
this);
2273 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2276 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2277 if (err != VK_SUCCESS) {
2278 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2285 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2286 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2289 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2290 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2291 if (err != VK_SUCCESS) {
2292 qWarning(
"Failed to create renderpass: %d", err);
2303 if (swapChainD->pixelSize.isEmpty()) {
2304 qWarning(
"Surface size is 0, cannot create swapchain");
2308 df->vkDeviceWaitIdle(dev);
2310 if (!vkCreateSwapchainKHR) {
2311 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2312 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2313 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2314 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2315 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2316 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2317 qWarning(
"Swapchain functions not available");
2322 VkSurfaceCapabilitiesKHR surfaceCaps;
2323 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2324 quint32 reqBufferCount;
2325 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2326 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2328 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2330 VkSurfaceTransformFlagBitsKHR preTransform =
2331 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2332 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2333 : surfaceCaps.currentTransform;
2359 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2360 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2361 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2362 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2364 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2365 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2366 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2367 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2368 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2369 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2370 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2371 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2372 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2373 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2376 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2377 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2378 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2379 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2381 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2382 && surfaceCaps.maxImageArrayLayers > 1;
2385 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2386 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2390 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2391 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2392 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2393 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2401 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2403 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2404 reuseExisting ?
"recycled" :
"new",
2405 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2407 VkSwapchainCreateInfoKHR swapChainInfo = {};
2408 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2409 swapChainInfo.surface = swapChainD->surface;
2410 swapChainInfo.minImageCount = reqBufferCount;
2411 swapChainInfo.imageFormat = swapChainD->colorFormat;
2412 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2413 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2414 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2415 swapChainInfo.imageUsage = usage;
2416 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2417 swapChainInfo.preTransform = preTransform;
2418 swapChainInfo.compositeAlpha = compositeAlpha;
2419 swapChainInfo.presentMode = presentMode;
2420 swapChainInfo.clipped =
true;
2421 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2423 VkSwapchainKHR newSwapChain;
2424 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2425 if (err != VK_SUCCESS) {
2426 qWarning(
"Failed to create swapchain: %d", err);
2429 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2434 swapChainD->sc = newSwapChain;
2435 swapChainD->lastConnectedSurface = swapChainD->surface;
2437 quint32 actualSwapChainBufferCount = 0;
2438 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2439 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2440 qWarning(
"Failed to get swapchain images: %d", err);
2444 if (actualSwapChainBufferCount != reqBufferCount)
2445 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2448 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2449 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2450 if (err != VK_SUCCESS) {
2451 qWarning(
"Failed to get swapchain images: %d", err);
2455 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2456 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2457 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2458 if (!createTransientImage(swapChainD->colorFormat,
2459 swapChainD->pixelSize,
2460 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2461 VK_IMAGE_ASPECT_COLOR_BIT,
2462 swapChainD->samples,
2463 &swapChainD->msaaImageMem,
2466 swapChainD->bufferCount))
2468 qWarning(
"Failed to create transient image for MSAA color buffer");
2473 VkFenceCreateInfo fenceInfo = {};
2474 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2475 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2478 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2482 image.image = swapChainImages[i];
2483 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2484 image.msaaImage = msaaImages[i];
2485 image.msaaImageView = msaaViews[i];
2488 VkImageViewCreateInfo imgViewInfo = {};
2489 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2490 imgViewInfo.image = swapChainImages[i];
2491 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2492 imgViewInfo.format = swapChainD->colorFormat;
2493 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2494 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2495 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2496 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2497 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2498 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2499 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2500 if (err != VK_SUCCESS) {
2501 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2507 VkSemaphoreCreateInfo semInfo = {};
2508 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2509 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2514 image.image = swapChainImages[i];
2515 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2516 image.msaaImage = msaaImages[i];
2517 image.msaaImageView = msaaViews[i];
2520 VkImageViewCreateInfo imgViewInfo = {};
2521 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2522 imgViewInfo.image = swapChainImages[i];
2523 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2524 imgViewInfo.format = swapChainD->colorFormat;
2525 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2526 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2527 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2528 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2529 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2530 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2531 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2532 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2533 if (err != VK_SUCCESS) {
2534 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2538 VkSemaphoreCreateInfo semInfo = {};
2539 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2540 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2546 swapChainD->currentImageIndex = 0;
2548 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2550 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2551 VkImageViewCreateInfo viewInfo = {};
2552 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2553 viewInfo.image = texD->image;
2554 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2555 viewInfo.format = texD->viewFormat;
2556 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2557 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2558 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2559 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2560 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2561 viewInfo.subresourceRange.baseMipLevel = 0;
2562 viewInfo.subresourceRange.levelCount = 1;
2563 viewInfo.subresourceRange.baseArrayLayer = 0;
2564 viewInfo.subresourceRange.layerCount = 1;
2565 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2566 if (err != VK_SUCCESS) {
2567 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2572 VkSemaphoreCreateInfo semInfo = {};
2573 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2581 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2583 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2584 if (err != VK_SUCCESS) {
2585 qWarning(
"Failed to create command buffer fence: %d", err);
2598 if (swapChainD->sc == VK_NULL_HANDLE)
2602 df->vkDeviceWaitIdle(dev);
2606 if (frame.cmdFence) {
2608 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2609 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2610 frame.cmdFence = VK_NULL_HANDLE;
2613 if (frame.imageSem) {
2614 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2615 frame.imageSem = VK_NULL_HANDLE;
2622 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2623 image.fb = VK_NULL_HANDLE;
2625 if (image.imageView) {
2626 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2627 image.imageView = VK_NULL_HANDLE;
2629 if (image.msaaImageView) {
2630 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2631 image.msaaImageView = VK_NULL_HANDLE;
2633 if (image.msaaImage) {
2634 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2635 image.msaaImage = VK_NULL_HANDLE;
2637 if (image.drawSem) {
2638 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2639 image.drawSem = VK_NULL_HANDLE;
2643 if (swapChainD->msaaImageMem) {
2644 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2645 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2648 if (swapChainD->shadingRateMapView) {
2649 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2650 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2653 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2654 swapChainD->sc = VK_NULL_HANDLE;
2661 VkCommandPoolResetFlags flags = 0;
2666 if (releaseCachedResourcesCalledBeforeFrameStart)
2667 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2670 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2676 for (quint64 i = 0; i < timestampValidBits; i += 8)
2677 mask |= 0xFFULL << i;
2678 const quint64 ts0 = timestamp[0] & mask;
2679 const quint64 ts1 = timestamp[1] & mask;
2680 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2681 if (!qFuzzyIsNull(nsecsPerTick)) {
2682 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2683 const double elapsedSec = elapsedMs / 1000.0;
2694 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2697 inst->handle()->beginFrame(swapChainD->window);
2707 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2708 if (waitResult != QRhi::FrameOpSuccess)
2713 uint32_t imageIndex = 0;
2714 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2715 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2717 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2718 swapChainD->currentImageIndex = imageIndex;
2721 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2722 return QRhi::FrameOpSwapChainOutOfDate;
2724 if (err == VK_ERROR_DEVICE_LOST) {
2725 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2726 printExtraErrorInfo(err);
2728 return QRhi::FrameOpDeviceLost;
2730 qWarning(
"Failed to acquire next swapchain image: %d", err);
2731 return QRhi::FrameOpError;
2737 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2743 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2744 if (cbres != QRhi::FrameOpSuccess)
2747 swapChainD->cbWrapper.cb = frame.cmdBuf;
2750 swapChainD->rtWrapper.d.fb = image.fb;
2754 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2755 swapChainD->rtWrapperRight.d.fb = image.fb;
2762 quint64 timestamp[2] = { 0, 0 };
2763 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2764 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2765 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2766 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2768 if (err == VK_SUCCESS) {
2770 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2772 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2774 qWarning(
"Failed to query timestamp: %d", err);
2779 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2780 int timestampQueryIdx = -1;
2781 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2782 if (!timestampQueryPoolMap.testBit(i)) {
2783 timestampQueryPoolMap.setBit(i);
2784 timestampQueryIdx = i * 2;
2788 if (timestampQueryIdx >= 0) {
2789 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2791 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2792 timestampQueryPool, uint32_t(timestampQueryIdx));
2797 return QRhi::FrameOpSuccess;
2805 auto cleanup = qScopeGuard([
this, swapChainD] {
2806 inst->handle()->endFrame(swapChainD->window);
2811 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2816 VkImageMemoryBarrier presTrans = {};
2817 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2818 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2819 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2820 presTrans.image = image.image;
2821 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2822 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2826 presTrans.srcAccessMask = 0;
2827 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2828 df->vkCmdPipelineBarrier(frame.cmdBuf,
2829 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2830 0, 0,
nullptr, 0,
nullptr,
2834 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2835 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2836 df->vkCmdPipelineBarrier(frame.cmdBuf,
2837 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2838 0, 0,
nullptr, 0,
nullptr,
2846 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2852 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2853 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2855 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2856 needsPresent ? &image.drawSem :
nullptr);
2857 if (submitres != QRhi::FrameOpSuccess)
2865 VkPresentInfoKHR presInfo = {};
2866 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2867 presInfo.swapchainCount = 1;
2868 presInfo.pSwapchains = &swapChainD->sc;
2869 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2870 waitSemaphoresForPresent.append(image.drawSem);
2871 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2872 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2876 inst->presentAboutToBeQueued(swapChainD->window);
2878 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2879 waitSemaphoresForPresent.clear();
2880 if (err != VK_SUCCESS) {
2881 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2882 return QRhi::FrameOpSwapChainOutOfDate;
2883 }
else if (err != VK_SUBOPTIMAL_KHR) {
2884 if (err == VK_ERROR_DEVICE_LOST) {
2885 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2886 printExtraErrorInfo(err);
2888 return QRhi::FrameOpDeviceLost;
2890 qWarning(
"Failed to present: %d", err);
2891 return QRhi::FrameOpError;
2897 inst->presentQueued(swapChainD->window);
2902 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
2907 return QRhi::FrameOpSuccess;
2921 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2931 VkCommandBufferAllocateInfo cmdBufInfo = {};
2932 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2933 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2934 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2935 cmdBufInfo.commandBufferCount = 1;
2937 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2938 if (err != VK_SUCCESS) {
2939 if (err == VK_ERROR_DEVICE_LOST) {
2940 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2941 printExtraErrorInfo(err);
2943 return QRhi::FrameOpDeviceLost;
2945 qWarning(
"Failed to allocate frame command buffer: %d", err);
2946 return QRhi::FrameOpError;
2950 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2951 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2953 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2954 if (err != VK_SUCCESS) {
2955 if (err == VK_ERROR_DEVICE_LOST) {
2956 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2957 printExtraErrorInfo(err);
2959 return QRhi::FrameOpDeviceLost;
2961 qWarning(
"Failed to begin frame command buffer: %d", err);
2962 return QRhi::FrameOpError;
2965 return QRhi::FrameOpSuccess;
2969 VkSemaphore *waitSem, VkSemaphore *signalSem)
2971 VkResult err =
df->vkEndCommandBuffer(cb);
2972 if (err != VK_SUCCESS) {
2973 if (err == VK_ERROR_DEVICE_LOST) {
2974 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2975 printExtraErrorInfo(err);
2977 return QRhi::FrameOpDeviceLost;
2979 qWarning(
"Failed to end frame command buffer: %d", err);
2980 return QRhi::FrameOpError;
2983 VkSubmitInfo submitInfo = {};
2984 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2985 submitInfo.commandBufferCount = 1;
2986 submitInfo.pCommandBuffers = &cb;
2989 waitSemaphoresForQueueSubmit.append(*waitSem);
2991 signalSemaphoresForQueueSubmit.append(*signalSem);
2993 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2994 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2995 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2996 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2997 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2999 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3000 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3001 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3004 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3006 waitSemaphoresForQueueSubmit.clear();
3007 signalSemaphoresForQueueSubmit.clear();
3009 if (err != VK_SUCCESS) {
3010 if (err == VK_ERROR_DEVICE_LOST) {
3011 qWarning(
"Device loss detected in vkQueueSubmit()");
3012 printExtraErrorInfo(err);
3014 return QRhi::FrameOpDeviceLost;
3016 qWarning(
"Failed to submit to graphics queue: %d", err);
3017 return QRhi::FrameOpError;
3020 return QRhi::FrameOpSuccess;
3025 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3026 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3027 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3028 if (frame.cmdFenceWaitable) {
3029 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3031 if (err != VK_SUCCESS) {
3032 if (err == VK_ERROR_DEVICE_LOST) {
3033 qWarning(
"Device loss detected in vkWaitForFences()");
3034 printExtraErrorInfo(err);
3036 return QRhi::FrameOpDeviceLost;
3038 qWarning(
"Failed to wait for fence: %d", err);
3039 return QRhi::FrameOpError;
3042 df->vkResetFences(dev, 1, &frame.cmdFence);
3043 frame.cmdFenceWaitable =
false;
3047 if (ofr.cmdFenceWaitable[frameSlot]) {
3048 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3049 if (err != VK_SUCCESS) {
3050 if (err == VK_ERROR_DEVICE_LOST) {
3051 qWarning(
"Device loss detected in vkWaitForFences()");
3052 printExtraErrorInfo(err);
3054 return QRhi::FrameOpDeviceLost;
3056 qWarning(
"Failed to wait for offscreen fence: %d", err);
3057 return QRhi::FrameOpError;
3059 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3060 ofr.cmdFenceWaitable[frameSlot] =
false;
3063 return QRhi::FrameOpSuccess;
3068 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3069 if (waitResult != QRhi::FrameOpSuccess)
3075 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3076 if (cbres != QRhi::FrameOpSuccess)
3082 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3083 quint64 timestamp[2] = { 0, 0 };
3084 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3085 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3086 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3087 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3088 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3089 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3090 if (err == VK_SUCCESS) {
3092 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3096 qWarning(
"Failed to query timestamp: %d", err);
3100 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3101 int timestampQueryIdx = -1;
3102 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3103 if (!timestampQueryPoolMap.testBit(i)) {
3104 timestampQueryPoolMap.setBit(i);
3105 timestampQueryIdx = i * 2;
3109 if (timestampQueryIdx >= 0) {
3110 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3112 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3113 timestampQueryPool, uint32_t(timestampQueryIdx));
3114 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3119 return QRhi::FrameOpSuccess;
3125 Q_ASSERT(ofr.active);
3131 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3135 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3136 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3137 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3140 if (!ofr.cmdFence[currentFrameSlot]) {
3141 VkFenceCreateInfo fenceInfo = {};
3142 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3143 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3144 if (err != VK_SUCCESS) {
3145 qWarning(
"Failed to create command buffer fence: %d", err);
3146 return QRhi::FrameOpError;
3150 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3151 if (submitres != QRhi::FrameOpSuccess)
3154 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3157 if (readbacksPending) {
3158 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3159 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3160 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3167 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3169 return QRhi::FrameOpSuccess;
3191 swapChainD->cbWrapper.resetCommands();
3192 cb = swapChainD->cbWrapper.cb;
3194 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3195 if (submitres != QRhi::FrameOpSuccess)
3199 df->vkQueueWaitIdle(gfxQueue);
3206 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3209 startPrimaryCommandBuffer(&frame.cmdBuf);
3210 swapChainD->cbWrapper.cb = frame.cmdBuf;
3217 return QRhi::FrameOpSuccess;
3224 u
.access =
int(bufUsage.access);
3225 u
.stage =
int(bufUsage.stage);
3233 u
.access =
int(texUsage.access);
3234 u
.stage =
int(texUsage.stage);
3240 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3243 rtD->lastActiveFrameSlot = currentFrameSlot;
3244 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3246 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3254 texD->lastActiveFrameSlot = currentFrameSlot;
3259 rbD->lastActiveFrameSlot = currentFrameSlot;
3265 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3268 if (rtD->m_desc.depthStencilBuffer()) {
3270 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3277 rbD->lastActiveFrameSlot = currentFrameSlot;
3279 if (rtD->m_desc.depthTexture()) {
3284 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3286 if (rtD->m_desc.depthResolveTexture()) {
3291 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3293 if (rtD->m_desc.shadingRateMap()) {
3298 texD->lastActiveFrameSlot = currentFrameSlot;
3312 VkCommandBuffer secondaryCb;
3314 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3315 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3316 freeSecondaryCbs[currentFrameSlot].removeLast();
3318 VkCommandBufferAllocateInfo cmdBufInfo = {};
3319 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3320 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3321 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3322 cmdBufInfo.commandBufferCount = 1;
3324 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3325 if (err != VK_SUCCESS) {
3326 qWarning(
"Failed to create secondary command buffer: %d", err);
3327 return VK_NULL_HANDLE;
3331 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3332 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3333 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3334 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3335 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3336 cmdBufInheritInfo.subpass = 0;
3338 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3339 cmdBufInheritInfo.framebuffer = rtD->fb;
3341 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3343 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3344 if (err != VK_SUCCESS) {
3345 qWarning(
"Failed to begin secondary command buffer: %d", err);
3346 return VK_NULL_HANDLE;
3354 VkResult err =
df->vkEndCommandBuffer(cb);
3355 if (err != VK_SUCCESS)
3356 qWarning(
"Failed to end secondary command buffer: %d", err);
3360 cmd.args.executeSecondary.cb = cb;
3364 e.lastActiveFrameSlot = currentFrameSlot;
3365 e.secondaryCommandBuffer.cb = cb;
3366 releaseQueue.append(e);
3370 QRhiRenderTarget *rt,
3371 const QColor &colorClearValue,
3372 const QRhiDepthStencilClearValue &depthStencilClearValue,
3373 QRhiResourceUpdateBatch *resourceUpdates,
3374 QRhiCommandBuffer::BeginPassFlags flags)
3379 if (resourceUpdates)
3389 switch (rt->resourceType()) {
3390 case QRhiResource::SwapChainRenderTarget:
3392 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3402 texD->lastActiveFrameSlot = currentFrameSlot;
3405 case QRhiResource::TextureRenderTarget:
3419 cbD->currentTarget = rt;
3424 VkRenderPassBeginInfo rpBeginInfo = {};
3425 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3426 rpBeginInfo.renderPass = rtD
->rp->rp;
3427 rpBeginInfo.framebuffer = rtD->fb;
3428 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3429 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3431 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3432 [](
const VkAttachmentDescription &attDesc) {
3433 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3434 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3437 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3438 if (rpHasAnyClearOp) {
3441 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3442 colorClearValue.alphaF() } };
3447 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3452 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3453 colorClearValue.alphaF() } };
3458 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3463 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3467 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3468 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3472 cmd.args.beginRenderPass.desc = rpBeginInfo;
3473 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3475 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3478 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3483 rateCmd.args.setShadingRate.w = 1;
3484 rateCmd.args.setShadingRate.h = 1;
3496 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3497 cbD->activeSecondaryCbStack.removeLast();
3498 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3505 cbD->currentTarget =
nullptr;
3507 if (resourceUpdates)
3512 QRhiResourceUpdateBatch *resourceUpdates,
3513 QRhiCommandBuffer::BeginPassFlags flags)
3518 if (resourceUpdates)
3526 cbD->computePassState.reset();
3529 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3540 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3541 cbD->activeSecondaryCbStack.removeLast();
3542 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3547 if (resourceUpdates)
3554 Q_ASSERT(psD->pipeline);
3558 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3560 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3564 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3565 cmd.args.bindPipeline.pipeline = psD->pipeline;
3568 cbD->currentGraphicsPipeline =
nullptr;
3569 cbD->currentComputePipeline = ps;
3570 cbD->currentPipelineGeneration = psD->generation;
3573 psD->lastActiveFrameSlot = currentFrameSlot;
3578 QRhiShaderResourceBinding::Type bindingType,
3579 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3581 VkAccessFlags access = 0;
3582 if (bindingType == loadTypeVal) {
3583 access = VK_ACCESS_SHADER_READ_BIT;
3585 access = VK_ACCESS_SHADER_WRITE_BIT;
3586 if (bindingType == loadStoreTypeVal)
3587 access |= VK_ACCESS_SHADER_READ_BIT;
3589 auto it = writtenResources->find(resource);
3590 if (it != writtenResources->end())
3591 it->second.accessFlags |= access;
3592 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3593 writtenResources->insert(resource, { access,
true });
3603 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3604 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3605 if (cbD->currentComputeSrb) {
3609 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3610 accessAndIsNewFlag = { 0,
false };
3613 for (
auto &binding : srbD->m_bindings) {
3614 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3616 case QRhiShaderResourceBinding::ImageLoad:
3617 case QRhiShaderResourceBinding::ImageStore:
3618 case QRhiShaderResourceBinding::ImageLoadStore:
3619 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3622 QRhiShaderResourceBinding::ImageLoad,
3623 QRhiShaderResourceBinding::ImageStore,
3624 QRhiShaderResourceBinding::ImageLoadStore);
3626 case QRhiShaderResourceBinding::BufferLoad:
3627 case QRhiShaderResourceBinding::BufferStore:
3628 case QRhiShaderResourceBinding::BufferLoadStore:
3629 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3632 QRhiShaderResourceBinding::BufferLoad,
3633 QRhiShaderResourceBinding::BufferStore,
3634 QRhiShaderResourceBinding::BufferLoadStore);
3641 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3642 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3643 const bool isNewInThisDispatch = it->second.isNew;
3644 if (accessInThisDispatch && !isNewInThisDispatch) {
3645 if (it.key()->resourceType() == QRhiResource::Texture) {
3647 VkImageMemoryBarrier barrier = {};
3648 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3649 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3651 barrier.subresourceRange.baseMipLevel = 0;
3652 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3653 barrier.subresourceRange.baseArrayLayer = 0;
3654 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3655 barrier.oldLayout = texD->usageState.layout;
3656 barrier.newLayout = texD->usageState.layout;
3657 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3658 barrier.dstAccessMask = accessInThisDispatch;
3659 barrier.image = texD->image;
3660 imageBarriers.append(barrier);
3663 VkBufferMemoryBarrier barrier = {};
3664 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3665 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3666 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3667 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3668 barrier.dstAccessMask = accessInThisDispatch;
3669 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3670 barrier.size = VK_WHOLE_SIZE;
3671 bufferBarriers.append(barrier);
3677 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3678 it = cbD->computePassState.writtenResources.erase(it);
3685 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3686 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3687 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3689 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3690 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3692 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3694 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3697 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3698 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3699 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3700 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3701 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3702 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3703 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3704 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3708 cmd.args.dispatch.x = x;
3709 cmd.args.dispatch.y = y;
3710 cmd.args.dispatch.z = z;
3716 VkShaderModuleCreateInfo shaderInfo = {};
3717 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3718 shaderInfo.codeSize = size_t(spirv.size());
3719 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3720 VkShaderModule shaderModule;
3721 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3722 if (err != VK_SUCCESS) {
3723 qWarning(
"Failed to create shader module: %d", err);
3724 return VK_NULL_HANDLE;
3726 return shaderModule;
3734 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3735 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3736 pipelineCacheInfo.initialDataSize = initialDataSize;
3737 pipelineCacheInfo.pInitialData = initialData;
3738 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3739 if (err != VK_SUCCESS) {
3740 qWarning(
"Failed to create pipeline cache: %d", err);
3750 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3751 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3752 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3753 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3754 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3756 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3757 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3760 VkWriteDescriptorSet writeInfo = {};
3761 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3762 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3763 writeInfo.dstBinding = uint32_t(b->binding);
3764 writeInfo.descriptorCount = 1;
3766 int bufferInfoIndex = -1;
3767 int imageInfoIndex = -1;
3770 case QRhiShaderResourceBinding::UniformBuffer:
3772 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3773 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3774 QRhiBuffer *buf = b->u.ubuf.buf;
3776 bd.ubuf.id = bufD->m_id;
3777 bd.ubuf.generation = bufD->generation;
3778 VkDescriptorBufferInfo bufInfo;
3779 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3780 bufInfo.offset = b->u.ubuf.offset;
3781 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3783 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3784 bufferInfoIndex = bufferInfos.size();
3785 bufferInfos.append(bufInfo);
3788 case QRhiShaderResourceBinding::SampledTexture:
3790 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3791 writeInfo.descriptorCount = data->count;
3792 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3793 ArrayOfImageDesc imageInfo(data->count);
3794 for (
int elem = 0; elem < data->count; ++elem) {
3797 bd.stex.d[elem].texId = texD->m_id;
3798 bd.stex.d[elem].texGeneration = texD->generation;
3799 bd.stex.d[elem].samplerId = samplerD->m_id;
3800 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3801 imageInfo[elem].sampler = samplerD->sampler;
3802 imageInfo[elem].imageView = texD->imageView;
3803 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3805 bd.stex.count = data->count;
3806 imageInfoIndex = imageInfos.size();
3807 imageInfos.append(imageInfo);
3810 case QRhiShaderResourceBinding::Texture:
3812 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3813 writeInfo.descriptorCount = data->count;
3814 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3815 ArrayOfImageDesc imageInfo(data->count);
3816 for (
int elem = 0; elem < data->count; ++elem) {
3818 bd.stex.d[elem].texId = texD->m_id;
3819 bd.stex.d[elem].texGeneration = texD->generation;
3820 bd.stex.d[elem].samplerId = 0;
3821 bd.stex.d[elem].samplerGeneration = 0;
3822 imageInfo[elem].sampler = VK_NULL_HANDLE;
3823 imageInfo[elem].imageView = texD->imageView;
3824 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3826 bd.stex.count = data->count;
3827 imageInfoIndex = imageInfos.size();
3828 imageInfos.append(imageInfo);
3831 case QRhiShaderResourceBinding::Sampler:
3834 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3835 bd.stex.d[0].texId = 0;
3836 bd.stex.d[0].texGeneration = 0;
3837 bd.stex.d[0].samplerId = samplerD->m_id;
3838 bd.stex.d[0].samplerGeneration = samplerD->generation;
3839 ArrayOfImageDesc imageInfo(1);
3840 imageInfo[0].sampler = samplerD->sampler;
3841 imageInfo[0].imageView = VK_NULL_HANDLE;
3842 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3843 imageInfoIndex = imageInfos.size();
3844 imageInfos.append(imageInfo);
3847 case QRhiShaderResourceBinding::ImageLoad:
3848 case QRhiShaderResourceBinding::ImageStore:
3849 case QRhiShaderResourceBinding::ImageLoadStore:
3852 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3854 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3855 bd.simage.id = texD->m_id;
3856 bd.simage.generation = texD->generation;
3857 ArrayOfImageDesc imageInfo(1);
3858 imageInfo[0].sampler = VK_NULL_HANDLE;
3859 imageInfo[0].imageView = view;
3860 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3861 imageInfoIndex = imageInfos.size();
3862 imageInfos.append(imageInfo);
3866 case QRhiShaderResourceBinding::BufferLoad:
3867 case QRhiShaderResourceBinding::BufferStore:
3868 case QRhiShaderResourceBinding::BufferLoadStore:
3871 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3872 bd.sbuf.id = bufD->m_id;
3873 bd.sbuf.generation = bufD->generation;
3874 VkDescriptorBufferInfo bufInfo;
3875 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3876 bufInfo.offset = b->u.sbuf.offset;
3877 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3878 bufferInfoIndex = bufferInfos.size();
3879 bufferInfos.append(bufInfo);
3886 writeInfos.append(writeInfo);
3887 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3890 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3891 const int bufferInfoIndex = infoIndices[i].first;
3892 const int imageInfoIndex = infoIndices[i].second;
3893 if (bufferInfoIndex >= 0)
3894 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3895 else if (imageInfoIndex >= 0)
3896 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3899 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3904 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3905 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3906 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3907 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3908 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3909 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3913 VkAccessFlags access, VkPipelineStageFlags stage)
3916 Q_ASSERT(access && stage);
3924 if (s.access == access && s.stage == stage) {
3927 if (!accessIsWrite(access))
3931 VkBufferMemoryBarrier bufMemBarrier = {};
3932 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3933 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3934 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3935 bufMemBarrier.srcAccessMask = s.access;
3936 bufMemBarrier.dstAccessMask = access;
3937 bufMemBarrier.buffer = bufD->buffers[slot];
3938 bufMemBarrier.size = VK_WHOLE_SIZE;
3942 cmd.args.bufferBarrier.srcStageMask = s.stage;
3943 cmd.args.bufferBarrier.dstStageMask = stage;
3944 cmd.args.bufferBarrier.count = 1;
3945 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3946 cbD->pools.bufferBarrier.append(bufMemBarrier);
3953 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3956 Q_ASSERT(layout && access && stage);
3958 if (s.access == access && s.stage == stage && s.layout == layout) {
3959 if (!accessIsWrite(access))
3963 VkImageMemoryBarrier barrier = {};
3964 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3965 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3966 barrier.subresourceRange.baseMipLevel = 0;
3967 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3968 barrier.subresourceRange.baseArrayLayer = 0;
3969 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3970 barrier.oldLayout = s.layout;
3971 barrier.newLayout = layout;
3972 barrier.srcAccessMask = s.access;
3973 barrier.dstAccessMask = access;
3974 barrier.image = texD->image;
3976 VkPipelineStageFlags srcStage = s.stage;
3979 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3983 cmd.args.imageBarrier.srcStageMask = srcStage;
3984 cmd.args.imageBarrier.dstStageMask = stage;
3985 cmd.args.imageBarrier.count = 1;
3986 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3987 cbD->pools.imageBarrier.append(barrier);
3998 VkImageMemoryBarrier barrier = {};
3999 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4000 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4001 barrier.subresourceRange.baseMipLevel = 0;
4002 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4003 barrier.subresourceRange.baseArrayLayer = 0;
4004 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4005 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4006 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4007 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4008 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4009 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4010 barrier.image = rbD->image;
4012 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4013 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4017 cmd.args.imageBarrier.srcStageMask = stages;
4018 cmd.args.imageBarrier.dstStageMask = stages;
4019 cmd.args.imageBarrier.count = 1;
4020 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4021 cbD->pools.imageBarrier.append(barrier);
4025 VkImageLayout oldLayout, VkImageLayout newLayout,
4026 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4027 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4028 int startLayer,
int layerCount,
4029 int startLevel,
int levelCount)
4032 VkImageMemoryBarrier barrier = {};
4033 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4034 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4035 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4036 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4037 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4038 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4039 barrier.oldLayout = oldLayout;
4040 barrier.newLayout = newLayout;
4041 barrier.srcAccessMask = srcAccess;
4042 barrier.dstAccessMask = dstAccess;
4043 barrier.image = image;
4047 cmd.args.imageBarrier.srcStageMask = srcStage;
4048 cmd.args.imageBarrier.dstStageMask = dstStage;
4049 cmd.args.imageBarrier.count = 1;
4050 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4051 cbD->pools.imageBarrier.append(barrier);
4056 VkDeviceSize size = 0;
4057 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4058 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4059 if (imageSizeBytes > 0)
4060 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4065 const QRhiTextureSubresourceUploadDescription &subresDesc,
4066 size_t *curOfs,
void *mp,
4067 BufferImageCopyList *copyInfos)
4069 qsizetype copySizeBytes = 0;
4070 qsizetype imageSizeBytes = 0;
4071 const void *src =
nullptr;
4072 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4073 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4075 VkBufferImageCopy copyInfo = {};
4076 copyInfo.bufferOffset = *curOfs;
4077 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4078 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4079 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4080 copyInfo.imageSubresource.layerCount = 1;
4081 copyInfo.imageExtent.depth = 1;
4083 copyInfo.imageOffset.z = uint32_t(layer);
4085 copyInfo.imageOffset.y = uint32_t(layer);
4087 const QByteArray rawData = subresDesc.data();
4088 const QPoint dp = subresDesc.destinationTopLeft();
4089 QImage image = subresDesc.image();
4090 if (!image.isNull()) {
4091 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4092 QSize size = image.size();
4093 src = image.constBits();
4096 int bpc = qMax(1, image.depth() / 8);
4098 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4099 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4100 const int sx = subresDesc.sourceTopLeft().x();
4101 const int sy = subresDesc.sourceTopLeft().y();
4102 if (!subresDesc.sourceSize().isEmpty())
4103 size = subresDesc.sourceSize();
4104 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4105 if (size.width() == image.width()) {
4108 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4109 copySizeBytes = size.height() * image.bytesPerLine();
4111 image = image.copy(sx, sy, size.width(), size.height());
4112 src = image.constBits();
4115 copySizeBytes = image.sizeInBytes();
4116 bpc = qMax(1, image.depth() / 8);
4117 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4120 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4122 copyInfo.imageOffset.x = dp.x();
4123 copyInfo.imageOffset.y = dp.y();
4124 copyInfo.imageExtent.width = uint32_t(size.width());
4125 copyInfo.imageExtent.height = uint32_t(size.height());
4126 copyInfos->append(copyInfo);
4127 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4128 copySizeBytes = imageSizeBytes = rawData.size();
4129 src = rawData.constData();
4130 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4131 const int subresw = size.width();
4132 const int subresh = size.height();
4133 if (!subresDesc.sourceSize().isEmpty())
4134 size = subresDesc.sourceSize();
4135 const int w = size.width();
4136 const int h = size.height();
4138 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4140 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4141 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4144 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4145 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4146 copyInfos->append(copyInfo);
4147 }
else if (!rawData.isEmpty()) {
4148 copySizeBytes = imageSizeBytes = rawData.size();
4149 src = rawData.constData();
4150 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4151 if (subresDesc.dataStride()) {
4152 quint32 bytesPerPixel = 0;
4153 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4155 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4157 if (!subresDesc.sourceSize().isEmpty())
4158 size = subresDesc.sourceSize();
4159 copyInfo.imageOffset.x = dp.x();
4160 copyInfo.imageOffset.y = dp.y();
4161 copyInfo.imageExtent.width = uint32_t(size.width());
4162 copyInfo.imageExtent.height = uint32_t(size.height());
4163 copyInfos->append(copyInfo);
4165 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4169 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4170 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4176 if (err == VK_ERROR_DEVICE_LOST)
4178 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4179 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4184#ifdef VK_EXT_device_fault
4185 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4188 VkDeviceFaultCountsEXT faultCounts{};
4189 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4190 faultCounts.pNext =
nullptr;
4192 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4193 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4194 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4197 faultCounts.vendorBinarySize = 0;
4199 QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
4200 addressInfos.resize(faultCounts.addressInfoCount);
4202 QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
4203 vendorInfos.resize(faultCounts.vendorInfoCount);
4205 VkDeviceFaultInfoEXT info{};
4206 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4207 info.pNext =
nullptr;
4208 info.pAddressInfos = addressInfos.isEmpty() ?
nullptr : addressInfos.data();
4209 info.pVendorInfos = vendorInfos.isEmpty() ?
nullptr : vendorInfos.data();
4210 info.pVendorBinaryData =
nullptr;
4212 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4213 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4214 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4218 const char *desc = info.description[0] ? info.description :
"n/a";
4219 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4220 faultCounts.addressInfoCount,
4221 faultCounts.vendorInfoCount,
4222 (
unsigned long long)faultCounts.vendorBinarySize,
4225 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4226 const auto &a = addressInfos[i];
4227 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4229 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4230 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4231 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4232 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4233 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4234 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4235 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4236 default:
return "UNKNOWN";
4239 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4241 addressTypeString(a.addressType),
4242 (
unsigned long long)a.reportedAddress,
4243 (
unsigned long long)a.addressPrecision);
4246 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4247 const auto &v = vendorInfos[i];
4248 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4250 (
unsigned long long)v.vendorFaultCode,
4251 (
unsigned long long)v.vendorFaultData,
4265 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4267 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4268 bufD->pendingDynamicUpdates[i].clear();
4269 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4273 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4274 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4276 if (!bufD->stagingBuffers[currentFrameSlot]) {
4277 VkBufferCreateInfo bufferInfo = {};
4278 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4281 bufferInfo.size = bufD->m_size;
4282 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4284 VmaAllocationCreateInfo allocInfo = {};
4285 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4287 VmaAllocation allocation;
4288 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4289 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4290 if (err == VK_SUCCESS) {
4291 bufD->stagingAllocations[currentFrameSlot] = allocation;
4292 setAllocationName(allocation, bufD->name());
4294 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4295 printExtraErrorInfo(err);
4300 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4301 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4302 u.offset, u
.data.size());
4303 if (err != VK_SUCCESS) {
4304 qWarning(
"Failed to copy memory to buffer: %d", err);
4308 trackedBufferBarrier(cbD, bufD, 0,
4309 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4311 VkBufferCopy copyInfo = {};
4312 copyInfo.srcOffset = u.offset;
4313 copyInfo.dstOffset = u.offset;
4314 copyInfo.size = u
.data.size();
4318 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4319 cmd.args.copyBuffer.dst = bufD->buffers[0];
4320 cmd.args.copyBuffer.desc = copyInfo;
4329 bufD->lastActiveFrameSlot = currentFrameSlot;
4331 if (bufD->m_type == QRhiBuffer::Immutable) {
4334 e.lastActiveFrameSlot = currentFrameSlot;
4335 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4336 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4337 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4338 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4339 releaseQueue.append(e);
4343 if (bufD->m_type == QRhiBuffer::Dynamic) {
4345 u.result->data.resizeForOverwrite(u.readSize);
4346 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4347 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4348 u.offset, u.result->data.data(), u.readSize);
4349 if (err != VK_SUCCESS) {
4350 qWarning(
"Failed to copy memory from buffer: %d", err);
4351 u.result->data.clear();
4353 if (u.result->completed)
4354 u.result->completed();
4363 readback.activeFrameSlot = currentFrameSlot;
4364 readback.result = u.result;
4365 readback.byteSize = u.readSize;
4367 VkBufferCreateInfo bufferInfo = {};
4368 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4369 bufferInfo.size = readback.byteSize;
4370 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4372 VmaAllocationCreateInfo allocInfo = {};
4373 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4375 VmaAllocation allocation;
4376 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4377 if (err == VK_SUCCESS) {
4379 setAllocationName(allocation, bufD->name());
4381 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4382 printExtraErrorInfo(err);
4386 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4388 VkBufferCopy copyInfo = {};
4389 copyInfo.srcOffset = u.offset;
4390 copyInfo.size = u.readSize;
4394 cmd.args.copyBuffer.src = bufD->buffers[0];
4395 cmd.args.copyBuffer.dst = readback.stagingBuf;
4396 cmd.args.copyBuffer.desc = copyInfo;
4398 bufD->lastActiveFrameSlot = currentFrameSlot;
4400 activeBufferReadbacks.append(readback);
4410 VkDeviceSize stagingSize = 0;
4411 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4412 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4413 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4414 stagingSize += subresUploadByteSize(subresDesc);
4418 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4419 VkBufferCreateInfo bufferInfo = {};
4420 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4421 bufferInfo.size = stagingSize;
4422 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4424 VmaAllocationCreateInfo allocInfo = {};
4425 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4427 VmaAllocation allocation;
4428 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4429 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4430 if (err != VK_SUCCESS) {
4431 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4432 printExtraErrorInfo(err);
4435 utexD->stagingAllocations[currentFrameSlot] = allocation;
4436 setAllocationName(allocation, utexD->name());
4438 BufferImageCopyList copyInfos;
4441 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4442 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4443 if (err != VK_SUCCESS) {
4444 qWarning(
"Failed to map image data: %d", err);
4448 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4449 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4450 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4453 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4454 prepareUploadSubres(utexD, layer, level,
4455 subresDesc, &curOfs, mp, ©Infos);
4459 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4460 vmaUnmapMemory(toVmaAllocator(allocator), a);
4462 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4463 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4467 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4468 cmd.args.copyBufferToImage.dst = utexD->image;
4469 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4470 cmd.args.copyBufferToImage.count = copyInfos.size();
4471 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4472 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4477 e.lastActiveFrameSlot = currentFrameSlot;
4478 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4479 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4480 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4481 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4482 releaseQueue.append(e);
4487 utexD->lastActiveFrameSlot = currentFrameSlot;
4491 qWarning(
"Texture copy with matching source and destination is not supported");
4496 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4497 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4499 VkImageCopy region = {};
4500 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4501 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4502 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4503 region.srcSubresource.layerCount = 1;
4505 region.srcOffset.x = u.desc.sourceTopLeft().x();
4506 region.srcOffset.y = u.desc.sourceTopLeft().y();
4508 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4510 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4511 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4512 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4513 region.dstSubresource.layerCount = 1;
4515 region.dstOffset.x = u.desc.destinationTopLeft().x();
4516 region.dstOffset.y = u.desc.destinationTopLeft().y();
4518 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4520 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4521 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4522 region.extent.width = uint32_t(copySize.width());
4523 region.extent.height = uint32_t(copySize.height());
4524 region.extent.depth = 1;
4526 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4527 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4528 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4529 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4533 cmd.args.copyImage.src = srcD->image;
4534 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4535 cmd.args.copyImage.dst = dstD->image;
4536 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4537 cmd.args.copyImage.desc = region;
4539 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4542 readback.activeFrameSlot = currentFrameSlot;
4543 readback.desc = u.rb;
4544 readback.result = u.result;
4550 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4551 qWarning(
"Multisample texture cannot be read back");
4554 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4555 if (u.rb.rect().isValid())
4556 readback.rect = u.rb.rect();
4558 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4559 readback.format = texD->m_format;
4560 texD->lastActiveFrameSlot = currentFrameSlot;
4565 qWarning(
"Swapchain does not support readback");
4568 if (u.rb.rect().isValid())
4569 readback.rect = u.rb.rect();
4571 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4572 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4573 if (readback.format == QRhiTexture::UnknownFormat)
4579 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4582 VkBufferCreateInfo bufferInfo = {};
4583 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4584 bufferInfo.size = readback.byteSize;
4585 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4587 VmaAllocationCreateInfo allocInfo = {};
4588 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4590 VmaAllocation allocation;
4591 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4592 if (err == VK_SUCCESS) {
4594 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4596 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4597 printExtraErrorInfo(err);
4602 VkBufferImageCopy copyDesc = {};
4603 copyDesc.bufferOffset = 0;
4604 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4605 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4606 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4607 copyDesc.imageSubresource.layerCount = 1;
4608 copyDesc.imageOffset.x = readback.rect.x();
4609 copyDesc.imageOffset.y = readback.rect.y();
4611 copyDesc.imageOffset.z = u.rb.layer();
4612 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4613 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4614 copyDesc.imageExtent.depth = 1;
4617 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4618 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4621 cmd.args.copyImageToBuffer.src = texD->image;
4622 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4623 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4624 cmd.args.copyImageToBuffer.desc = copyDesc;
4628 VkImage image = imageRes.image;
4631 qWarning(
"Attempted to read back undefined swapchain image content, "
4632 "results are undefined. (do a render pass first)");
4634 subresourceBarrier(cbD, image,
4635 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4636 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4637 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4645 cmd.args.copyImageToBuffer.src = image;
4646 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4647 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4648 cmd.args.copyImageToBuffer.desc = copyDesc;
4651 activeTextureReadbacks.append(readback);
4654 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4655 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4656 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4657 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4659 VkImageLayout origLayout = utexD->usageState.layout;
4660 VkAccessFlags origAccess = utexD->usageState.access;
4661 VkPipelineStageFlags origStage = utexD->usageState.stage;
4663 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4665 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4666 int w = utexD->m_pixelSize.width();
4667 int h = utexD->m_pixelSize.height();
4668 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4669 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4671 subresourceBarrier(cbD, utexD->image,
4672 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4673 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4674 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4678 subresourceBarrier(cbD, utexD->image,
4679 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4680 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4681 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4686 subresourceBarrier(cbD, utexD->image,
4687 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4688 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4689 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4693 VkImageBlit region = {};
4694 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4695 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4696 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4697 region.srcSubresource.layerCount = 1;
4699 region.srcOffsets[1].x = qMax(1, w);
4700 region.srcOffsets[1].y = qMax(1, h);
4701 region.srcOffsets[1].z = qMax(1, depth);
4703 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4704 region.dstSubresource.mipLevel = uint32_t(level);
4705 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4706 region.dstSubresource.layerCount = 1;
4708 region.dstOffsets[1].x = qMax(1, w >> 1);
4709 region.dstOffsets[1].y = qMax(1, h >> 1);
4710 region.dstOffsets[1].z = qMax(1, depth >> 1);
4714 cmd.args.blitImage.src = utexD->image;
4715 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4716 cmd.args.blitImage.dst = utexD->image;
4717 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4718 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4719 cmd.args.blitImage.desc = region;
4726 if (utexD->mipLevelCount > 1) {
4727 subresourceBarrier(cbD, utexD->image,
4728 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4729 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4730 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4732 0,
int(utexD->mipLevelCount) - 1);
4733 subresourceBarrier(cbD, utexD->image,
4734 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4735 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4736 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4738 int(utexD->mipLevelCount) - 1, 1);
4741 utexD->lastActiveFrameSlot = currentFrameSlot;
4750 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4753 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4755 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4759 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4760 if (err != VK_SUCCESS) {
4761 qWarning(
"Failed to map buffer: %d", err);
4764 quint32 changeBegin = UINT32_MAX;
4765 quint32 changeEnd = 0;
4766 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4767 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4768 if (u.offset < changeBegin)
4769 changeBegin = u.offset;
4770 if (u.offset + u.data.size() > changeEnd)
4771 changeEnd = u.offset + u.data.size();
4773 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4774 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4775 vmaUnmapMemory(toVmaAllocator(allocator), a);
4777 bufD->pendingDynamicUpdates[slot].clear();
4783 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4784 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4790 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4791 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4792 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4797 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4798 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4800 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4801 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4802 if (e.texture.extraImageViews[i])
4803 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4809 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4814 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4816 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4819 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4820 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4823 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4824 if (e.shaderResourceBindings.poolIndex >= 0) {
4825 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4826 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4833 qrhivk_releaseRenderBuffer(e, dev,
df);
4839 qrhivk_releaseSampler(e, dev,
df);
4842 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4844 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4845 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4847 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4848 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4849 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4852 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4855 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4857 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4858 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4864 releaseQueue.removeAt(i);
4871 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4873 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4875 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4876 readback.result->format = readback.format;
4877 readback.result->pixelSize = readback.rect.size();
4878 readback.result->data.resizeForOverwrite(readback.byteSize);
4879 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4880 toVmaAllocation(readback.stagingAlloc),
4881 0, readback.result->data.data(), readback.byteSize);
4882 if (err != VK_SUCCESS) {
4883 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4884 readback.result->data.clear();
4887 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4889 if (readback.result->completed)
4890 completedCallbacks.append(readback.result->completed);
4892 activeTextureReadbacks.remove(i);
4896 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4898 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4899 readback.result->data.resizeForOverwrite(readback.byteSize);
4900 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4901 toVmaAllocation(readback.stagingAlloc),
4902 0, readback.result->data.data(), readback.byteSize);
4903 if (err != VK_SUCCESS) {
4904 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4905 readback.result->data.clear();
4908 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4910 if (readback.result->completed)
4911 completedCallbacks.append(readback.result->completed);
4913 activeBufferReadbacks.remove(i);
4917 for (
const auto &f : completedCallbacks)
4924} qvk_sampleCounts[] = {
4926 { VK_SAMPLE_COUNT_1_BIT, 1 },
4927 { VK_SAMPLE_COUNT_2_BIT, 2 },
4928 { VK_SAMPLE_COUNT_4_BIT, 4 },
4929 { VK_SAMPLE_COUNT_8_BIT, 8 },
4930 { VK_SAMPLE_COUNT_16_BIT, 16 },
4931 { VK_SAMPLE_COUNT_32_BIT, 32 },
4932 { VK_SAMPLE_COUNT_64_BIT, 64 }
4937 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4938 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4939 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4940 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4943 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4944 if ((color & qvk_sampleCount.mask)
4945 && (depth & qvk_sampleCount.mask)
4946 && (stencil & qvk_sampleCount.mask))
4948 result.append(qvk_sampleCount.count);
4957 const int s = effectiveSampleCount(sampleCount);
4959 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4960 if (qvk_sampleCount.count == s)
4961 return qvk_sampleCount.mask;
4964 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4969 QList<QSize> result;
4970#ifdef VK_KHR_fragment_shading_rate
4971 sampleCount = qMax(1, sampleCount);
4972 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4973 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4974 if (qvk_sampleCount.count == sampleCount) {
4975 mask = qvk_sampleCount.mask;
4979 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4980 if (s.sampleCounts & mask)
4981 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4984 Q_UNUSED(sampleCount);
4985 result.append(QSize(1, 1));
4992 cbD->passResTrackers.emplace_back();
4997 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5004 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5008 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5009 1, &cmd.args.copyBuffer.desc);
5012 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5013 cmd.args.copyBufferToImage.dstLayout,
5014 uint32_t(cmd.args.copyBufferToImage.count),
5015 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5018 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5019 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5020 1, &cmd.args.copyImage.desc);
5023 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5024 cmd.args.copyImageToBuffer.dst,
5025 1, &cmd.args.copyImageToBuffer.desc);
5028 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5029 0, 0,
nullptr, 0,
nullptr,
5030 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5033 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5035 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5039 const auto &barrier = cmd.args.imageAndBufferBarrier;
5040 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5041 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5042 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5043 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5044 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5046 barrier.bufferCount, bufferBarrierData,
5047 barrier.imageCount, imageBarrierData);
5050 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5051 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5052 1, &cmd.args.blitImage.desc,
5053 cmd.args.blitImage.filter);
5056 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5057 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5058 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5059 : VK_SUBPASS_CONTENTS_INLINE);
5062 VkMemoryBarrier barrier;
5063 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5064 barrier.pNext =
nullptr;
5065 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5066 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5067 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5073 df->vkCmdEndRenderPass(cbD->cb);
5076 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5080 const uint32_t *offsets =
nullptr;
5081 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5082 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5083 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5084 cmd.args.bindDescriptorSet.pipelineLayout,
5085 0, 1, &cmd.args.bindDescriptorSet.descSet,
5086 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5091 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5092 uint32_t(cmd.args.bindVertexBuffer.count),
5093 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5094 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5097 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5098 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5101 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5104 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5107 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5110 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5113 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5114 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5117 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5118 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5119 cmd.args.drawIndexed.firstInstance);
5122 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5123 cmd.args.drawIndirect.indirectBufferOffset,
5124 cmd.args.drawIndirect.drawCount,
5125 cmd.args.drawIndirect.stride);
5128 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5129 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5130 cmd.args.drawIndexedIndirect.drawCount,
5131 cmd.args.drawIndexedIndirect.stride);
5134#ifdef VK_EXT_debug_utils
5135 cmd.args.debugMarkerBegin.label.pLabelName =
5136 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5137 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5141#ifdef VK_EXT_debug_utils
5142 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5146#ifdef VK_EXT_debug_utils
5147 cmd.args.debugMarkerInsert.label.pLabelName =
5148 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5149 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5156 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5159 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5163#ifdef VK_KHR_fragment_shading_rate
5164 VkFragmentShadingRateCombinerOpKHR op[2] = {
5165 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5166 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5168 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5169 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5182 case QRhiPassResourceTracker::BufIndirectDraw:
5183 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5184 case QRhiPassResourceTracker::BufVertexInput:
5185 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5186 case QRhiPassResourceTracker::BufIndexRead:
5187 return VK_ACCESS_INDEX_READ_BIT;
5188 case QRhiPassResourceTracker::BufUniformRead:
5189 return VK_ACCESS_UNIFORM_READ_BIT;
5190 case QRhiPassResourceTracker::BufStorageLoad:
5191 return VK_ACCESS_SHADER_READ_BIT;
5192 case QRhiPassResourceTracker::BufStorageStore:
5193 return VK_ACCESS_SHADER_WRITE_BIT;
5194 case QRhiPassResourceTracker::BufStorageLoadStore:
5195 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5206 case QRhiPassResourceTracker::BufIndirectDrawStage:
5207 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5208 case QRhiPassResourceTracker::BufVertexInputStage:
5209 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5210 case QRhiPassResourceTracker::BufVertexStage:
5211 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5212 case QRhiPassResourceTracker::BufTCStage:
5213 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5214 case QRhiPassResourceTracker::BufTEStage:
5215 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5216 case QRhiPassResourceTracker::BufFragmentStage:
5217 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5218 case QRhiPassResourceTracker::BufComputeStage:
5219 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5220 case QRhiPassResourceTracker::BufGeometryStage:
5221 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5232 u.access = VkAccessFlags(usage
.access);
5233 u.stage = VkPipelineStageFlags(usage
.stage);
5240 case QRhiPassResourceTracker::TexSample:
5241 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5242 case QRhiPassResourceTracker::TexColorOutput:
5243 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5244 case QRhiPassResourceTracker::TexDepthOutput:
5245 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5246 case QRhiPassResourceTracker::TexStorageLoad:
5247 case QRhiPassResourceTracker::TexStorageStore:
5248 case QRhiPassResourceTracker::TexStorageLoadStore:
5249 return VK_IMAGE_LAYOUT_GENERAL;
5250 case QRhiPassResourceTracker::TexShadingRate:
5251#ifdef VK_KHR_fragment_shading_rate
5252 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5254 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5260 return VK_IMAGE_LAYOUT_GENERAL;
5266 case QRhiPassResourceTracker::TexSample:
5267 return VK_ACCESS_SHADER_READ_BIT;
5268 case QRhiPassResourceTracker::TexColorOutput:
5269 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5270 case QRhiPassResourceTracker::TexDepthOutput:
5271 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5272 case QRhiPassResourceTracker::TexStorageLoad:
5273 return VK_ACCESS_SHADER_READ_BIT;
5274 case QRhiPassResourceTracker::TexStorageStore:
5275 return VK_ACCESS_SHADER_WRITE_BIT;
5276 case QRhiPassResourceTracker::TexStorageLoadStore:
5277 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5290 case QRhiPassResourceTracker::TexVertexStage:
5291 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5292 case QRhiPassResourceTracker::TexTCStage:
5293 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5294 case QRhiPassResourceTracker::TexTEStage:
5295 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5296 case QRhiPassResourceTracker::TexFragmentStage:
5297 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5298 case QRhiPassResourceTracker::TexColorOutputStage:
5299 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5300 case QRhiPassResourceTracker::TexDepthOutputStage:
5301 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5302 case QRhiPassResourceTracker::TexComputeStage:
5303 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5304 case QRhiPassResourceTracker::TexGeometryStage:
5305 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5316 u.layout = VkImageLayout(usage
.layout);
5317 u.access = VkAccessFlags(usage
.access);
5318 u.stage = VkPipelineStageFlags(usage
.stage);
5329 const VkAccessFlags newAccess = toVkAccess(access);
5330 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5331 if (u.access == newAccess && u.stage == newStage) {
5332 if (!accessIsWrite(access))
5336 u.access = newAccess;
5346 const VkAccessFlags newAccess = toVkAccess(access);
5347 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5348 const VkImageLayout newLayout = toVkLayout(access);
5349 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5350 if (!accessIsWrite(access))
5354 u.layout = newLayout;
5355 u.access = newAccess;
5364 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5365 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5366 VkAccessFlags access = toVkAccess(trackedB.access);
5367 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5368 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5371 if (s.access == access && s.stage == stage) {
5372 if (!accessIsWrite(access))
5375 VkBufferMemoryBarrier bufMemBarrier = {};
5376 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5377 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5378 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5379 bufMemBarrier.srcAccessMask = s.access;
5380 bufMemBarrier.dstAccessMask = access;
5381 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5382 bufMemBarrier.size = VK_WHOLE_SIZE;
5383 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5389 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5390 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5391 VkImageLayout layout = toVkLayout(trackedT.access);
5392 VkAccessFlags access = toVkAccess(trackedT.access);
5393 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5394 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5395 if (s.access == access && s.stage == stage && s.layout == layout) {
5396 if (!accessIsWrite(access))
5399 VkImageMemoryBarrier barrier = {};
5400 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5401 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5402 barrier.subresourceRange.baseMipLevel = 0;
5403 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5404 barrier.subresourceRange.baseArrayLayer = 0;
5405 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5406 barrier.oldLayout = s.layout;
5407 barrier.newLayout = layout;
5408 barrier.srcAccessMask = s.access;
5409 barrier.dstAccessMask = access;
5410 barrier.image = texD->image;
5411 VkPipelineStageFlags srcStage = s.stage;
5414 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5415 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5424 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5425 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5426 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5428 qWarning(
"Physical device surface queries not available");
5432 return new QVkSwapChain(
this);
5435QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5437 return new QVkBuffer(
this, type, usage, size);
5442 return int(ubufAlign);
5464 static QMatrix4x4 m;
5465 if (m.isIdentity()) {
5467 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5468 0.0f, -1.0f, 0.0f, 0.0f,
5469 0.0f, 0.0f, 0.5f, 0.5f,
5470 0.0f, 0.0f, 0.0f, 1.0f);
5480 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5481 if (!physDevFeatures.textureCompressionBC)
5485 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5486 if (!physDevFeatures.textureCompressionETC2)
5490 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5491 if (!physDevFeatures.textureCompressionASTC_LDR)
5495 VkFormat vkformat = toVkTextureFormat(format, flags);
5496 VkFormatProperties props;
5497 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5498 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5504 case QRhi::MultisampleTexture:
5506 case QRhi::MultisampleRenderBuffer:
5508 case QRhi::DebugMarkers:
5509 return caps.debugUtils;
5510 case QRhi::Timestamps:
5511 return timestampValidBits != 0;
5512 case QRhi::Instancing:
5514 case QRhi::CustomInstanceStepRate:
5515 return caps.vertexAttribDivisor;
5516 case QRhi::PrimitiveRestart:
5518 case QRhi::NonDynamicUniformBuffers:
5520 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5522 case QRhi::NPOTTextureRepeat:
5524 case QRhi::RedOrAlpha8IsRed:
5526 case QRhi::ElementIndexUint:
5529 return caps.compute;
5530 case QRhi::WideLines:
5531 return caps.wideLines;
5532 case QRhi::VertexShaderPointSize:
5534 case QRhi::BaseVertex:
5536 case QRhi::BaseInstance:
5538 case QRhi::TriangleFanTopology:
5540 case QRhi::ReadBackNonUniformBuffer:
5542 case QRhi::ReadBackNonBaseMipLevel:
5544 case QRhi::TexelFetch:
5546 case QRhi::RenderToNonBaseMipLevel:
5548 case QRhi::IntAttributes:
5550 case QRhi::ScreenSpaceDerivatives:
5552 case QRhi::ReadBackAnyTextureFormat:
5554 case QRhi::PipelineCacheDataLoadSave:
5556 case QRhi::ImageDataStride:
5558 case QRhi::RenderBufferImport:
5560 case QRhi::ThreeDimensionalTextures:
5562 case QRhi::RenderTo3DTextureSlice:
5563 return caps.texture3DSliceAs2D;
5564 case QRhi::TextureArrays:
5566 case QRhi::Tessellation:
5567 return caps.tessellation;
5568 case QRhi::GeometryShader:
5569 return caps.geometryShader;
5570 case QRhi::TextureArrayRange:
5572 case QRhi::NonFillPolygonMode:
5573 return caps.nonFillPolygonMode;
5574 case QRhi::OneDimensionalTextures:
5576 case QRhi::OneDimensionalTextureMipmaps:
5578 case QRhi::HalfAttributes:
5580 case QRhi::RenderToOneDimensionalTexture:
5582 case QRhi::ThreeDimensionalTextureMipmaps:
5584 case QRhi::MultiView:
5585 return caps.multiView;
5586 case QRhi::TextureViewFormat:
5588 case QRhi::ResolveDepthStencil:
5589 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5590 case QRhi::VariableRateShading:
5591 return caps.renderPass2KHR && caps.perDrawShadingRate;
5592 case QRhi::VariableRateShadingMap:
5593 case QRhi::VariableRateShadingMapWithTexture:
5594 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5595 case QRhi::PerRenderTargetBlending:
5596 case QRhi::SampleVariables:
5598 case QRhi::InstanceIndexIncludesBaseInstance:
5600 case QRhi::DepthClamp:
5601 return caps.depthClamp;
5602 case QRhi::DrawIndirect:
5604 case QRhi::DrawIndirectMulti:
5605 return caps.drawIndirectMulti;
5606 case QRhi::ShaderDrawParameters:
5607 return caps.shaderDrawParameters;
5609 Q_UNREACHABLE_RETURN(
false);
5616 case QRhi::TextureSizeMin:
5618 case QRhi::TextureSizeMax:
5619 return int(physDevProperties.limits.maxImageDimension2D);
5620 case QRhi::MaxColorAttachments:
5621 return int(physDevProperties.limits.maxColorAttachments);
5622 case QRhi::FramesInFlight:
5624 case QRhi::MaxAsyncReadbackFrames:
5626 case QRhi::MaxThreadGroupsPerDimension:
5627 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5628 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5629 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5630 case QRhi::MaxThreadsPerThreadGroup:
5631 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5632 case QRhi::MaxThreadGroupX:
5633 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5634 case QRhi::MaxThreadGroupY:
5635 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5636 case QRhi::MaxThreadGroupZ:
5637 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5638 case QRhi::TextureArraySizeMax:
5639 return int(physDevProperties.limits.maxImageArrayLayers);
5640 case QRhi::MaxUniformBufferRange:
5641 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5642 case QRhi::MaxVertexInputs:
5643 return physDevProperties.limits.maxVertexInputAttributes;
5644 case QRhi::MaxVertexOutputs:
5645 return physDevProperties.limits.maxVertexOutputComponents / 4;
5646 case QRhi::ShadingRateImageTileSize:
5647 return caps.imageBasedShadingRateTileSize;
5649 Q_UNREACHABLE_RETURN(0);
5655 return &nativeHandlesStruct;
5660 return driverInfoStruct;
5666 result.totalPipelineCreationTime = totalPipelineCreationTime();
5668 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5669 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5671 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5672 for (uint32_t i = 0; i < count; ++i) {
5673 const VmaStatistics &stats(budgets[i].statistics);
5674 result.blockCount += stats.blockCount;
5675 result.allocCount += stats.allocationCount;
5676 result.usedBytes += stats.allocationBytes;
5677 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5691 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5695 waitSemaphoresForQueueSubmit.clear();
5696 if (sp->waitSemaphoreCount)
5697 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5699 signalSemaphoresForQueueSubmit.clear();
5700 if (sp->signalSemaphoreCount)
5701 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5703 waitSemaphoresForPresent.clear();
5704 if (sp->presentWaitSemaphoreCount)
5705 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5735 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5738 size_t dataSize = 0;
5739 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5740 if (err != VK_SUCCESS) {
5741 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5742 return QByteArray();
5745 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5746 data.resize(dataOffset + dataSize);
5747 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5748 if (err != VK_SUCCESS) {
5749 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5750 return QByteArray();
5754 header.rhiId = pipelineCacheRhiId();
5755 header.arch = quint32(
sizeof(
void*));
5756 header.driverVersion = physDevProperties.driverVersion;
5757 header.vendorId = physDevProperties.vendorID;
5758 header.deviceId = physDevProperties.deviceID;
5759 header.dataSize = quint32(dataSize);
5760 header.uuidSize = VK_UUID_SIZE;
5761 header.reserved = 0;
5762 memcpy(data.data(), &header, headerSize);
5763 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5774 if (data.size() < qsizetype(headerSize)) {
5775 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5779 memcpy(&header, data.constData(), headerSize);
5781 const quint32 rhiId = pipelineCacheRhiId();
5782 if (header.rhiId != rhiId) {
5783 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5784 rhiId, header.rhiId);
5787 const quint32 arch = quint32(
sizeof(
void*));
5788 if (header.arch != arch) {
5789 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5793 if (header.driverVersion != physDevProperties.driverVersion) {
5794 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5795 physDevProperties.driverVersion, header.driverVersion);
5798 if (header.vendorId != physDevProperties.vendorID) {
5799 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5800 physDevProperties.vendorID, header.vendorId);
5803 if (header.deviceId != physDevProperties.deviceID) {
5804 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5805 physDevProperties.deviceID, header.deviceId);
5808 if (header.uuidSize != VK_UUID_SIZE) {
5809 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5810 quint32(VK_UUID_SIZE), header.uuidSize);
5814 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5815 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5818 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5819 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5823 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5824 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5825 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5829 if (pipelineCache) {
5830 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5831 pipelineCache = VK_NULL_HANDLE;
5834 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5835 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5836 int(header.dataSize));
5838 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5842QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5843 int sampleCount, QRhiRenderBuffer::Flags flags,
5844 QRhiTexture::Format backingFormatHint)
5846 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5850 const QSize &pixelSize,
int depth,
int arraySize,
5851 int sampleCount, QRhiTexture::Flags flags)
5853 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5857 QRhiSampler::Filter mipmapMode,
5858 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5860 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5865 return new QVkShadingRateMap(
this);
5869 QRhiTextureRenderTarget::Flags flags)
5876 return new QVkGraphicsPipeline(
this);
5881 return new QVkComputePipeline(
this);
5886 return new QVkShaderResourceBindings(
this);
5892 Q_ASSERT(psD->pipeline);
5896 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5898 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5902 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5903 cmd.args.bindPipeline.pipeline = psD->pipeline;
5906 cbD->currentGraphicsPipeline = ps;
5907 cbD->currentComputePipeline =
nullptr;
5908 cbD->currentPipelineGeneration = psD->generation;
5914 psD->lastActiveFrameSlot = currentFrameSlot;
5918 int dynamicOffsetCount,
5919 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5929 srb = gfxPsD->m_shaderResourceBindings;
5931 srb = compPsD->m_shaderResourceBindings;
5935 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5936 bool rewriteDescSet =
false;
5937 bool addWriteBarrier =
false;
5938 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5939 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5943 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5944 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5947 case QRhiShaderResourceBinding::UniformBuffer:
5950 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5951 sanityCheckResourceOwnership(bufD);
5953 if (bufD->m_type == QRhiBuffer::Dynamic)
5956 bufD->lastActiveFrameSlot = currentFrameSlot;
5957 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5959 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5965 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5966 rewriteDescSet =
true;
5967 bd.ubuf.id = bufD->m_id;
5968 bd.ubuf.generation = bufD->generation;
5972 case QRhiShaderResourceBinding::SampledTexture:
5973 case QRhiShaderResourceBinding::Texture:
5974 case QRhiShaderResourceBinding::Sampler:
5976 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5977 if (bd.stex.count != data->count) {
5978 bd.stex.count = data->count;
5979 rewriteDescSet =
true;
5981 for (
int elem = 0; elem < data->count; ++elem) {
5987 Q_ASSERT(texD || samplerD);
5988 sanityCheckResourceOwnership(texD);
5989 sanityCheckResourceOwnership(samplerD);
5991 texD->lastActiveFrameSlot = currentFrameSlot;
5997 samplerD->lastActiveFrameSlot = currentFrameSlot;
5998 const quint64 texId = texD ? texD->m_id : 0;
5999 const uint texGen = texD ? texD->generation : 0;
6000 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6001 const uint samplerGen = samplerD ? samplerD->generation : 0;
6002 if (texGen != bd.stex.d[elem].texGeneration
6003 || texId != bd.stex.d[elem].texId
6004 || samplerGen != bd.stex.d[elem].samplerGeneration
6005 || samplerId != bd.stex.d[elem].samplerId)
6007 rewriteDescSet =
true;
6008 bd.stex.d[elem].texId = texId;
6009 bd.stex.d[elem].texGeneration = texGen;
6010 bd.stex.d[elem].samplerId = samplerId;
6011 bd.stex.d[elem].samplerGeneration = samplerGen;
6016 case QRhiShaderResourceBinding::ImageLoad:
6017 case QRhiShaderResourceBinding::ImageStore:
6018 case QRhiShaderResourceBinding::ImageLoadStore:
6021 sanityCheckResourceOwnership(texD);
6022 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6023 texD->lastActiveFrameSlot = currentFrameSlot;
6025 if (b->type == QRhiShaderResourceBinding::ImageLoad)
6027 else if (b->type == QRhiShaderResourceBinding::ImageStore)
6032 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6033 const auto prevAccess = passResTracker.textures().find(texD);
6034 if (prevAccess != passResTracker.textures().end()) {
6038 addWriteBarrier =
true;
6039 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6040 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6048 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6049 rewriteDescSet =
true;
6050 bd.simage.id = texD->m_id;
6051 bd.simage.generation = texD->generation;
6055 case QRhiShaderResourceBinding::BufferLoad:
6056 case QRhiShaderResourceBinding::BufferStore:
6057 case QRhiShaderResourceBinding::BufferLoadStore:
6060 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6061 sanityCheckResourceOwnership(bufD);
6063 if (bufD->m_type == QRhiBuffer::Dynamic)
6066 bufD->lastActiveFrameSlot = currentFrameSlot;
6068 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6070 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6075 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6076 const auto prevAccess = passResTracker.buffers().find(bufD);
6077 if (prevAccess != passResTracker.buffers().end()) {
6081 addWriteBarrier =
true;
6082 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6083 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6086 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6090 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6091 rewriteDescSet =
true;
6092 bd.sbuf.id = bufD->m_id;
6093 bd.sbuf.generation = bufD->generation;
6103 if (addWriteBarrier) {
6105 VkMemoryBarrier barrier;
6106 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6107 barrier.pNext =
nullptr;
6108 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6109 barrier.srcAccessMask = barrier.dstAccessMask;
6110 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6117 cmd.args.memoryBarrier.dependencyFlags = 0;
6118 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6119 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6120 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6121 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6127 updateShaderResourceBindings(srb);
6131 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6132 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6134 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6136 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6137 QVarLengthArray<uint32_t, 4> dynOfs;
6142 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6143 uint32_t offset = 0;
6144 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6145 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6146 if (bindingOffsetPair.first == bindingNumber) {
6147 offset = bindingOffsetPair.second;
6151 dynOfs.append(offset);
6155 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6156 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6157 gfxPsD ? gfxPsD->layout : compPsD->layout,
6158 0, 1, &srbD->descSets[currentFrameSlot],
6159 uint32_t(dynOfs.size()),
6160 dynOfs.size() ? dynOfs.constData() :
nullptr);
6164 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6165 : VK_PIPELINE_BIND_POINT_COMPUTE;
6166 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6167 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6168 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6169 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6170 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6174 cbD->currentGraphicsSrb = srb;
6175 cbD->currentComputeSrb =
nullptr;
6177 cbD->currentGraphicsSrb =
nullptr;
6178 cbD->currentComputeSrb = srb;
6180 cbD->currentSrbGeneration = srbD->generation;
6181 cbD->currentDescSetSlot = currentFrameSlot;
6184 srbD->lastActiveFrameSlot = currentFrameSlot;
6188 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6189 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6195 bool needsBindVBuf =
false;
6196 for (
int i = 0; i < bindingCount; ++i) {
6197 const int inputSlot = startBinding + i;
6199 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6200 bufD->lastActiveFrameSlot = currentFrameSlot;
6201 if (bufD->m_type == QRhiBuffer::Dynamic)
6204 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6205 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6206 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6208 needsBindVBuf =
true;
6209 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6210 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6214 if (needsBindVBuf) {
6215 QVarLengthArray<VkBuffer, 4> bufs;
6216 QVarLengthArray<VkDeviceSize, 4> ofs;
6217 for (
int i = 0; i < bindingCount; ++i) {
6219 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6220 bufs.append(bufD->buffers[slot]);
6221 ofs.append(bindings[i].second);
6228 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6229 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6233 cmd.args.bindVertexBuffer.startBinding = startBinding;
6234 cmd.args.bindVertexBuffer.count = bufs.size();
6235 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6236 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6237 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6238 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6244 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6245 ibufD->lastActiveFrameSlot = currentFrameSlot;
6246 if (ibufD->m_type == QRhiBuffer::Dynamic)
6249 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6250 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6251 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6252 : VK_INDEX_TYPE_UINT32;
6254 if (cbD->currentIndexBuffer != vkindexbuf
6255 || cbD->currentIndexOffset != indexOffset
6256 || cbD->currentIndexFormat != type)
6258 cbD->currentIndexBuffer = vkindexbuf;
6259 cbD->currentIndexOffset = indexOffset;
6260 cbD->currentIndexFormat = type;
6263 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6267 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6268 cmd.args.bindIndexBuffer.ofs = indexOffset;
6269 cmd.args.bindIndexBuffer.type = type;
6283 const QSize outputSize = cbD->currentTarget->pixelSize();
6284 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6285 float x = 0, y = 0, w = 0, h = 0;
6287 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6290 w = outputSize.width();
6291 h = outputSize.height();
6294 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6298 VkRect2D *s = &cmd.args.setScissor.scissor;
6299 s->offset.x = int32_t(x);
6300 s->offset.y = int32_t(y);
6301 s->extent.width = uint32_t(w);
6302 s->extent.height = uint32_t(h);
6305 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6306 cbD->commands.unget();
6316 const QSize outputSize = cbD->currentTarget->pixelSize();
6320 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6324 VkViewport *vp = &cmd.args.setViewport.viewport;
6329 vp->minDepth = viewport.minDepth();
6330 vp->maxDepth = viewport.maxDepth();
6333 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6334 cbD->commands.unget();
6339 cbD->currentViewport = viewport;
6340 if (cbD->currentGraphicsPipeline
6341 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6351 Q_ASSERT(!cbD->currentGraphicsPipeline
6353 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6354 const QSize outputSize = cbD->currentTarget->pixelSize();
6358 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6362 VkRect2D *s = &cmd.args.setScissor.scissor;
6365 s->extent.width = uint32_t(w);
6366 s->extent.height = uint32_t(h);
6369 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6370 cbD->commands.unget();
6384 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6385 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6389 cmd.args.setBlendConstants.c[0] = c.redF();
6390 cmd.args.setBlendConstants.c[1] = c.greenF();
6391 cmd.args.setBlendConstants.c[2] = c.blueF();
6392 cmd.args.setBlendConstants.c[3] = c.alphaF();
6402 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6406 cmd.args.setStencilRef.ref = refValue;
6412#ifdef VK_KHR_fragment_shading_rate
6413 if (!vkCmdSetFragmentShadingRateKHR)
6416 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6417 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6418 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6420 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6421 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6422 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6424 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6425 if (cbD->passUsesSecondaryCb) {
6426 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6428 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6429 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6430 cmd.args.setShadingRate.w = size.width;
6431 cmd.args.setShadingRate.h = size.height;
6433 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6434 cbD->hasShadingRateSet =
true;
6437 Q_UNUSED(coarsePixelSize);
6442 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6448 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6452 cmd.args.draw.vertexCount = vertexCount;
6453 cmd.args.draw.instanceCount = instanceCount;
6454 cmd.args.draw.firstVertex = firstVertex;
6455 cmd.args.draw.firstInstance = firstInstance;
6460 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6466 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6467 firstIndex, vertexOffset, firstInstance);
6471 cmd.args.drawIndexed.indexCount = indexCount;
6472 cmd.args.drawIndexed.instanceCount = instanceCount;
6473 cmd.args.drawIndexed.firstIndex = firstIndex;
6474 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6475 cmd.args.drawIndexed.firstInstance = firstInstance;
6480 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6487 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6488 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6490 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6494 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6497 if (caps.drawIndirectMulti) {
6498 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6499 indirectBufVk, indirectBufferOffset,
6502 VkDeviceSize offset = indirectBufferOffset;
6503 for (quint32 i = 0; i < drawCount; ++i) {
6504 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6505 indirectBufVk, offset,
6511 if (caps.drawIndirectMulti) {
6514 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6515 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6516 cmd.args.drawIndirect.drawCount = drawCount;
6517 cmd.args.drawIndirect.stride = stride;
6519 VkDeviceSize offset = indirectBufferOffset;
6520 for (quint32 i = 0; i < drawCount; ++i) {
6523 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6524 cmd.args.drawIndirect.indirectBufferOffset = offset;
6525 cmd.args.drawIndirect.drawCount = 1;
6526 cmd.args.drawIndirect.stride = stride;
6534 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6541 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6542 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6544 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6548 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6551 if (caps.drawIndirectMulti) {
6552 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6553 indirectBufVk, indirectBufferOffset,
6556 VkDeviceSize offset = indirectBufferOffset;
6557 for (quint32 i = 0; i < drawCount; ++i) {
6558 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6559 indirectBufVk, offset,
6565 if (caps.drawIndirectMulti) {
6568 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6569 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
6570 cmd.args.drawIndexedIndirect.drawCount = drawCount;
6571 cmd.args.drawIndexedIndirect.stride = stride;
6573 VkDeviceSize offset = indirectBufferOffset;
6574 for (quint32 i = 0; i < drawCount; ++i) {
6577 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6578 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
6579 cmd.args.drawIndexedIndirect.drawCount = 1;
6580 cmd.args.drawIndexedIndirect.stride = stride;
6589#ifdef VK_EXT_debug_utils
6590 if (!debugMarkers || !caps.debugUtils)
6593 VkDebugUtilsLabelEXT label = {};
6594 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6596 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6597 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6598 label.pLabelName = name.constData();
6599 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6601 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6602 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6603 cmd.args.debugMarkerBegin.label = label;
6604 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6605 cbD->pools.debugMarkerData.append(name);
6615#ifdef VK_EXT_debug_utils
6616 if (!debugMarkers || !caps.debugUtils)
6619 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6620 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6621 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6623 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6624 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6633#ifdef VK_EXT_debug_utils
6634 if (!debugMarkers || !caps.debugUtils)
6637 VkDebugUtilsLabelEXT label = {};
6638 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6640 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6641 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6642 label.pLabelName = msg.constData();
6643 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6645 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6646 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6647 cmd.args.debugMarkerInsert.label = label;
6648 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6649 cbD->pools.debugMarkerData.append(msg);
6659 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6664 Q_ASSERT(cbD->currentTarget);
6667 switch (cbD->currentTarget->resourceType()) {
6668 case QRhiResource::SwapChainRenderTarget:
6671 case QRhiResource::TextureRenderTarget:
6703 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6704 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6708 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6709 cbD->activeSecondaryCbStack.removeLast();
6710 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6712 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6714 cbD->activeSecondaryCbStack.append(extCb);
6726 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6727 cbD->activeSecondaryCbStack.removeLast();
6728 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6729 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6743 if (!debugMarkers || name.isEmpty())
6746 QByteArray decoratedName = name;
6748 decoratedName +=
'/';
6749 decoratedName += QByteArray::number(slot);
6751 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6756#ifdef VK_EXT_debug_utils
6757 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6760 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6761 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6762 nameInfo.objectType = type;
6763 nameInfo.objectHandle = object;
6764 QByteArray decoratedName = name;
6766 decoratedName +=
'/';
6767 decoratedName += QByteArray::number(slot);
6769 nameInfo.pObjectName = decoratedName.constData();
6770 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6782 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6783 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6784 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6785 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6786 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6787 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6788 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6789 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6790 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
6791 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
6792 return VkBufferUsageFlagBits(u);
6798 case QRhiSampler::Nearest:
6799 return VK_FILTER_NEAREST;
6800 case QRhiSampler::Linear:
6801 return VK_FILTER_LINEAR;
6803 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6810 case QRhiSampler::None:
6811 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6812 case QRhiSampler::Nearest:
6813 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6814 case QRhiSampler::Linear:
6815 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6817 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6824 case QRhiSampler::Repeat:
6825 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6826 case QRhiSampler::ClampToEdge:
6827 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6828 case QRhiSampler::Mirror:
6829 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6831 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6838 case QRhiShaderStage::Vertex:
6839 return VK_SHADER_STAGE_VERTEX_BIT;
6840 case QRhiShaderStage::TessellationControl:
6841 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6842 case QRhiShaderStage::TessellationEvaluation:
6843 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6844 case QRhiShaderStage::Fragment:
6845 return VK_SHADER_STAGE_FRAGMENT_BIT;
6846 case QRhiShaderStage::Compute:
6847 return VK_SHADER_STAGE_COMPUTE_BIT;
6848 case QRhiShaderStage::Geometry:
6849 return VK_SHADER_STAGE_GEOMETRY_BIT;
6851 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6858 case QRhiVertexInputAttribute::Float4:
6859 return VK_FORMAT_R32G32B32A32_SFLOAT;
6860 case QRhiVertexInputAttribute::Float3:
6861 return VK_FORMAT_R32G32B32_SFLOAT;
6862 case QRhiVertexInputAttribute::Float2:
6863 return VK_FORMAT_R32G32_SFLOAT;
6864 case QRhiVertexInputAttribute::Float:
6865 return VK_FORMAT_R32_SFLOAT;
6866 case QRhiVertexInputAttribute::UNormByte4:
6867 return VK_FORMAT_R8G8B8A8_UNORM;
6868 case QRhiVertexInputAttribute::UNormByte2:
6869 return VK_FORMAT_R8G8_UNORM;
6870 case QRhiVertexInputAttribute::UNormByte:
6871 return VK_FORMAT_R8_UNORM;
6872 case QRhiVertexInputAttribute::UInt4:
6873 return VK_FORMAT_R32G32B32A32_UINT;
6874 case QRhiVertexInputAttribute::UInt3:
6875 return VK_FORMAT_R32G32B32_UINT;
6876 case QRhiVertexInputAttribute::UInt2:
6877 return VK_FORMAT_R32G32_UINT;
6878 case QRhiVertexInputAttribute::UInt:
6879 return VK_FORMAT_R32_UINT;
6880 case QRhiVertexInputAttribute::SInt4:
6881 return VK_FORMAT_R32G32B32A32_SINT;
6882 case QRhiVertexInputAttribute::SInt3:
6883 return VK_FORMAT_R32G32B32_SINT;
6884 case QRhiVertexInputAttribute::SInt2:
6885 return VK_FORMAT_R32G32_SINT;
6886 case QRhiVertexInputAttribute::SInt:
6887 return VK_FORMAT_R32_SINT;
6888 case QRhiVertexInputAttribute::Half4:
6889 return VK_FORMAT_R16G16B16A16_SFLOAT;
6890 case QRhiVertexInputAttribute::Half3:
6891 return VK_FORMAT_R16G16B16_SFLOAT;
6892 case QRhiVertexInputAttribute::Half2:
6893 return VK_FORMAT_R16G16_SFLOAT;
6894 case QRhiVertexInputAttribute::Half:
6895 return VK_FORMAT_R16_SFLOAT;
6896 case QRhiVertexInputAttribute::UShort4:
6897 return VK_FORMAT_R16G16B16A16_UINT;
6898 case QRhiVertexInputAttribute::UShort3:
6899 return VK_FORMAT_R16G16B16_UINT;
6900 case QRhiVertexInputAttribute::UShort2:
6901 return VK_FORMAT_R16G16_UINT;
6902 case QRhiVertexInputAttribute::UShort:
6903 return VK_FORMAT_R16_UINT;
6904 case QRhiVertexInputAttribute::SShort4:
6905 return VK_FORMAT_R16G16B16A16_SINT;
6906 case QRhiVertexInputAttribute::SShort3:
6907 return VK_FORMAT_R16G16B16_SINT;
6908 case QRhiVertexInputAttribute::SShort2:
6909 return VK_FORMAT_R16G16_SINT;
6910 case QRhiVertexInputAttribute::SShort:
6911 return VK_FORMAT_R16_SINT;
6913 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6920 case QRhiGraphicsPipeline::Triangles:
6921 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6922 case QRhiGraphicsPipeline::TriangleStrip:
6923 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6924 case QRhiGraphicsPipeline::TriangleFan:
6925 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6926 case QRhiGraphicsPipeline::Lines:
6927 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6928 case QRhiGraphicsPipeline::LineStrip:
6929 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6930 case QRhiGraphicsPipeline::Points:
6931 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6932 case QRhiGraphicsPipeline::Patches:
6933 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6935 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6942 case QRhiGraphicsPipeline::None:
6943 return VK_CULL_MODE_NONE;
6944 case QRhiGraphicsPipeline::Front:
6945 return VK_CULL_MODE_FRONT_BIT;
6946 case QRhiGraphicsPipeline::Back:
6947 return VK_CULL_MODE_BACK_BIT;
6949 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6956 case QRhiGraphicsPipeline::CCW:
6957 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6958 case QRhiGraphicsPipeline::CW:
6959 return VK_FRONT_FACE_CLOCKWISE;
6961 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6968 if (c.testFlag(QRhiGraphicsPipeline::R))
6969 f |= VK_COLOR_COMPONENT_R_BIT;
6970 if (c.testFlag(QRhiGraphicsPipeline::G))
6971 f |= VK_COLOR_COMPONENT_G_BIT;
6972 if (c.testFlag(QRhiGraphicsPipeline::B))
6973 f |= VK_COLOR_COMPONENT_B_BIT;
6974 if (c.testFlag(QRhiGraphicsPipeline::A))
6975 f |= VK_COLOR_COMPONENT_A_BIT;
6976 return VkColorComponentFlags(f);
6982 case QRhiGraphicsPipeline::Zero:
6983 return VK_BLEND_FACTOR_ZERO;
6984 case QRhiGraphicsPipeline::One:
6985 return VK_BLEND_FACTOR_ONE;
6986 case QRhiGraphicsPipeline::SrcColor:
6987 return VK_BLEND_FACTOR_SRC_COLOR;
6988 case QRhiGraphicsPipeline::OneMinusSrcColor:
6989 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6990 case QRhiGraphicsPipeline::DstColor:
6991 return VK_BLEND_FACTOR_DST_COLOR;
6992 case QRhiGraphicsPipeline::OneMinusDstColor:
6993 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6994 case QRhiGraphicsPipeline::SrcAlpha:
6995 return VK_BLEND_FACTOR_SRC_ALPHA;
6996 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6997 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6998 case QRhiGraphicsPipeline::DstAlpha:
6999 return VK_BLEND_FACTOR_DST_ALPHA;
7000 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7001 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7002 case QRhiGraphicsPipeline::ConstantColor:
7003 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7004 case QRhiGraphicsPipeline::OneMinusConstantColor:
7005 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7006 case QRhiGraphicsPipeline::ConstantAlpha:
7007 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7008 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7009 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7010 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7011 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7012 case QRhiGraphicsPipeline::Src1Color:
7013 return VK_BLEND_FACTOR_SRC1_COLOR;
7014 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7015 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7016 case QRhiGraphicsPipeline::Src1Alpha:
7017 return VK_BLEND_FACTOR_SRC1_ALPHA;
7018 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7019 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7021 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7028 case QRhiGraphicsPipeline::Add:
7029 return VK_BLEND_OP_ADD;
7030 case QRhiGraphicsPipeline::Subtract:
7031 return VK_BLEND_OP_SUBTRACT;
7032 case QRhiGraphicsPipeline::ReverseSubtract:
7033 return VK_BLEND_OP_REVERSE_SUBTRACT;
7034 case QRhiGraphicsPipeline::Min:
7035 return VK_BLEND_OP_MIN;
7036 case QRhiGraphicsPipeline::Max:
7037 return VK_BLEND_OP_MAX;
7039 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7046 case QRhiGraphicsPipeline::Never:
7047 return VK_COMPARE_OP_NEVER;
7048 case QRhiGraphicsPipeline::Less:
7049 return VK_COMPARE_OP_LESS;
7050 case QRhiGraphicsPipeline::Equal:
7051 return VK_COMPARE_OP_EQUAL;
7052 case QRhiGraphicsPipeline::LessOrEqual:
7053 return VK_COMPARE_OP_LESS_OR_EQUAL;
7054 case QRhiGraphicsPipeline::Greater:
7055 return VK_COMPARE_OP_GREATER;
7056 case QRhiGraphicsPipeline::NotEqual:
7057 return VK_COMPARE_OP_NOT_EQUAL;
7058 case QRhiGraphicsPipeline::GreaterOrEqual:
7059 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7060 case QRhiGraphicsPipeline::Always:
7061 return VK_COMPARE_OP_ALWAYS;
7063 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7070 case QRhiGraphicsPipeline::StencilZero:
7071 return VK_STENCIL_OP_ZERO;
7072 case QRhiGraphicsPipeline::Keep:
7073 return VK_STENCIL_OP_KEEP;
7074 case QRhiGraphicsPipeline::Replace:
7075 return VK_STENCIL_OP_REPLACE;
7076 case QRhiGraphicsPipeline::IncrementAndClamp:
7077 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7078 case QRhiGraphicsPipeline::DecrementAndClamp:
7079 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7080 case QRhiGraphicsPipeline::Invert:
7081 return VK_STENCIL_OP_INVERT;
7082 case QRhiGraphicsPipeline::IncrementAndWrap:
7083 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7084 case QRhiGraphicsPipeline::DecrementAndWrap:
7085 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7087 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7094 case QRhiGraphicsPipeline::Fill:
7095 return VK_POLYGON_MODE_FILL;
7096 case QRhiGraphicsPipeline::Line:
7097 return VK_POLYGON_MODE_LINE;
7099 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7105 dst->failOp = toVkStencilOp(src.failOp);
7106 dst->passOp = toVkStencilOp(src.passOp);
7107 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7108 dst->compareOp = toVkCompareOp(src.compareOp);
7114 case QRhiShaderResourceBinding::UniformBuffer:
7115 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7116 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7118 case QRhiShaderResourceBinding::SampledTexture:
7119 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7121 case QRhiShaderResourceBinding::Texture:
7122 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7124 case QRhiShaderResourceBinding::Sampler:
7125 return VK_DESCRIPTOR_TYPE_SAMPLER;
7127 case QRhiShaderResourceBinding::ImageLoad:
7128 case QRhiShaderResourceBinding::ImageStore:
7129 case QRhiShaderResourceBinding::ImageLoadStore:
7130 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7132 case QRhiShaderResourceBinding::BufferLoad:
7133 case QRhiShaderResourceBinding::BufferStore:
7134 case QRhiShaderResourceBinding::BufferLoadStore:
7135 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7138 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7145 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7146 s |= VK_SHADER_STAGE_VERTEX_BIT;
7147 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7148 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7149 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7150 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7151 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7152 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7153 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7154 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7155 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7156 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7157 return VkShaderStageFlags(s);
7163 case QRhiSampler::Never:
7164 return VK_COMPARE_OP_NEVER;
7165 case QRhiSampler::Less:
7166 return VK_COMPARE_OP_LESS;
7167 case QRhiSampler::Equal:
7168 return VK_COMPARE_OP_EQUAL;
7169 case QRhiSampler::LessOrEqual:
7170 return VK_COMPARE_OP_LESS_OR_EQUAL;
7171 case QRhiSampler::Greater:
7172 return VK_COMPARE_OP_GREATER;
7173 case QRhiSampler::NotEqual:
7174 return VK_COMPARE_OP_NOT_EQUAL;
7175 case QRhiSampler::GreaterOrEqual:
7176 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7177 case QRhiSampler::Always:
7178 return VK_COMPARE_OP_ALWAYS;
7180 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7188 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7208 e.buffer.buffers[i] = buffers[i];
7210 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7213 buffers[i] = VK_NULL_HANDLE;
7215 stagingBuffers[i] = VK_NULL_HANDLE;
7217 pendingDynamicUpdates[i].clear();
7225 rhiD->releaseQueue.append(e);
7226 rhiD->unregisterResource(
this);
7235 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7236 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7240 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7242 VkBufferCreateInfo bufferInfo = {};
7243 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7244 bufferInfo.size = nonZeroSize;
7245 bufferInfo.usage = toVkBufferUsage(m_usage);
7247 VmaAllocationCreateInfo allocInfo = {};
7249 if (m_type == Dynamic) {
7254 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7257 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7259 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7260 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7264 VkResult err = VK_SUCCESS;
7266 buffers[i] = VK_NULL_HANDLE;
7268 usageState[i].access = usageState[i].stage = 0;
7269 if (i == 0 || m_type == Dynamic) {
7270 VmaAllocation allocation;
7271 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7272 if (err != VK_SUCCESS)
7275 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7276 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7277 m_type == Dynamic ? i : -1);
7281 if (err != VK_SUCCESS) {
7282 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7283 rhiD->printExtraErrorInfo(err);
7289 rhiD->registerResource(
this);
7295 if (m_type == Dynamic) {
7301 b.objects[i] = &buffers[i];
7306 return { { &buffers[0] }, 1 };
7316 Q_ASSERT(m_type == Dynamic);
7318 Q_ASSERT(rhiD->inFrame);
7319 const int slot = rhiD->currentFrameSlot;
7321 VmaAllocation a = toVmaAllocation(allocations[slot]);
7322 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7323 if (err != VK_SUCCESS) {
7324 qWarning(
"Failed to map buffer: %d", err);
7327 return static_cast<
char *>(p);
7333 const int slot = rhiD->currentFrameSlot;
7334 VmaAllocation a = toVmaAllocation(allocations[slot]);
7335 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7336 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7340 int sampleCount, Flags flags,
7341 QRhiTexture::Format backingFormatHint)
7354 if (!memory && !backingTexture)
7361 e.renderBuffer.memory = memory;
7362 e.renderBuffer.image = image;
7363 e.renderBuffer.imageView = imageView;
7365 memory = VK_NULL_HANDLE;
7366 image = VK_NULL_HANDLE;
7367 imageView = VK_NULL_HANDLE;
7377 rhiD->releaseQueue.append(e);
7378 rhiD->unregisterResource(
this);
7384 if (memory || backingTexture)
7387 if (m_pixelSize.isEmpty())
7391 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7394 case QRhiRenderBuffer::Color:
7402 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7410 vkformat = backingTexture->vkformat;
7413 case QRhiRenderBuffer::DepthStencil:
7414 vkformat = rhiD->optimalDepthStencilFormat();
7415 if (!rhiD->createTransientImage(vkformat,
7417 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7418 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7427 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7436 rhiD->registerResource(
this);
7442 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7443 return m_backingFormatHint;
7445 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7449 int arraySize,
int sampleCount, Flags flags)
7453 stagingBuffers[i] = VK_NULL_HANDLE;
7456 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7457 perLevelImageViews[i] = VK_NULL_HANDLE;
7474 e.texture.image = owns ? image : VK_NULL_HANDLE;
7475 e.texture.imageView = imageView;
7479 e.texture.stagingBuffers[i] = stagingBuffers[i];
7482 stagingBuffers[i] = VK_NULL_HANDLE;
7486 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7487 e.texture.extraImageViews[i] = perLevelImageViews[i];
7488 perLevelImageViews[i] = VK_NULL_HANDLE;
7491 image = VK_NULL_HANDLE;
7492 imageView = VK_NULL_HANDLE;
7497 rhiD->releaseQueue.append(e);
7498 rhiD->unregisterResource(
this);
7508 vkformat = toVkTextureFormat(m_format, m_flags);
7509 if (m_writeViewFormat.format != UnknownFormat)
7510 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7512 viewFormat = vkformat;
7513 if (m_readViewFormat.format != UnknownFormat)
7514 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7516 viewFormatForSampling = vkformat;
7518 VkFormatProperties props;
7519 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7520 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7521 if (!canSampleOptimal) {
7522 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7526 const bool isCube = m_flags.testFlag(CubeMap);
7527 const bool isArray = m_flags.testFlag(TextureArray);
7528 const bool is3D = m_flags.testFlag(ThreeDimensional);
7529 const bool is1D = m_flags.testFlag(OneDimensional);
7530 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7532 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7533 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7535 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7536 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7537 if (mipLevelCount > maxLevels) {
7538 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7539 mipLevelCount = maxLevels;
7541 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7542 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7544 qWarning(
"Cubemap texture cannot be multisample");
7548 qWarning(
"3D texture cannot be multisample");
7552 qWarning(
"Multisample texture cannot have mipmaps");
7556 if (isCube && is3D) {
7557 qWarning(
"Texture cannot be both cube and 3D");
7560 if (isArray && is3D) {
7561 qWarning(
"Texture cannot be both array and 3D");
7564 if (isCube && is1D) {
7565 qWarning(
"Texture cannot be both cube and 1D");
7569 qWarning(
"Texture cannot be both 1D and 3D");
7572 if (m_depth > 1 && !is3D) {
7573 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7576 if (m_arraySize > 0 && !isArray) {
7577 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7580 if (m_arraySize < 1 && isArray) {
7581 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7585 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7586 usageState.access = 0;
7587 usageState.stage = 0;
7590 *adjustedSize = size;
7599 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7600 const bool isCube = m_flags.testFlag(CubeMap);
7601 const bool isArray = m_flags.testFlag(TextureArray);
7602 const bool is3D = m_flags.testFlag(ThreeDimensional);
7603 const bool is1D = m_flags.testFlag(OneDimensional);
7605 VkImageViewCreateInfo viewInfo = {};
7606 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7607 viewInfo.image = image;
7608 viewInfo.viewType = isCube
7609 ? VK_IMAGE_VIEW_TYPE_CUBE
7610 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7611 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7612 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7613 viewInfo.format = viewFormatForSampling;
7614 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7615 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7616 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7617 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7618 viewInfo.subresourceRange.aspectMask = aspectMask;
7621 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7622 viewInfo.subresourceRange.levelCount = mipLevelCount;
7623 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7624 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7625 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7627 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7630 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7631 if (err != VK_SUCCESS) {
7632 qWarning(
"Failed to create image view: %d", err);
7645 if (!prepareCreate(&size))
7649 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7650 const bool isDepth = isDepthTextureFormat(m_format);
7651 const bool isCube = m_flags.testFlag(CubeMap);
7652 const bool isArray = m_flags.testFlag(TextureArray);
7653 const bool is3D = m_flags.testFlag(ThreeDimensional);
7654 const bool is1D = m_flags.testFlag(OneDimensional);
7656 VkImageCreateInfo imageInfo = {};
7657 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7658 imageInfo.flags = 0;
7660 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7662 if (is3D && isRenderTarget) {
7668 if (!rhiD->caps.texture3DSliceAs2D)
7669 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7670#ifdef VK_VERSION_1_1
7671 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7673 imageInfo.flags |= 0x00000020;
7677 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7678 imageInfo.format = vkformat;
7679 imageInfo.extent.width = uint32_t(size.width());
7680 imageInfo.extent.height = uint32_t(size.height());
7681 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7682 imageInfo.mipLevels = mipLevelCount;
7683 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7684 imageInfo.samples = samples;
7685 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7686 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7688 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7689 if (isRenderTarget) {
7691 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7693 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7695 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7696 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7697 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7698 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7699 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7700 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7701#ifdef VK_KHR_fragment_shading_rate
7702 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7703 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7706 VmaAllocationCreateInfo allocInfo = {};
7707 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7709 VmaAllocation allocation;
7710 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7711 if (err != VK_SUCCESS) {
7712 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7713 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7714 int(imageInfo.format),
7715 imageInfo.mipLevels,
7716 imageInfo.arrayLayers,
7717 int(imageInfo.samples),
7719 rhiD->printExtraErrorInfo(err);
7723 rhiD->setAllocationName(allocation, m_objectName);
7728 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7731 rhiD->registerResource(
this);
7737 VkImage img = VkImage(src.object);
7741 if (!prepareCreate())
7749 usageState.layout = VkImageLayout(src.layout);
7753 rhiD->registerResource(
this);
7759 return {quint64(image), usageState.layout};
7764 usageState.layout = VkImageLayout(layout);
7769 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7770 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7771 return perLevelImageViews[level];
7773 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7774 const bool isCube = m_flags.testFlag(CubeMap);
7775 const bool isArray = m_flags.testFlag(TextureArray);
7776 const bool is3D = m_flags.testFlag(ThreeDimensional);
7777 const bool is1D = m_flags.testFlag(OneDimensional);
7779 VkImageViewCreateInfo viewInfo = {};
7780 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7781 viewInfo.image = image;
7782 viewInfo.viewType = isCube
7783 ? VK_IMAGE_VIEW_TYPE_CUBE
7784 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7785 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7786 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7787 viewInfo.format = viewFormat;
7788 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7789 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7790 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7791 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7792 viewInfo.subresourceRange.aspectMask = aspectMask;
7793 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7794 viewInfo.subresourceRange.levelCount = 1;
7795 viewInfo.subresourceRange.baseArrayLayer = 0;
7796 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7798 VkImageView v = VK_NULL_HANDLE;
7800 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7801 if (err != VK_SUCCESS) {
7802 qWarning(
"Failed to create image view: %d", err);
7803 return VK_NULL_HANDLE;
7806 perLevelImageViews[level] = v;
7811 AddressMode u, AddressMode v, AddressMode w)
7830 e.sampler.sampler = sampler;
7831 sampler = VK_NULL_HANDLE;
7835 rhiD->releaseQueue.append(e);
7836 rhiD->unregisterResource(
this);
7845 VkSamplerCreateInfo samplerInfo = {};
7846 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7847 samplerInfo.magFilter = toVkFilter(m_magFilter);
7848 samplerInfo.minFilter = toVkFilter(m_minFilter);
7849 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7850 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7851 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7852 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7853 samplerInfo.maxAnisotropy = 1.0f;
7854 samplerInfo.compareEnable = m_compareOp != Never;
7855 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7856 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7859 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7860 if (err != VK_SUCCESS) {
7861 qWarning(
"Failed to create sampler: %d", err);
7867 rhiD->registerResource(
this);
7874 serializedFormatData.reserve(64);
7888 rp = VK_NULL_HANDLE;
7896 e.renderPass.rp = rp;
7898 rp = VK_NULL_HANDLE;
7902 rhiD->releaseQueue.append(e);
7903 rhiD->unregisterResource(
this);
7909 return a.format == b.format
7910 && a.samples == b.samples
7911 && a.loadOp == b.loadOp
7912 && a.storeOp == b.storeOp
7913 && a.stencilLoadOp == b.stencilLoadOp
7914 && a.stencilStoreOp == b.stencilStoreOp
7915 && a.initialLayout == b.initialLayout
7916 && a.finalLayout == b.finalLayout;
7929 if (attDescs.size() != o->attDescs.size())
7931 if (colorRefs.size() != o->colorRefs.size())
7933 if (resolveRefs.size() != o->resolveRefs.size())
7939 if (multiViewCount != o->multiViewCount)
7944 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7945 const uint32_t attIdx = colorRefs[i].attachment;
7946 if (attIdx != o->colorRefs[i].attachment)
7948 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7953 const uint32_t attIdx = dsRef.attachment;
7954 if (attIdx != o->dsRef.attachment)
7956 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7960 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7961 const uint32_t attIdx = resolveRefs[i].attachment;
7962 if (attIdx != o->resolveRefs[i].attachment)
7964 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7969 const uint32_t attIdx = dsResolveRef.attachment;
7970 if (attIdx != o->dsResolveRef.attachment)
7972 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7977 const uint32_t attIdx = shadingRateRef.attachment;
7978 if (attIdx != o->shadingRateRef.attachment)
7980 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7991 serializedFormatData.clear();
7992 auto p =
std::back_inserter(serializedFormatData);
7994 *p++ = attDescs.size();
7995 *p++ = colorRefs.size();
7996 *p++ = resolveRefs.size();
8000 *p++ = multiViewCount;
8002 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8003 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8004 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8005 *p++ = used ? a->format : 0;
8006 *p++ = used ? a->samples : 0;
8007 *p++ = used ? a->loadOp : 0;
8008 *p++ = used ? a->storeOp : 0;
8009 *p++ = used ? a->stencilLoadOp : 0;
8010 *p++ = used ? a->stencilStoreOp : 0;
8011 *p++ = used ? a->initialLayout : 0;
8012 *p++ = used ? a->finalLayout : 0;
8015 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8016 const uint32_t attIdx = colorRefs[i].attachment;
8018 serializeAttachmentData(attIdx);
8022 const uint32_t attIdx = dsRef.attachment;
8024 serializeAttachmentData(attIdx);
8027 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8028 const uint32_t attIdx = resolveRefs[i].attachment;
8030 serializeAttachmentData(attIdx);
8034 const uint32_t attIdx = dsResolveRef.attachment;
8036 serializeAttachmentData(attIdx);
8040 const uint32_t attIdx = shadingRateRef.attachment;
8042 serializeAttachmentData(attIdx);
8051 rpD->attDescs = attDescs;
8052 rpD->colorRefs = colorRefs;
8053 rpD->resolveRefs = resolveRefs;
8054 rpD->subpassDeps = subpassDeps;
8058 rpD->multiViewCount = multiViewCount;
8060 rpD->dsResolveRef = dsResolveRef;
8061 rpD->shadingRateRef = shadingRateRef;
8063 VkRenderPassCreateInfo rpInfo;
8064 VkSubpassDescription subpassDesc;
8065 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8069 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8074#ifdef VK_KHR_create_renderpass2
8075 if (rhiD->caps.renderPass2KHR) {
8077 VkRenderPassCreateInfo2KHR rpInfo2;
8078 RenderPass2SetupHelper rp2Helper(rhiD);
8079 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8083 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8084 if (err != VK_SUCCESS) {
8085 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8092 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8093 if (err != VK_SUCCESS) {
8094 qWarning(
"Failed to create renderpass: %d", err);
8101 rhiD->registerResource(rpD);
8107 return serializedFormatData;
8112 nativeHandlesStruct.renderPass = rp;
8113 return &nativeHandlesStruct;
8139 texture =
QRHI_RES(QVkTexture, src);
8171 return d.sampleCount;
8175 const QRhiTextureRenderTargetDescription &desc,
8180 rtv[att] = VK_NULL_HANDLE;
8181 resrtv[att] = VK_NULL_HANDLE;
8199 e.textureRenderTarget.fb = d.fb;
8200 d.fb = VK_NULL_HANDLE;
8203 e.textureRenderTarget.rtv[att] = rtv[att];
8204 e.textureRenderTarget.resrtv[att] = resrtv[att];
8205 rtv[att] = VK_NULL_HANDLE;
8206 resrtv[att] = VK_NULL_HANDLE;
8209 e.textureRenderTarget.dsv = dsv;
8210 dsv = VK_NULL_HANDLE;
8211 e.textureRenderTarget.resdsv = resdsv;
8212 resdsv = VK_NULL_HANDLE;
8214 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8215 shadingRateMapView = VK_NULL_HANDLE;
8219 rhiD->releaseQueue.append(e);
8220 rhiD->unregisterResource(
this);
8230 if (!rhiD->createOffscreenRenderPass(rp,
8231 m_desc.cbeginColorAttachments(),
8232 m_desc.cendColorAttachments(),
8233 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8234 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8235 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8236 m_desc.depthStencilBuffer(),
8237 m_desc.depthTexture(),
8238 m_desc.depthResolveTexture(),
8239 m_desc.depthLayer(),
8240 m_desc.shadingRateMap()))
8248 rhiD->registerResource(rp);
8257 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8258 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8259 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8262 QVarLengthArray<VkImageView, 8> views;
8263 d.multiViewCount = 0;
8265 d.colorAttCount = 0;
8267 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8268 d.colorAttCount += 1;
8271 Q_ASSERT(texD || rbD);
8273 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8274 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8275 const bool isMultiView = it->multiViewCount() >= 2;
8276 if (isMultiView && d.multiViewCount == 0)
8277 d.multiViewCount = it->multiViewCount();
8278 VkImageViewCreateInfo viewInfo = {};
8279 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8280 viewInfo.image = texD->image;
8281 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8282 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8283 : VK_IMAGE_VIEW_TYPE_2D);
8284 viewInfo.format = texD->viewFormat;
8285 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8286 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8287 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8288 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8289 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8290 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8291 viewInfo.subresourceRange.levelCount = 1;
8292 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8293 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8294 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8295 if (err != VK_SUCCESS) {
8296 qWarning(
"Failed to create render target image view: %d", err);
8299 views.append(rtv[attIndex]);
8300 if (attIndex == 0) {
8301 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8302 d.sampleCount = texD->samples;
8307 if (attIndex == 0) {
8308 d.pixelSize = rbD->pixelSize();
8309 d.sampleCount = rbD->samples;
8315 if (hasDepthStencil) {
8316 if (m_desc.depthTexture()) {
8319 VkImageViewCreateInfo viewInfo = {};
8320 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8321 viewInfo.image = depthTexD->image;
8322 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8323 viewInfo.format = depthTexD->viewFormat;
8324 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8325 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8326 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8327 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8328 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8329 viewInfo.subresourceRange.levelCount = 1;
8330 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8331 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8332 viewInfo.subresourceRange.layerCount = 1;
8335 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8336 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8337 if (err != VK_SUCCESS) {
8338 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8342 if (d.colorAttCount == 0) {
8343 d.pixelSize = depthTexD->pixelSize();
8344 d.sampleCount = depthTexD->samples;
8348 views.append(depthRbD->imageView);
8349 if (d.colorAttCount == 0) {
8350 d.pixelSize = depthRbD->pixelSize();
8351 d.sampleCount = depthRbD->samples;
8359 d.resolveAttCount = 0;
8361 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8362 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8363 if (it->resolveTexture()) {
8365 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8366 d.resolveAttCount += 1;
8368 VkImageViewCreateInfo viewInfo = {};
8369 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8370 viewInfo.image = resTexD->image;
8371 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8372 : VK_IMAGE_VIEW_TYPE_2D;
8373 viewInfo.format = resTexD->viewFormat;
8374 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8375 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8376 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8377 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8378 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8379 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8380 viewInfo.subresourceRange.levelCount = 1;
8381 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8382 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8383 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8384 if (err != VK_SUCCESS) {
8385 qWarning(
"Failed to create render target resolve image view: %d", err);
8388 views.append(resrtv[attIndex]);
8392 if (m_desc.depthResolveTexture()) {
8394 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8396 VkImageViewCreateInfo viewInfo = {};
8397 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8398 viewInfo.image = resTexD->image;
8399 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8400 : VK_IMAGE_VIEW_TYPE_2D;
8401 viewInfo.format = resTexD->viewFormat;
8402 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8403 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8404 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8405 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8406 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8407 viewInfo.subresourceRange.baseMipLevel = 0;
8408 viewInfo.subresourceRange.levelCount = 1;
8409 viewInfo.subresourceRange.baseArrayLayer = 0;
8410 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8411 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8412 if (err != VK_SUCCESS) {
8413 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8416 views.append(resdsv);
8417 d.dsResolveAttCount = 1;
8419 d.dsResolveAttCount = 0;
8422 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8424 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8426 VkImageViewCreateInfo viewInfo = {};
8427 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8428 viewInfo.image = texD->image;
8429 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8430 : VK_IMAGE_VIEW_TYPE_2D;
8431 viewInfo.format = texD->viewFormat;
8432 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8433 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8434 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8435 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8436 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8437 viewInfo.subresourceRange.baseMipLevel = 0;
8438 viewInfo.subresourceRange.levelCount = 1;
8439 viewInfo.subresourceRange.baseArrayLayer = 0;
8440 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8441 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8442 if (err != VK_SUCCESS) {
8443 qWarning(
"Failed to create render target shading rate map view: %d", err);
8446 views.append(shadingRateMapView);
8447 d.shadingRateAttCount = 1;
8449 d.shadingRateAttCount = 0;
8452 if (!m_renderPassDesc)
8453 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8455 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8456 Q_ASSERT(d.rp && d.rp->rp);
8458 VkFramebufferCreateInfo fbInfo = {};
8459 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8460 fbInfo.renderPass = d.rp->rp;
8461 fbInfo.attachmentCount = uint32_t(views.count());
8462 fbInfo.pAttachments = views.constData();
8463 fbInfo.width = uint32_t(d.pixelSize.width());
8464 fbInfo.height = uint32_t(d.pixelSize.height());
8467 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8468 if (err != VK_SUCCESS) {
8469 qWarning(
"Failed to create framebuffer: %d", err);
8473 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8476 rhiD->registerResource(
this);
8482 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8495 return d.sampleCount;
8513 sortedBindings.clear();
8514 sortedDynamicOffsetBindingNumbers.clear();
8520 e.shaderResourceBindings.poolIndex =
poolIndex;
8521 e.shaderResourceBindings.layout = layout;
8524 layout = VK_NULL_HANDLE;
8525 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8526 descSets[i] = VK_NULL_HANDLE;
8530 rhiD->releaseQueue.append(e);
8531 rhiD->unregisterResource(
this);
8541 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8544 rhiD->updateLayoutDesc(
this);
8546 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8547 descSets[i] = VK_NULL_HANDLE;
8549 sortedBindings.clear();
8550 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8551 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8553 sortedDynamicOffsetBindingNumbers.clear();
8554 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8555 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8556 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8557 if (b->u.ubuf.hasDynamicOffset)
8558 sortedDynamicOffsetBindingNumbers.append(b->binding);
8562 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
8563 vkbindings.reserve(sortedBindings.size());
8564 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8565 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8566 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
8567 vkbinding.binding = uint32_t(b->binding);
8568 vkbinding.descriptorType = toVkDescriptorType(b);
8569 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8570 vkbinding.descriptorCount = b->u.stex.count;
8572 vkbinding.descriptorCount = 1;
8573 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8576 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8577 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8578 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8579 layoutInfo.pBindings = vkbindings.constData();
8581 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8582 if (err != VK_SUCCESS) {
8583 qWarning(
"Failed to create descriptor set layout: %d", err);
8586 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
8588 VkDescriptorSetAllocateInfo allocInfo = {};
8589 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8592 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8593 layouts[i] = layout;
8594 allocInfo.pSetLayouts = layouts;
8595 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8599 boundResourceData[i].resize(sortedBindings.size());
8600 for (BoundResourceData &bd : boundResourceData[i])
8601 memset(&bd, 0,
sizeof(BoundResourceData));
8605 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
8609 rhiD->registerResource(
this);
8615 sortedBindings.clear();
8616 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8617 if (!flags.testFlag(BindingsAreSorted))
8618 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8620 sortedDynamicOffsetBindingNumbers.clear();
8621 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8622 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8623 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8624 if (b->u.ubuf.hasDynamicOffset)
8625 sortedDynamicOffsetBindingNumbers.append(b->binding);
8639 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8640 for (BoundResourceData &bd : boundResourceData[i])
8641 memset(&bd, 0,
sizeof(BoundResourceData));
8659 if (!pipeline && !layout)
8666 e.pipelineState.pipeline = pipeline;
8667 e.pipelineState.layout = layout;
8669 pipeline = VK_NULL_HANDLE;
8670 layout = VK_NULL_HANDLE;
8674 rhiD->releaseQueue.append(e);
8675 rhiD->unregisterResource(
this);
8681 if (pipeline || layout)
8685 rhiD->pipelineCreationStart();
8686 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8689 if (!rhiD->ensurePipelineCache())
8692 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8693 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8694 pipelineLayoutInfo.setLayoutCount = 1;
8696 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8697 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8698 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8699 if (err != VK_SUCCESS) {
8700 qWarning(
"Failed to create pipeline layout: %d", err);
8703 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
8704 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
8705 layout = VK_NULL_HANDLE;
8708 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8709 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8711 QVarLengthArray<VkShaderModule, 4> shaders;
8712 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
8713 for (VkShaderModule shader : shaders)
8714 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8716 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8717 QVarLengthArray<QByteArray, 4> entryPointNames;
8718 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8719 const QShader bakedShader = shaderStage.shader();
8720 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8721 if (spirv.shader().isEmpty()) {
8722 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8725 VkShaderModule shader = rhiD->createShader(spirv.shader());
8727 shaders.append(shader);
8728 VkPipelineShaderStageCreateInfo shaderInfo = {};
8729 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8730 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8731 shaderInfo.module = shader;
8732 entryPointNames.append(spirv.entryPoint());
8733 shaderInfo.pName =
nullptr;
8734 shaderStageCreateInfos.append(shaderInfo);
8739 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
8740 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
8742 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8743 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8745 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8746#ifdef VK_EXT_vertex_attribute_divisor
8747 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8749 int bindingIndex = 0;
8750 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8751 it != itEnd; ++it, ++bindingIndex)
8753 VkVertexInputBindingDescription bindingInfo = {
8754 uint32_t(bindingIndex),
8756 it->classification() == QRhiVertexInputBinding::PerVertex
8757 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8759 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8760#ifdef VK_EXT_vertex_attribute_divisor
8761 if (rhiD->caps.vertexAttribDivisor) {
8762 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8766 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8767 "VK_EXT_vertex_attribute_divisor on the device and "
8768 "VK_KHR_get_physical_device_properties2 on the instance");
8771 vertexBindings.append(bindingInfo);
8773 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8774 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8777 VkVertexInputAttributeDescription attributeInfo = {
8778 uint32_t(it->location()),
8779 uint32_t(it->binding()),
8780 toVkAttributeFormat(it->format()),
8783 vertexAttributes.append(attributeInfo);
8785 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8786 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8787 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8788 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8789 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8790 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8791#ifdef VK_EXT_vertex_attribute_divisor
8792 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8793 if (!nonOneStepRates.isEmpty()) {
8794 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8795 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8796 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8797 vertexInputInfo.pNext = &divisorInfo;
8800 pipelineInfo.pVertexInputState = &vertexInputInfo;
8802 QVarLengthArray<VkDynamicState, 8> dynEnable;
8803 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8804 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8805 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8806 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8807 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8808 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8809#ifdef VK_KHR_fragment_shading_rate
8810 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8811 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8814 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8815 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8816 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8817 dynamicInfo.pDynamicStates = dynEnable.constData();
8818 pipelineInfo.pDynamicState = &dynamicInfo;
8820 VkPipelineViewportStateCreateInfo viewportInfo = {};
8821 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8822 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8823 pipelineInfo.pViewportState = &viewportInfo;
8825 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8826 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8827 inputAsmInfo.topology = toVkTopology(m_topology);
8828 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8829 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8831 VkPipelineTessellationStateCreateInfo tessInfo = {};
8832#ifdef VK_VERSION_1_1
8833 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8835 if (m_topology == Patches) {
8836 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8837 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8844#ifdef VK_VERSION_1_1
8845 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8846 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8847 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8848 tessInfo.pNext = &originInfo;
8850 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8853 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8856 pipelineInfo.pTessellationState = &tessInfo;
8859 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8860 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8861 if (m_depthClamp && rhiD->caps.depthClamp)
8862 rastInfo.depthClampEnable = m_depthClamp;
8863 rastInfo.cullMode = toVkCullMode(m_cullMode);
8864 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8865 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8866 rastInfo.depthBiasEnable =
true;
8867 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8868 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8870 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8871 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8872 pipelineInfo.pRasterizationState = &rastInfo;
8874 VkPipelineMultisampleStateCreateInfo msInfo = {};
8875 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8876 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8877 pipelineInfo.pMultisampleState = &msInfo;
8879 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8880 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8881 dsInfo.depthTestEnable = m_depthTest;
8882 dsInfo.depthWriteEnable = m_depthWrite;
8883 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8884 dsInfo.stencilTestEnable = m_stencilTest;
8885 if (m_stencilTest) {
8886 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8887 dsInfo.front.compareMask = m_stencilReadMask;
8888 dsInfo.front.writeMask = m_stencilWriteMask;
8889 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8890 dsInfo.back.compareMask = m_stencilReadMask;
8891 dsInfo.back.writeMask = m_stencilWriteMask;
8893 pipelineInfo.pDepthStencilState = &dsInfo;
8895 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8896 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8897 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8898 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8899 VkPipelineColorBlendAttachmentState blend = {};
8900 blend.blendEnable = b.enable;
8901 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8902 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8903 blend.colorBlendOp = toVkBlendOp(b.opColor);
8904 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8905 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8906 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8907 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8908 vktargetBlends.append(blend);
8910 if (vktargetBlends.isEmpty()) {
8911 VkPipelineColorBlendAttachmentState blend = {};
8912 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8913 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8914 vktargetBlends.append(blend);
8916 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8917 blendInfo.pAttachments = vktargetBlends.constData();
8918 pipelineInfo.pColorBlendState = &blendInfo;
8920 pipelineInfo.layout = layout;
8922 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8923 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8925 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8927 if (err != VK_SUCCESS) {
8928 qWarning(
"Failed to create graphics pipeline: %d", err);
8931 pipelineLayoutCleanup.dismiss();
8933 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8935 rhiD->pipelineCreationEnd();
8938 rhiD->registerResource(
this);
8954 if (!pipeline && !layout)
8961 e.pipelineState.pipeline = pipeline;
8962 e.pipelineState.layout = layout;
8964 pipeline = VK_NULL_HANDLE;
8965 layout = VK_NULL_HANDLE;
8969 rhiD->releaseQueue.append(e);
8970 rhiD->unregisterResource(
this);
8976 if (pipeline || layout)
8980 rhiD->pipelineCreationStart();
8981 if (!rhiD->ensurePipelineCache())
8984 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8985 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8986 pipelineLayoutInfo.setLayoutCount = 1;
8988 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8989 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8990 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8991 if (err != VK_SUCCESS) {
8992 qWarning(
"Failed to create pipeline layout: %d", err);
8995 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
8996 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
8997 layout = VK_NULL_HANDLE;
9000 VkComputePipelineCreateInfo pipelineInfo = {};
9001 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9002 pipelineInfo.layout = layout;
9004 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9005 qWarning(
"Compute pipeline requires a compute shader stage");
9008 const QShader bakedShader = m_shaderStage.shader();
9009 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9010 if (spirv.shader().isEmpty()) {
9011 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9014 if (bakedShader.stage() != QShader::ComputeStage) {
9015 qWarning() << bakedShader <<
"is not a compute shader";
9018 VkShaderModule shader = rhiD->createShader(spirv.shader());
9021 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9022 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9024 VkPipelineShaderStageCreateInfo shaderInfo = {};
9025 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9026 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9027 shaderInfo.module = shader;
9028 const QByteArray entryPointName = spirv.entryPoint();
9029 shaderInfo.pName = entryPointName.constData();
9030 pipelineInfo.stage = shaderInfo;
9032 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9033 if (err != VK_SUCCESS) {
9034 qWarning(
"Failed to create graphics pipeline: %d", err);
9037 pipelineLayoutCleanup.dismiss();
9039 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9041 rhiD->pipelineCreationEnd();
9044 rhiD->registerResource(
this);
9073 nativeHandlesStruct.commandBuffer = cb;
9075 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9076 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9078 nativeHandlesStruct.commandBuffer = cb;
9081 return &nativeHandlesStruct;
9099 if (sc == VK_NULL_HANDLE)
9104 rhiD->swapchains.remove(
this);
9110 frame.cmdBuf = VK_NULL_HANDLE;
9114 surface = lastConnectedSurface = VK_NULL_HANDLE;
9117 rhiD->unregisterResource(
this);
9132 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9142 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9144 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9145 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9146 if (bufferSize.width == uint32_t(-1)) {
9147 Q_ASSERT(bufferSize.height == uint32_t(-1));
9148 return m_window->size() * m_window->devicePixelRatio();
9150 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9156 case QRhiSwapChain::HDRExtendedSrgbLinear:
9157 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9158 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9159 case QRhiSwapChain::HDR10:
9160 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9161 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9162 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9163 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9164 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9177 qWarning(
"Attempted to call isFormatSupported() without a window set");
9182 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9185 uint32_t formatCount = 0;
9186 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9187 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9189 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9190 for (uint32_t i = 0; i < formatCount; ++i) {
9191 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9203 QRHI_RES_RHI(QRhiVulkan);
9205 if (m_window && rhiD->adapterLuidValid)
9206 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9220 if (!rhiD->createDefaultRenderPass(rp,
9221 m_depthStencil !=
nullptr,
9232 rhiD->registerResource(rp);
9239 case VK_FORMAT_R8_SRGB:
9240 case VK_FORMAT_R8G8_SRGB:
9241 case VK_FORMAT_R8G8B8_SRGB:
9242 case VK_FORMAT_B8G8R8_SRGB:
9243 case VK_FORMAT_R8G8B8A8_SRGB:
9244 case VK_FORMAT_B8G8R8A8_SRGB:
9245 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9260 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9262 qWarning(
"Failed to get surface for window");
9265 if (surface == surf)
9271 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9272 qWarning(
"Presenting not supported on this window");
9276 quint32 formatCount = 0;
9277 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9278 QList<VkSurfaceFormatKHR> formats(formatCount);
9279 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9283 colorFormat = formats.constFirst().format;
9284 colorSpace = formats.constFirst().colorSpace;
9287 const bool srgbRequested = m_flags.testFlag(sRGB);
9288 bool foundBestFormat =
false;
9289 if (m_format == SDR) {
9290 for (
int i = 0; i <
int(formatCount); ++i) {
9292 if (srgbRequested) {
9293 ok = defaultSrgbColorFormat == formats[i].format;
9295 ok = defaultColorFormat == formats[i].format;
9298 foundBestFormat =
true;
9299 colorFormat = formats[i].format;
9300 colorSpace = formats[i].colorSpace;
9307 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9308 for (
int i = 0; i <
int(formatCount); ++i) {
9310 if (m_format != SDR) {
9311 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9312 }
else if (srgbRequested) {
9313 ok = isSrgbFormat(formats[i].format);
9316 colorFormat = formats[i].format;
9317 colorSpace = formats[i].colorSpace;
9324 if (m_format != SDR) {
9325 VkSurfaceFormatKHR format{};
9326 format.format = colorFormat;
9327 format.colorSpace = colorSpace;
9328 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9329 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9333 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9334 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9339#if QT_CONFIG(wayland)
9344 const bool hasPassThrough =
9345 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9346 return fmt.format == colorFormat
9347 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9349 if (hasPassThrough) {
9350 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9354 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9356 quint32 presModeCount = 0;
9357 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9358 supportedPresentationModes.resize(presModeCount);
9359 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9360 supportedPresentationModes.data());
9368 const bool needsRegistration = !window || window != m_window;
9375 if (window && window != m_window)
9379 m_currentPixelSize = surfacePixelSize();
9380 pixelSize = m_currentPixelSize;
9383 qWarning(
"Failed to create new swapchain");
9387 if (needsRegistration || !rhiD->swapchains.contains(
this))
9388 rhiD->swapchains.insert(
this);
9390 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9391 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9392 m_depthStencil->sampleCount(), m_sampleCount);
9394 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9395 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9396 m_depthStencil->setPixelSize(pixelSize);
9397 if (!m_depthStencil->create())
9398 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9399 pixelSize.width(), pixelSize.height());
9401 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9402 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9403 pixelSize.width(), pixelSize.height());
9407 if (!m_renderPassDesc)
9408 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9410 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9411 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9412 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9414 rtWrapper.d.pixelSize = pixelSize;
9415 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9416 rtWrapper.d.sampleCount = samples;
9417 rtWrapper.d.colorAttCount = 1;
9418 if (m_depthStencil) {
9419 rtWrapper.d.dsAttCount = 1;
9420 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9422 rtWrapper.d.dsAttCount = 0;
9425 rtWrapper.d.dsResolveAttCount = 0;
9426 if (samples > VK_SAMPLE_COUNT_1_BIT)
9427 rtWrapper.d.resolveAttCount = 1;
9429 rtWrapper.d.resolveAttCount = 0;
9431 if (shadingRateMapView)
9432 rtWrapper.d.shadingRateAttCount = 1;
9434 rtWrapper.d.shadingRateAttCount = 0;
9439 QVarLengthArray<VkImageView, 4> views;
9440 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9442 views.append(
ds->imageView);
9443 if (samples > VK_SAMPLE_COUNT_1_BIT)
9444 views.append(image.imageView);
9445 if (shadingRateMapView)
9446 views.append(shadingRateMapView);
9448 VkFramebufferCreateInfo fbInfo = {};
9449 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9450 fbInfo.renderPass = rtWrapper.d.rp->rp;
9451 fbInfo.attachmentCount = uint32_t(views.count());
9452 fbInfo.pAttachments = views.constData();
9453 fbInfo.width = uint32_t(pixelSize.width());
9454 fbInfo.height = uint32_t(pixelSize.height());
9457 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9458 if (err != VK_SUCCESS) {
9459 qWarning(
"Failed to create framebuffer: %d", err);
9465 rtWrapperRight.setRenderPassDescriptor(
9467 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9468 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9470 rtWrapperRight.d.pixelSize = pixelSize;
9471 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9472 rtWrapperRight.d.sampleCount = samples;
9473 rtWrapperRight.d.colorAttCount = 1;
9474 if (m_depthStencil) {
9475 rtWrapperRight.d.dsAttCount = 1;
9476 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9478 rtWrapperRight.d.dsAttCount = 0;
9481 rtWrapperRight.d.dsResolveAttCount = 0;
9482 if (samples > VK_SAMPLE_COUNT_1_BIT)
9483 rtWrapperRight.d.resolveAttCount = 1;
9485 rtWrapperRight.d.resolveAttCount = 0;
9490 QVarLengthArray<VkImageView, 4> views;
9491 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9493 views.append(
ds->imageView);
9494 if (samples > VK_SAMPLE_COUNT_1_BIT)
9495 views.append(image.imageView);
9496 if (shadingRateMapView)
9497 views.append(shadingRateMapView);
9499 VkFramebufferCreateInfo fbInfo = {};
9500 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9501 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9502 fbInfo.attachmentCount = uint32_t(views.count());
9503 fbInfo.pAttachments = views.constData();
9504 fbInfo.width = uint32_t(pixelSize.width());
9505 fbInfo.height = uint32_t(pixelSize.height());
9508 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9509 if (err != VK_SUCCESS) {
9510 qWarning(
"Failed to create framebuffer: %d", err);
9518 if (needsRegistration)
9519 rhiD->registerResource(
this);
const char * constData() const
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker)
VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD=nullptr)
QRhiSwapChain * createSwapChain() override
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
int resourceLimit(QRhi::ResourceLimit limit) const override
bool isDeviceLost() const override
void prepareUploadSubres(QVkTexture *texD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, size_t *curOfs, void *mp, BufferImageCopyList *copyInfos)
void executeDeferredReleases(bool forced=false)
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex)
QRhi::FrameOpResult finish() override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples, VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count)
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void releaseCachedResources() override
QVkSwapChain * currentSwapChain
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams=nullptr)
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
QList< int > supportedSampleCounts() const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb)
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot, VkAccessFlags access, VkPipelineStageFlags stage)
QRhi::FrameOpResult waitCommandCompletion(int frameSlot)
void endExternal(QRhiCommandBuffer *cb) override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex)
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
void drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride) override
VkResult createDescriptorPool(VkDescriptorPool *pool)
void prepareNewFrame(QRhiCommandBuffer *cb)
void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, int startLayer, int layerCount, int startLevel, int levelCount)
QList< QSize > supportedShadingRates(int sampleCount) const override
void printExtraErrorInfo(VkResult err)
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb)
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, QVkTexture *texD, QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage)
bool releaseCachedResourcesCalledBeforeFrameStart
QRhiGraphicsPipeline * createGraphicsPipeline() override
QRhiComputePipeline * createComputePipeline() override
void setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot=-1)
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
const QRhiNativeHandles * nativeHandles(QRhiCommandBuffer *cb) override
bool recreateSwapChain(QRhiSwapChain *swapChain)
void printDeviceLossErrorInfo() const
bool ensurePipelineCache(const void *initialData=nullptr, size_t initialDataSize=0)
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD)
void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD, VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
VkShaderModule createShader(const QByteArray &spirv)
void enqueueTransitionPassResources(QVkCommandBuffer *cbD)
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
bool create(QRhi::Flags flags) override
QVulkanDeviceFunctions * df
void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot=-1)
bool isFeatureSupported(QRhi::Feature feature) const override
void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
bool isYUpInFramebuffer() const override
void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override
void debugMarkEnd(QRhiCommandBuffer *cb) override
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
void releaseSwapChainResources(QRhiSwapChain *swapChain)
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, int depthLayer, QRhiShadingRateMap *shadingRateMap)
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, QVkBuffer *bufD, int slot, QRhiPassResourceTracker::BufferAccess access, QRhiPassResourceTracker::BufferStage stage)
VkFormat optimalDepthStencilFormat()
QRhiStats statistics() override
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
void drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride) override
void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD)
void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
void setDefaultScissor(QVkCommandBuffer *cbD)
bool isYUpInNDC() const override
const QRhiNativeHandles * nativeHandles() override
QRhiShadingRateMap * createShadingRateMap() override
void setPipelineCacheData(const QByteArray &data) override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
QRhiShaderResourceBindings * createShaderResourceBindings() override
void finishActiveReadbacks(bool forced=false)
void ensureCommandPoolForNewFrame()
QByteArray pipelineCacheData() override
void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD)
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
bool isClipDepthZeroToOne() const override
void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
QMatrix4x4 clipSpaceCorrMatrix() const override
int ubufAlignment() const override
QRhiDriverInfo driverInfo() const override
void beginExternal(QRhiCommandBuffer *cb) override
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat, QRhiShadingRateMap *shadingRateMap)
QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence, VkSemaphore *waitSem, VkSemaphore *signalSem)
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount)
bool makeThreadLocalNativeContextCurrent() override
QRhiDriverInfo info() const override
Combined button and popup list for selecting options.
static VkPolygonMode toVkPolygonMode(QRhiGraphicsPipeline::PolygonMode mode)
static VkCullModeFlags toVkCullMode(QRhiGraphicsPipeline::CullMode c)
static bool accessIsWrite(VkAccessFlags access)
static VkCompareOp toVkTextureCompareOp(QRhiSampler::CompareOp op)
static QVulkanInstance * globalVulkanInstance
static VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
static QRhiTexture::Format swapchainReadbackTextureFormat(VkFormat format, QRhiTexture::Flags *flags)
static VkStencilOp toVkStencilOp(QRhiGraphicsPipeline::StencilOp op)
static bool qvk_debug_filter(QVulkanInstance::DebugMessageSeverityFlags severity, QVulkanInstance::DebugMessageTypeFlags type, const void *callbackData)
static QVkBuffer::UsageState toVkBufferUsageState(QRhiPassResourceTracker::UsageState usage)
static bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b)
static bool isSrgbFormat(VkFormat format)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::TextureStage stage)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::BufferAccess access)
static VkImageLayout toVkLayout(QRhiPassResourceTracker::TextureAccess access)
static VkFormat toVkAttributeFormat(QRhiVertexInputAttribute::Format format)
static QVkTexture::UsageState toVkTextureUsageState(QRhiPassResourceTracker::UsageState usage)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::BufferStage stage)
static QRhiDriverInfo::DeviceType toRhiDeviceType(VkPhysicalDeviceType type)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkBuffer::UsageState &bufUsage)
static VkColorComponentFlags toVkColorComponents(QRhiGraphicsPipeline::ColorMask c)
static VkFilter toVkFilter(QRhiSampler::Filter f)
static VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t)
static void qrhivk_releaseTexture(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df, void *allocator)
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::TextureAccess access)
static VmaAllocator toVmaAllocator(QVkAllocator a)
static VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
static constexpr bool isDepthTextureFormat(QRhiTexture::Format format)
static void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphicsPipeline::StencilOpState &src)
VkSampleCountFlagBits mask
static VkShaderStageFlags toVkShaderStageFlags(QRhiShaderResourceBinding::StageFlags stage)
static constexpr VkImageAspectFlags aspectMaskForTextureFormat(QRhiTexture::Format format)
static VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
static VkBlendFactor toVkBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
static void fillDriverInfo(QRhiDriverInfo *info, const VkPhysicalDeviceProperties &physDevProperties)
static VkBlendOp toVkBlendOp(QRhiGraphicsPipeline::BlendOp op)
static void qrhivk_releaseRenderBuffer(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static VkFrontFace toVkFrontFace(QRhiGraphicsPipeline::FrontFace f)
void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource, QRhiShaderResourceBinding::Type bindingType, int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
static VkFormat toVkTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
static VkCompareOp toVkCompareOp(QRhiGraphicsPipeline::CompareOp op)
static void fillRenderPassCreateInfo(VkRenderPassCreateInfo *rpInfo, VkSubpassDescription *subpassDesc, QVkRenderPassDescriptor *rpD)
static VkSamplerMipmapMode toVkMipmapMode(QRhiSampler::Filter f)
static bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, const VkSurfaceFormatKHR &s)
static void qrhivk_releaseSampler(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static constexpr bool isStencilTextureFormat(QRhiTexture::Format format)
static QVkRenderTargetData * maybeRenderTargetData(QVkCommandBuffer *cbD)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkTexture::UsageState &texUsage)
static VmaAllocation toVmaAllocation(QVkAlloc a)
static void addToChain(T *head, void *entry)
static VkShaderStageFlagBits toVkShaderStage(QRhiShaderStage::Type type)
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS
static const int QVK_DESC_SETS_PER_POOL
static const int QVK_FRAMES_IN_FLIGHT
bool prepare(VkRenderPassCreateInfo *rpInfo, int multiViewCount, bool multiViewCap)
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
QRhiBuffer::NativeBuffer nativeBuffer() override
bool create() override
Creates the corresponding native graphics resources.
char * beginFullDynamicBufferUpdateForCurrentFrame() override
@ TransitionPassResources
QVkCommandBuffer(QRhiImplementation *rhi)
const QRhiNativeHandles * nativeHandles()
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
int currentPassResTrackerIndex
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkComputePipeline(QRhiImplementation *rhi)
QVkGraphicsPipeline(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags, QRhiTexture::Format backingFormatHint)
QRhiTexture::Format backingFormat() const override
bool create() override
Creates the corresponding native graphics resources.
QVkTexture * backingTexture
const QRhiNativeHandles * nativeHandles() override
void updateSerializedFormat()
bool hasDepthStencilResolve
~QVkRenderPassDescriptor()
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVector< quint32 > serializedFormat() const override
QVkRenderPassDescriptor(QRhiImplementation *rhi)
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QVkRenderPassDescriptor * rp
static const int MAX_COLOR_ATTACHMENTS
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
void updateResources(UpdateFlags flags) override
QVkShaderResourceBindings(QRhiImplementation *rhi)
bool create() override
Creates the corresponding resource binding set.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
~QVkShaderResourceBindings()
bool createFrom(QRhiTexture *src) override
Sets up the shading rate map to use the texture src as the image containing the per-tile shading rate...
QVkShadingRateMap(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QSize pixelSize() const override
int sampleCount() const override
float devicePixelRatio() const override
~QVkSwapChainRenderTarget()
QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
@ ScImageUseTransferSource
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QRhiRenderTarget * currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override
bool isFormatSupported(Format f) override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
QVkSwapChain(QRhiImplementation *rhi)
QSize surfacePixelSize() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderTarget * currentFrameRenderTarget() override
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::limitsType
QRhiCommandBuffer * currentFrameCommandBuffer() override
QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
~QVkTextureRenderTarget()
float devicePixelRatio() const override
bool create() override
Creates the corresponding native graphics resources.
int sampleCount() const override
QSize pixelSize() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
VkImageView perLevelImageViewForLoadStore(int level)
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
void setNativeLayout(int layout) override
With some graphics APIs, such as Vulkan, integrating custom rendering code that uses the graphics API...
QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
NativeTexture nativeTexture() override
bool prepareCreate(QSize *adjustedSize=nullptr)