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)) {
740 multiviewFeaturesIfApi11 = {};
741 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
742 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
743 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
744 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
745 featuresQueried =
true;
750 if (!featuresQueried) {
753 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
754 featuresQueried =
true;
762 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
763 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
764 queryQueueFamilyProps();
765 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
766 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
767 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
768 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
769 if (!gfxQueueFamilyIdxOpt.has_value()
770 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
771 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
773 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
774 gfxQueueFamilyIdxOpt = i;
775 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
776 computelessGfxQueueCandidateIdxOpt = i;
779 if (gfxQueueFamilyIdxOpt.has_value()) {
780 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
782 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
783 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
785 qWarning(
"No graphics (or no graphics+present) queue family found");
790 VkDeviceQueueCreateInfo queueInfo = {};
791 const float prio[] = { 0 };
792 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
793 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
794 queueInfo.queueCount = 1;
795 queueInfo.pQueuePriorities = prio;
797 QList<
const char *> devLayers;
798 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
799 devLayers.append(
"VK_LAYER_KHRONOS_validation");
801 QList<
const char *> requestedDevExts;
802 requestedDevExts.append(
"VK_KHR_swapchain");
804 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
806 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
807 if (hasPhysDevProp2) {
808 requestedDevExts.append(
"VK_KHR_portability_subset");
810 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
811 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
816#ifdef VK_EXT_vertex_attribute_divisor
817 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
818 if (hasPhysDevProp2) {
819 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
820 caps.vertexAttribDivisor =
true;
825#ifdef VK_KHR_create_renderpass2
826 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
827 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
828 caps.renderPass2KHR =
true;
832#ifdef VK_KHR_depth_stencil_resolve
833 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
834 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
835 caps.depthStencilResolveKHR =
true;
839#ifdef VK_KHR_fragment_shading_rate
840 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
841 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
844#ifdef VK_EXT_device_fault
845 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
846 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
847 caps.deviceFault =
true;
851 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
852 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
853 if (devExts.contains(ext)) {
854 requestedDevExts.append(ext.constData());
856 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
862 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
863 for (
const QByteArray &ext : envExtList) {
864 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
865 if (devExts.contains(ext)) {
866 requestedDevExts.append(ext.constData());
868 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
874 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
875 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
876 for (
const char *ext : std::as_const(requestedDevExts))
877 qCDebug(QRHI_LOG_INFO,
" %s", ext);
880 VkDeviceCreateInfo devInfo = {};
881 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
882 devInfo.queueCreateInfoCount = 1;
883 devInfo.pQueueCreateInfos = &queueInfo;
884 devInfo.enabledLayerCount = uint32_t(devLayers.size());
885 devInfo.ppEnabledLayerNames = devLayers.constData();
886 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
887 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
903 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
906 physDevFeatures13.robustImageAccess = VK_FALSE;
910 if (caps.apiVersion >= QVersionNumber(1, 1)) {
917 devInfo.pNext = &physDevFeaturesChainable;
921 physDevFeatures.robustBufferAccess = VK_FALSE;
922 devInfo.pEnabledFeatures = &physDevFeatures;
925 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
926 if (err != VK_SUCCESS) {
927 qWarning(
"Failed to create device: %d", err);
931 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
936 caps.deviceFault =
true;
937 caps.vertexAttribDivisor =
true;
938 caps.renderPass2KHR =
true;
939 caps.depthStencilResolveKHR =
true;
942 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
943 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
944 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
945 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
946 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
947 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
949 df = inst->deviceFunctions(dev);
951 VkCommandPoolCreateInfo poolInfo = {};
952 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
953 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
955 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
956 if (err != VK_SUCCESS) {
957 qWarning(
"Failed to create command pool: %d", err);
962 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
963 gfxQueueFamilyIdx, gfxQueueIdx);
965 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
967 if (queueFamilyProps.isEmpty())
968 queryQueueFamilyProps();
970 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
971 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
973 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
976 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
978 caps.depthClamp = physDevFeatures.depthClamp;
980 caps.wideLines = physDevFeatures.wideLines;
982 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
984 caps.tessellation = physDevFeatures.tessellationShader;
985 caps.geometryShader = physDevFeatures.geometryShader;
987 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
989 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
992 if (caps.apiVersion >= QVersionNumber(1, 2))
993 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
997 if (caps.apiVersion == QVersionNumber(1, 1))
998 caps.multiView = multiviewFeaturesIfApi11.multiview;
1001#ifdef VK_KHR_fragment_shading_rate
1002 fragmentShadingRates.clear();
1003 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1004 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1005 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1006 if (caps.imageBasedShadingRate) {
1007 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1008 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1009 VkPhysicalDeviceProperties2 props2 = {};
1010 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1011 props2.pNext = &shadingRateProps;
1012 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1013 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1016 if (caps.perDrawShadingRate) {
1017 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1018 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1019 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1020 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1022 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1023 fragmentShadingRates.resize(count);
1024 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1026 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1028 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1030 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1031 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1040#ifdef VK_KHR_create_renderpass2
1041 if (caps.renderPass2KHR) {
1042 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1043 if (!vkCreateRenderPass2KHR)
1044 caps.renderPass2KHR =
false;
1050 adapterLuidValid =
false;
1052#ifdef VK_VERSION_1_2
1053 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1054 VkPhysicalDeviceVulkan11Properties v11props = {};
1055 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1056 VkPhysicalDeviceProperties2 props2 = {};
1057 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1058 props2.pNext = &v11props;
1059 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1060 if (v11props.deviceLUIDValid) {
1061 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1062 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1063 adapterLuidValid =
true;
1064 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1065 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1066 adapterLuid.LowPart, adapterLuid.HighPart);
1073 VmaVulkanFunctions funcs = {};
1074 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1075 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1077 VmaAllocatorCreateInfo allocatorInfo = {};
1080 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1081 allocatorInfo.physicalDevice = physDev;
1082 allocatorInfo.device = dev;
1083 allocatorInfo.pVulkanFunctions = &funcs;
1084 allocatorInfo.instance = inst->vkInstance();
1092#ifdef VK_VERSION_1_4
1093 if (caps.apiVersion >= QVersionNumber(1, 4))
1094 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1097#ifdef VK_VERSION_1_3
1098 if (caps.apiVersion >= QVersionNumber(1, 3))
1099 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1102#ifdef VK_VERSION_1_2
1103 if (caps.apiVersion >= QVersionNumber(1, 2))
1104 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1107#ifdef VK_VERSION_1_1
1108 if (caps.apiVersion >= QVersionNumber(1, 1))
1109 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1112#ifdef VK_VERSION_1_0
1113 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1116 VmaAllocator vmaallocator;
1117 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1118 if (err != VK_SUCCESS) {
1119 qWarning(
"Failed to create allocator: %d", err);
1125 inst->installDebugOutputFilter(qvk_debug_filter);
1127 VkDescriptorPool pool;
1128 VkResult err = createDescriptorPool(&pool);
1129 if (err == VK_SUCCESS)
1130 descriptorPools.append(pool);
1132 qWarning(
"Failed to create initial descriptor pool: %d", err);
1134 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1135 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1136 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1138 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1139 if (err != VK_SUCCESS) {
1140 qWarning(
"Failed to create timestamp query pool: %d", err);
1143 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1144 timestampQueryPoolMap.fill(
false);
1146#ifdef VK_EXT_debug_utils
1147 if (caps.debugUtils) {
1148 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1149 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1150 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1151 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1155#ifdef VK_EXT_device_fault
1156 if (caps.deviceFault) {
1157 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1163 nativeHandlesStruct.physDev = physDev;
1164 nativeHandlesStruct.dev = dev;
1165 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1166 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1167 nativeHandlesStruct.gfxQueue = gfxQueue;
1168 nativeHandlesStruct.vmemAllocator = allocator;
1169 nativeHandlesStruct.inst = inst;
1180 df->vkDeviceWaitIdle(dev);
1187 dxgiHdrInfo =
nullptr;
1191 df->vkDestroyFence(dev, ofr.cmdFence,
nullptr);
1192 ofr.cmdFence = VK_NULL_HANDLE;
1195 if (pipelineCache) {
1196 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1197 pipelineCache = VK_NULL_HANDLE;
1200 for (
const DescriptorPoolData &pool : descriptorPools)
1201 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1203 descriptorPools.clear();
1205 if (timestampQueryPool) {
1206 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1207 timestampQueryPool = VK_NULL_HANDLE;
1211 vmaDestroyAllocator(toVmaAllocator(allocator));
1217 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1218 cmdPool[i] = VK_NULL_HANDLE;
1220 freeSecondaryCbs[i].clear();
1221 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1224 if (!importedDevice && dev) {
1225 df->vkDestroyDevice(dev,
nullptr);
1226 inst->resetDeviceFunctions(dev);
1227 dev = VK_NULL_HANDLE;
1237QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1239 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1240 if (nativeHandles) {
1241 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1242 requestedPhysDev = h->physDev;
1245 QRhi::AdapterList list;
1246 QVulkanFunctions *f = inst->functions();
1247 uint32_t physDevCount = 0;
1248 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1252 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1253 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1254 if (err != VK_SUCCESS || !physDevCount)
1257 VkPhysicalDeviceProperties physDevProperties = {};
1258 for (uint32_t i = 0; i < physDevCount; ++i) {
1259 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1262 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1263 QVulkanAdapter *a =
new QVulkanAdapter;
1264 a->physDev = physDevs[i];
1265 fillDriverInfo(&a->adapterInfo, physDevProperties);
1279 VkDescriptorPoolSize descPoolSizes[] = {
1280 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1281 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1282 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1283 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1284 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1285 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1286 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1288 VkDescriptorPoolCreateInfo descPoolInfo = {};
1289 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1293 descPoolInfo.flags = 0;
1295 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1296 descPoolInfo.pPoolSizes = descPoolSizes;
1297 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1302 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1303 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1304 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1305 if (r == VK_SUCCESS)
1306 descriptorPools[poolIndex].refCount += 1;
1310 int lastPoolIdx = descriptorPools.size() - 1;
1311 for (
int i = lastPoolIdx; i >= 0; --i) {
1312 if (descriptorPools[i].refCount == 0) {
1313 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1314 descriptorPools[i].allocedDescSets = 0;
1316 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1317 VkResult err = tryAllocate(i);
1318 if (err == VK_SUCCESS) {
1319 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1320 *resultPoolIndex = i;
1326 VkDescriptorPool newPool;
1327 VkResult poolErr = createDescriptorPool(&newPool);
1328 if (poolErr == VK_SUCCESS) {
1329 descriptorPools.append(newPool);
1330 lastPoolIdx = descriptorPools.size() - 1;
1331 VkResult err = tryAllocate(lastPoolIdx);
1332 if (err != VK_SUCCESS) {
1333 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1336 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1337 *resultPoolIndex = lastPoolIdx;
1340 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1347 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1349 case QRhiTexture::RGBA8:
1350 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1351 case QRhiTexture::BGRA8:
1352 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1353 case QRhiTexture::R8:
1354 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1355 case QRhiTexture::RG8:
1356 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1357 case QRhiTexture::R16:
1358 return VK_FORMAT_R16_UNORM;
1359 case QRhiTexture::RG16:
1360 return VK_FORMAT_R16G16_UNORM;
1361 case QRhiTexture::RED_OR_ALPHA8:
1362 return VK_FORMAT_R8_UNORM;
1364 case QRhiTexture::RGBA16F:
1365 return VK_FORMAT_R16G16B16A16_SFLOAT;
1366 case QRhiTexture::RGBA32F:
1367 return VK_FORMAT_R32G32B32A32_SFLOAT;
1368 case QRhiTexture::R16F:
1369 return VK_FORMAT_R16_SFLOAT;
1370 case QRhiTexture::R32F:
1371 return VK_FORMAT_R32_SFLOAT;
1373 case QRhiTexture::RGB10A2:
1375 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1377 case QRhiTexture::R8SI:
1378 return VK_FORMAT_R8_SINT;
1379 case QRhiTexture::R32SI:
1380 return VK_FORMAT_R32_SINT;
1381 case QRhiTexture::RG32SI:
1382 return VK_FORMAT_R32G32_SINT;
1383 case QRhiTexture::RGBA32SI:
1384 return VK_FORMAT_R32G32B32A32_SINT;
1386 case QRhiTexture::R8UI:
1387 return VK_FORMAT_R8_UINT;
1388 case QRhiTexture::R32UI:
1389 return VK_FORMAT_R32_UINT;
1390 case QRhiTexture::RG32UI:
1391 return VK_FORMAT_R32G32_UINT;
1392 case QRhiTexture::RGBA32UI:
1393 return VK_FORMAT_R32G32B32A32_UINT;
1395 case QRhiTexture::D16:
1396 return VK_FORMAT_D16_UNORM;
1397 case QRhiTexture::D24:
1398 return VK_FORMAT_X8_D24_UNORM_PACK32;
1399 case QRhiTexture::D24S8:
1400 return VK_FORMAT_D24_UNORM_S8_UINT;
1401 case QRhiTexture::D32F:
1402 return VK_FORMAT_D32_SFLOAT;
1403 case QRhiTexture::D32FS8:
1404 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1406 case QRhiTexture::BC1:
1407 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1408 case QRhiTexture::BC2:
1409 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1410 case QRhiTexture::BC3:
1411 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1412 case QRhiTexture::BC4:
1413 return VK_FORMAT_BC4_UNORM_BLOCK;
1414 case QRhiTexture::BC5:
1415 return VK_FORMAT_BC5_UNORM_BLOCK;
1416 case QRhiTexture::BC6H:
1417 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1418 case QRhiTexture::BC7:
1419 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1421 case QRhiTexture::ETC2_RGB8:
1422 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1423 case QRhiTexture::ETC2_RGB8A1:
1424 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1425 case QRhiTexture::ETC2_RGBA8:
1426 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1428 case QRhiTexture::ASTC_4x4:
1429 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1430 case QRhiTexture::ASTC_5x4:
1431 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1432 case QRhiTexture::ASTC_5x5:
1433 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1434 case QRhiTexture::ASTC_6x5:
1435 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1436 case QRhiTexture::ASTC_6x6:
1437 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1438 case QRhiTexture::ASTC_8x5:
1439 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1440 case QRhiTexture::ASTC_8x6:
1441 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1442 case QRhiTexture::ASTC_8x8:
1443 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1444 case QRhiTexture::ASTC_10x5:
1445 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1446 case QRhiTexture::ASTC_10x6:
1447 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1448 case QRhiTexture::ASTC_10x8:
1449 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1450 case QRhiTexture::ASTC_10x10:
1451 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1452 case QRhiTexture::ASTC_12x10:
1453 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1454 case QRhiTexture::ASTC_12x12:
1455 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1458 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1465 case VK_FORMAT_R8G8B8A8_UNORM:
1466 return QRhiTexture::RGBA8;
1467 case VK_FORMAT_R8G8B8A8_SRGB:
1469 (*flags) |= QRhiTexture::sRGB;
1470 return QRhiTexture::RGBA8;
1471 case VK_FORMAT_B8G8R8A8_UNORM:
1472 return QRhiTexture::BGRA8;
1473 case VK_FORMAT_B8G8R8A8_SRGB:
1475 (*flags) |= QRhiTexture::sRGB;
1476 return QRhiTexture::BGRA8;
1477 case VK_FORMAT_R16G16B16A16_SFLOAT:
1478 return QRhiTexture::RGBA16F;
1479 case VK_FORMAT_R32G32B32A32_SFLOAT:
1480 return QRhiTexture::RGBA32F;
1481 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1482 return QRhiTexture::RGB10A2;
1484 qWarning(
"VkFormat %d cannot be read back", format);
1487 return QRhiTexture::UnknownFormat;
1493 case QRhiTexture::Format::D16:
1494 case QRhiTexture::Format::D24:
1495 case QRhiTexture::Format::D24S8:
1496 case QRhiTexture::Format::D32F:
1497 case QRhiTexture::Format::D32FS8:
1508 case QRhiTexture::Format::D24S8:
1509 case QRhiTexture::Format::D32FS8:
1519 if (isDepthTextureFormat(format)) {
1520 if (isStencilTextureFormat(format))
1521 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1523 return VK_IMAGE_ASPECT_DEPTH_BIT;
1525 return VK_IMAGE_ASPECT_COLOR_BIT;
1536 VkPhysicalDeviceMemoryProperties physDevMemProps;
1537 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1539 VkMemoryRequirements memReq;
1540 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1541 uint32_t memTypeIndex = uint32_t(-1);
1543 if (memReq.memoryTypeBits) {
1545 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1546 bool foundDevLocal =
false;
1547 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1548 if (memReq.memoryTypeBits & (1 << i)) {
1549 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1550 if (!foundDevLocal) {
1551 foundDevLocal =
true;
1554 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1563 return memTypeIndex;
1567 const QSize &pixelSize,
1568 VkImageUsageFlags usage,
1569 VkImageAspectFlags aspectMask,
1570 VkSampleCountFlagBits samples,
1571 VkDeviceMemory *mem,
1576 VkMemoryRequirements memReq;
1579 for (
int i = 0; i < count; ++i) {
1580 VkImageCreateInfo imgInfo = {};
1581 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1582 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1583 imgInfo.format = format;
1584 imgInfo.extent.width = uint32_t(pixelSize.width());
1585 imgInfo.extent.height = uint32_t(pixelSize.height());
1586 imgInfo.extent.depth = 1;
1587 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1588 imgInfo.samples = samples;
1589 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1590 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1591 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1593 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1594 if (err != VK_SUCCESS) {
1595 qWarning(
"Failed to create image: %d", err);
1602 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1605 VkMemoryAllocateInfo memInfo = {};
1606 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1607 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1609 uint32_t startIndex = 0;
1611 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1612 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1613 qWarning(
"No suitable memory type found");
1616 startIndex = memInfo.memoryTypeIndex + 1;
1617 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1618 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1619 qWarning(
"Failed to allocate image memory: %d", err);
1622 }
while (err != VK_SUCCESS);
1624 VkDeviceSize ofs = 0;
1625 for (
int i = 0; i < count; ++i) {
1626 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1627 if (err != VK_SUCCESS) {
1628 qWarning(
"Failed to bind image memory: %d", err);
1631 ofs += aligned(memReq.size, memReq.alignment);
1633 VkImageViewCreateInfo imgViewInfo = {};
1634 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1635 imgViewInfo.image = images[i];
1636 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1637 imgViewInfo.format = format;
1638 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1639 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1640 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1641 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1642 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1643 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1645 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1646 if (err != VK_SUCCESS) {
1647 qWarning(
"Failed to create image view: %d", err);
1657 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1658 return optimalDsFormat;
1660 const VkFormat dsFormatCandidates[] = {
1661 VK_FORMAT_D24_UNORM_S8_UINT,
1662 VK_FORMAT_D32_SFLOAT_S8_UINT,
1663 VK_FORMAT_D16_UNORM_S8_UINT
1665 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1666 int dsFormatIdx = 0;
1667 while (dsFormatIdx < dsFormatCandidateCount) {
1668 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1669 VkFormatProperties fmtProp;
1670 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1671 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1675 if (dsFormatIdx == dsFormatCandidateCount)
1676 qWarning(
"Failed to find an optimal depth-stencil format");
1678 return optimalDsFormat;
1683 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1685 if (multiViewCount < 2)
1687 if (!multiViewCap) {
1688 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1691#ifdef VK_VERSION_1_1
1692 uint32_t allViewsMask = 0;
1693 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1694 allViewsMask |= (1 << i);
1695 multiViewMask = allViewsMask;
1696 multiViewCorrelationMask = allViewsMask;
1697 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1698 multiViewInfo.subpassCount = 1;
1699 multiViewInfo.pViewMasks = &multiViewMask;
1700 multiViewInfo.correlationMaskCount = 1;
1701 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1702 rpInfo->pNext = &multiViewInfo;
1707#ifdef VK_VERSION_1_1
1714#ifdef VK_KHR_create_renderpass2
1718struct RenderPass2SetupHelper
1720 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1722 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1726 if (multiViewCount >= 2) {
1727 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1728 viewMask |= (1 << i);
1731 attDescs2.resize(rpInfo->attachmentCount);
1732 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1733 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1734 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1736 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1737 att2.flags = att.flags;
1738 att2.format = att.format;
1739 att2.samples = att.samples;
1740 att2.loadOp = att.loadOp;
1741 att2.storeOp = att.storeOp;
1742 att2.stencilLoadOp = att.stencilLoadOp;
1743 att2.stencilStoreOp = att.stencilStoreOp;
1744 att2.initialLayout = att.initialLayout;
1745 att2.finalLayout = att.finalLayout;
1750 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1751 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1752 subpass2.flags = subpassDesc.flags;
1753 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1754 if (multiViewCount >= 2)
1755 subpass2.viewMask = viewMask;
1758 qsizetype startIndex = attRefs2.count();
1759 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1760 attRefs2.append({});
1761 VkAttachmentReference2KHR &attref2(attRefs2.last());
1762 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1763 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1764 attref2.attachment = attref.attachment;
1765 attref2.layout = attref.layout;
1766 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1768 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1769 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1772 if (subpassDesc.pResolveAttachments) {
1773 startIndex = attRefs2.count();
1774 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1775 attRefs2.append({});
1776 VkAttachmentReference2KHR &attref2(attRefs2.last());
1777 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1778 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1779 attref2.attachment = attref.attachment;
1780 attref2.layout = attref.layout;
1781 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1783 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1787 if (subpassDesc.pDepthStencilAttachment) {
1788 startIndex = attRefs2.count();
1789 attRefs2.append({});
1790 VkAttachmentReference2KHR &attref2(attRefs2.last());
1791 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1792 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1793 attref2.attachment = attref.attachment;
1794 attref2.layout = attref.layout;
1795 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1796 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1800#ifdef VK_KHR_depth_stencil_resolve
1802 if (rpD->hasDepthStencilResolve) {
1803 startIndex = attRefs2.count();
1804 attRefs2.append({});
1805 VkAttachmentReference2KHR &attref2(attRefs2.last());
1806 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1807 attref2.attachment = rpD->dsResolveRef.attachment;
1808 attref2.layout = rpD->dsResolveRef.layout;
1809 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1810 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1811 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1812 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1813 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1814 addToChain(&subpass2, &dsResolveDesc);
1818#ifdef VK_KHR_fragment_shading_rate
1819 shadingRateAttInfo = {};
1820 if (rpD->hasShadingRateMap) {
1821 startIndex = attRefs2.count();
1822 attRefs2.append({});
1823 VkAttachmentReference2KHR &attref2(attRefs2.last());
1824 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1825 attref2.attachment = rpD->shadingRateRef.attachment;
1826 attref2.layout = rpD->shadingRateRef.layout;
1827 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1828 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1829 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1830 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1831 addToChain(&subpass2, &shadingRateAttInfo);
1837 subpassDeps2.clear();
1838 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1839 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1840 subpassDeps2.append({});
1841 VkSubpassDependency2 &dep2(subpassDeps2.last());
1842 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1843 dep2.srcSubpass = dep.srcSubpass;
1844 dep2.dstSubpass = dep.dstSubpass;
1845 dep2.srcStageMask = dep.srcStageMask;
1846 dep2.dstStageMask = dep.dstStageMask;
1847 dep2.srcAccessMask = dep.srcAccessMask;
1848 dep2.dstAccessMask = dep.dstAccessMask;
1849 dep2.dependencyFlags = dep.dependencyFlags;
1852 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1853 rpInfo2->pNext =
nullptr;
1854 rpInfo2->flags = rpInfo->flags;
1855 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1856 rpInfo2->pAttachments = attDescs2.constData();
1857 rpInfo2->subpassCount = 1;
1858 rpInfo2->pSubpasses = &subpass2;
1859 rpInfo2->dependencyCount = subpassDeps2.count();
1860 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1861 if (multiViewCount >= 2) {
1862 rpInfo2->correlatedViewMaskCount = 1;
1863 rpInfo2->pCorrelatedViewMasks = &viewMask;
1869 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1870 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1871 VkSubpassDescription2KHR subpass2;
1872 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1873#ifdef VK_KHR_depth_stencil_resolve
1874 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1876#ifdef VK_KHR_fragment_shading_rate
1877 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1884 VkSubpassDescription *subpassDesc,
1887 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1888 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1889 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1890 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1891 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1892 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1894 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1895 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1896 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1897 rpInfo->pAttachments = rpD->attDescs.constData();
1898 rpInfo->subpassCount = 1;
1899 rpInfo->pSubpasses = subpassDesc;
1900 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1901 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1905 bool hasDepthStencil,
1906 VkSampleCountFlagBits samples,
1907 VkFormat colorFormat,
1908 QRhiShadingRateMap *shadingRateMap)
1912 VkAttachmentDescription attDesc = {};
1913 attDesc.format = colorFormat;
1914 attDesc.samples = samples;
1915 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1916 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1917 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1918 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1919 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1920 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1921 rpD->attDescs.append(attDesc);
1923 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1928 rpD->multiViewCount = 0;
1930 if (hasDepthStencil) {
1934 attDesc.format = optimalDepthStencilFormat();
1935 attDesc.samples = samples;
1936 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1937 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1938 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1939 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1940 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1941 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1942 rpD->attDescs.append(attDesc);
1944 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1949 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1951 attDesc.format = colorFormat;
1952 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1953 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1954 attDesc.storeOp = 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 = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1959 rpD->attDescs.append(attDesc);
1961 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1964 rpD->dsResolveRef = {};
1966 rpD->shadingRateRef = {};
1967#ifdef VK_KHR_fragment_shading_rate
1968 if (shadingRateMap) {
1970 attDesc.format = VK_FORMAT_R8_UINT;
1971 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1972 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1973 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1974 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1975 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1976 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1977 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1978 rpD->attDescs.append(attDesc);
1980 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
1985 VkSubpassDependency subpassDep = {};
1986 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1987 subpassDep.dstSubpass = 0;
1988 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1989 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1990 subpassDep.srcAccessMask = 0;
1991 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1992 rpD->subpassDeps.append(subpassDep);
1993 if (hasDepthStencil) {
1994 memset(&subpassDep, 0,
sizeof(subpassDep));
1995 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1996 subpassDep.dstSubpass = 0;
1997 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1998 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1999 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2000 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2001 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2002 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2003 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2004 rpD->subpassDeps.append(subpassDep);
2007 VkRenderPassCreateInfo rpInfo;
2008 VkSubpassDescription subpassDesc;
2009 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2011#ifdef VK_KHR_create_renderpass2
2012 if (caps.renderPass2KHR) {
2014 VkRenderPassCreateInfo2KHR rpInfo2;
2015 RenderPass2SetupHelper rp2Helper(
this);
2016 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2018 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2019 if (err != VK_SUCCESS) {
2020 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2027 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2028 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2029 if (err != VK_SUCCESS) {
2030 qWarning(
"Failed to create renderpass: %d", err);
2039 const QRhiColorAttachment *colorAttachmentsBegin,
2040 const QRhiColorAttachment *colorAttachmentsEnd,
2044 QRhiRenderBuffer *depthStencilBuffer,
2045 QRhiTexture *depthTexture,
2046 QRhiTexture *depthResolveTexture,
2047 QRhiShadingRateMap *shadingRateMap)
2051 int multiViewCount = 0;
2052 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2055 Q_ASSERT(texD || rbD);
2056 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2057 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2059 VkAttachmentDescription attDesc = {};
2060 attDesc.format = vkformat;
2061 attDesc.samples = samples;
2062 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2063 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2064 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2065 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2067 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2068 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2069 rpD->attDescs.append(attDesc);
2071 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2072 rpD->colorRefs.append(ref);
2074 if (it->multiViewCount() >= 2) {
2075 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2076 qWarning(
"Inconsistent multiViewCount in color attachment set");
2078 multiViewCount = it->multiViewCount();
2079 }
else if (multiViewCount > 0) {
2080 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2083 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2084 rpD->multiViewCount = uint32_t(multiViewCount);
2088 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2089 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2090 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2091 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2092 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2093 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2094 VkAttachmentDescription attDesc = {};
2095 attDesc.format = dsFormat;
2096 attDesc.samples = samples;
2097 attDesc.loadOp = loadOp;
2098 attDesc.storeOp = storeOp;
2099 attDesc.stencilLoadOp = loadOp;
2100 attDesc.stencilStoreOp = storeOp;
2101 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2102 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2103 rpD->attDescs.append(attDesc);
2104 if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
2105 multiViewCount = depthTexture->arraySize();
2106 rpD->multiViewCount = multiViewCount;
2108 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2113 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2114 if (it->resolveTexture()) {
2116 const VkFormat dstFormat = rtexD->vkformat;
2117 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2118 qWarning(
"Resolving into a multisample texture is not supported");
2122 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2123 if (srcFormat != dstFormat) {
2127 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2128 int(srcFormat),
int(dstFormat));
2131 VkAttachmentDescription attDesc = {};
2132 attDesc.format = rtexD->viewFormat;
2133 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2134 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2135 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2136 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2137 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2138 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2139 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2140 rpD->attDescs.append(attDesc);
2142 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2143 rpD->resolveRefs.append(ref);
2145 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2146 rpD->resolveRefs.append(ref);
2149 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2154 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2155 qWarning(
"Resolving into a multisample depth texture is not supported");
2158 if (texD->vkformat != rtexD->vkformat) {
2159 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2160 int(texD->vkformat),
int(rtexD->vkformat));
2163 VkAttachmentDescription attDesc = {};
2164 attDesc.format = rtexD->viewFormat;
2165 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2166 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2167 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2168 attDesc.stencilLoadOp = attDesc.loadOp;
2169 attDesc.stencilStoreOp = attDesc.storeOp;
2170 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2171 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2172 rpD->attDescs.append(attDesc);
2173 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2175 rpD->dsResolveRef = {};
2179 rpD->shadingRateRef = {};
2180#ifdef VK_KHR_fragment_shading_rate
2181 if (shadingRateMap) {
2182 VkAttachmentDescription attDesc = {};
2183 attDesc.format = VK_FORMAT_R8_UINT;
2184 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2185 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2186 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2187 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2188 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2189 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2190 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2191 rpD->attDescs.append(attDesc);
2192 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2197 VkSubpassDependency selfDependency;
2198 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
2199 selfDependency.srcSubpass = 0;
2200 selfDependency.dstSubpass = 0;
2201 selfDependency.srcStageMask = stageMask;
2202 selfDependency.dstStageMask = stageMask;
2203 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2204 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2205#ifdef VK_VERSION_1_1
2206 selfDependency.dependencyFlags = rpD->multiViewCount >= 2 ? VK_DEPENDENCY_VIEW_LOCAL_BIT : 0;
2208 selfDependency.dependencyFlags = 0;
2210 rpD->subpassDeps.append(selfDependency);
2217 VkRenderPassCreateInfo rpInfo;
2218 VkSubpassDescription subpassDesc;
2219 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2222 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2225#ifdef VK_KHR_create_renderpass2
2226 if (caps.renderPass2KHR) {
2228 VkRenderPassCreateInfo2KHR rpInfo2;
2229 RenderPass2SetupHelper rp2Helper(
this);
2230 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2233 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2234 if (err != VK_SUCCESS) {
2235 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2242 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2243 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2246 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2247 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2248 if (err != VK_SUCCESS) {
2249 qWarning(
"Failed to create renderpass: %d", err);
2260 if (swapChainD->pixelSize.isEmpty()) {
2261 qWarning(
"Surface size is 0, cannot create swapchain");
2265 df->vkDeviceWaitIdle(dev);
2267 if (!vkCreateSwapchainKHR) {
2268 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2269 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2270 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2271 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2272 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2273 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2274 qWarning(
"Swapchain functions not available");
2279 VkSurfaceCapabilitiesKHR surfaceCaps;
2280 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2281 quint32 reqBufferCount;
2282 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2283 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2285 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2287 VkSurfaceTransformFlagBitsKHR preTransform =
2288 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2289 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2290 : surfaceCaps.currentTransform;
2316 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2317 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2318 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2319 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2321 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2322 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2323 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2324 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2325 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2326 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2327 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2328 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2329 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2330 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2333 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2334 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2335 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2336 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2338 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2339 && surfaceCaps.maxImageArrayLayers > 1;
2342 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2343 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2347 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2348 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2349 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2350 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2358 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2360 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2361 reuseExisting ?
"recycled" :
"new",
2362 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2364 VkSwapchainCreateInfoKHR swapChainInfo = {};
2365 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2366 swapChainInfo.surface = swapChainD->surface;
2367 swapChainInfo.minImageCount = reqBufferCount;
2368 swapChainInfo.imageFormat = swapChainD->colorFormat;
2369 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2370 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2371 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2372 swapChainInfo.imageUsage = usage;
2373 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2374 swapChainInfo.preTransform = preTransform;
2375 swapChainInfo.compositeAlpha = compositeAlpha;
2376 swapChainInfo.presentMode = presentMode;
2377 swapChainInfo.clipped =
true;
2378 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2380 VkSwapchainKHR newSwapChain;
2381 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2382 if (err != VK_SUCCESS) {
2383 qWarning(
"Failed to create swapchain: %d", err);
2386 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2391 swapChainD->sc = newSwapChain;
2392 swapChainD->lastConnectedSurface = swapChainD->surface;
2394 quint32 actualSwapChainBufferCount = 0;
2395 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2396 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2397 qWarning(
"Failed to get swapchain images: %d", err);
2401 if (actualSwapChainBufferCount != reqBufferCount)
2402 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2405 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2406 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2407 if (err != VK_SUCCESS) {
2408 qWarning(
"Failed to get swapchain images: %d", err);
2412 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2413 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2414 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2415 if (!createTransientImage(swapChainD->colorFormat,
2416 swapChainD->pixelSize,
2417 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2418 VK_IMAGE_ASPECT_COLOR_BIT,
2419 swapChainD->samples,
2420 &swapChainD->msaaImageMem,
2423 swapChainD->bufferCount))
2425 qWarning(
"Failed to create transient image for MSAA color buffer");
2430 VkFenceCreateInfo fenceInfo = {};
2431 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2432 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2435 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2439 image.image = swapChainImages[i];
2440 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2441 image.msaaImage = msaaImages[i];
2442 image.msaaImageView = msaaViews[i];
2445 VkImageViewCreateInfo imgViewInfo = {};
2446 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2447 imgViewInfo.image = swapChainImages[i];
2448 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2449 imgViewInfo.format = swapChainD->colorFormat;
2450 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2451 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2452 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2453 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2454 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2455 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2456 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2457 if (err != VK_SUCCESS) {
2458 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2464 VkSemaphoreCreateInfo semInfo = {};
2465 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2466 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2471 image.image = swapChainImages[i];
2472 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2473 image.msaaImage = msaaImages[i];
2474 image.msaaImageView = msaaViews[i];
2477 VkImageViewCreateInfo imgViewInfo = {};
2478 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2479 imgViewInfo.image = swapChainImages[i];
2480 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2481 imgViewInfo.format = swapChainD->colorFormat;
2482 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2483 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2484 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2485 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2486 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2487 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2488 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2489 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2490 if (err != VK_SUCCESS) {
2491 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2495 VkSemaphoreCreateInfo semInfo = {};
2496 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2497 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2503 swapChainD->currentImageIndex = 0;
2505 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2507 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2508 VkImageViewCreateInfo viewInfo = {};
2509 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2510 viewInfo.image = texD->image;
2511 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2512 viewInfo.format = texD->viewFormat;
2513 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2514 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2515 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2516 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2517 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2518 viewInfo.subresourceRange.baseMipLevel = 0;
2519 viewInfo.subresourceRange.levelCount = 1;
2520 viewInfo.subresourceRange.baseArrayLayer = 0;
2521 viewInfo.subresourceRange.layerCount = 1;
2522 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2523 if (err != VK_SUCCESS) {
2524 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2529 VkSemaphoreCreateInfo semInfo = {};
2530 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2538 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2540 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2541 if (err != VK_SUCCESS) {
2542 qWarning(
"Failed to create command buffer fence: %d", err);
2548 swapChainD->currentFrameSlot = 0;
2557 if (swapChainD->sc == VK_NULL_HANDLE)
2561 df->vkDeviceWaitIdle(dev);
2565 if (frame.cmdFence) {
2567 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2568 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2569 frame.cmdFence = VK_NULL_HANDLE;
2572 if (frame.imageSem) {
2573 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2574 frame.imageSem = VK_NULL_HANDLE;
2581 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2582 image.fb = VK_NULL_HANDLE;
2584 if (image.imageView) {
2585 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2586 image.imageView = VK_NULL_HANDLE;
2588 if (image.msaaImageView) {
2589 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2590 image.msaaImageView = VK_NULL_HANDLE;
2592 if (image.msaaImage) {
2593 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2594 image.msaaImage = VK_NULL_HANDLE;
2596 if (image.drawSem) {
2597 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2598 image.drawSem = VK_NULL_HANDLE;
2602 if (swapChainD->msaaImageMem) {
2603 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2604 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2607 if (swapChainD->shadingRateMapView) {
2608 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2609 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2612 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2613 swapChainD->sc = VK_NULL_HANDLE;
2620 VkCommandPoolResetFlags flags = 0;
2625 if (releaseCachedResourcesCalledBeforeFrameStart)
2626 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2629 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2635 for (quint64 i = 0; i < timestampValidBits; i += 8)
2636 mask |= 0xFFULL << i;
2637 const quint64 ts0 = timestamp[0] & mask;
2638 const quint64 ts1 = timestamp[1] & mask;
2639 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2640 if (!qFuzzyIsNull(nsecsPerTick)) {
2641 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2642 const double elapsedSec = elapsedMs / 1000.0;
2653 const int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2656 inst->handle()->beginFrame(swapChainD->window);
2666 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2667 if (waitResult != QRhi::FrameOpSuccess)
2672 uint32_t imageIndex = 0;
2673 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2674 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2676 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2677 swapChainD->currentImageIndex = imageIndex;
2680 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2681 return QRhi::FrameOpSwapChainOutOfDate;
2683 if (err == VK_ERROR_DEVICE_LOST) {
2684 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2685 printExtraErrorInfo(err);
2687 return QRhi::FrameOpDeviceLost;
2689 qWarning(
"Failed to acquire next swapchain image: %d", err);
2690 return QRhi::FrameOpError;
2694 currentFrameSlot =
int(swapChainD->currentFrameSlot);
2697 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2703 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2704 if (cbres != QRhi::FrameOpSuccess)
2707 swapChainD->cbWrapper.cb = frame.cmdBuf;
2710 swapChainD->rtWrapper.d.fb = image.fb;
2714 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2715 swapChainD->rtWrapperRight.d.fb = image.fb;
2722 quint64 timestamp[2] = { 0, 0 };
2723 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2724 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2725 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2726 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2728 if (err == VK_SUCCESS) {
2730 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2732 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2734 qWarning(
"Failed to query timestamp: %d", err);
2739 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2740 int timestampQueryIdx = -1;
2741 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2742 if (!timestampQueryPoolMap.testBit(i)) {
2743 timestampQueryPoolMap.setBit(i);
2744 timestampQueryIdx = i * 2;
2748 if (timestampQueryIdx >= 0) {
2749 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2751 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2752 timestampQueryPool, uint32_t(timestampQueryIdx));
2757 return QRhi::FrameOpSuccess;
2765 auto cleanup = qScopeGuard([
this, swapChainD] {
2766 inst->handle()->endFrame(swapChainD->window);
2771 int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2776 VkImageMemoryBarrier presTrans = {};
2777 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2778 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2779 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2780 presTrans.image = image.image;
2781 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2782 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2786 presTrans.srcAccessMask = 0;
2787 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2788 df->vkCmdPipelineBarrier(frame.cmdBuf,
2789 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2790 0, 0,
nullptr, 0,
nullptr,
2794 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2795 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2796 df->vkCmdPipelineBarrier(frame.cmdBuf,
2797 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2798 0, 0,
nullptr, 0,
nullptr,
2806 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2812 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2813 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2815 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2816 needsPresent ? &image.drawSem :
nullptr);
2817 if (submitres != QRhi::FrameOpSuccess)
2825 VkPresentInfoKHR presInfo = {};
2826 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2827 presInfo.swapchainCount = 1;
2828 presInfo.pSwapchains = &swapChainD->sc;
2829 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2830 waitSemaphoresForPresent.append(image.drawSem);
2831 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2832 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2836 inst->presentAboutToBeQueued(swapChainD->window);
2838 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2839 waitSemaphoresForPresent.clear();
2840 if (err != VK_SUCCESS) {
2841 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2842 return QRhi::FrameOpSwapChainOutOfDate;
2843 }
else if (err != VK_SUBOPTIMAL_KHR) {
2844 if (err == VK_ERROR_DEVICE_LOST) {
2845 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2846 printExtraErrorInfo(err);
2848 return QRhi::FrameOpDeviceLost;
2850 qWarning(
"Failed to present: %d", err);
2851 return QRhi::FrameOpError;
2857 inst->presentQueued(swapChainD->window);
2867 return QRhi::FrameOpSuccess;
2886 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2896 VkCommandBufferAllocateInfo cmdBufInfo = {};
2897 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2898 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2899 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2900 cmdBufInfo.commandBufferCount = 1;
2902 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2903 if (err != VK_SUCCESS) {
2904 if (err == VK_ERROR_DEVICE_LOST) {
2905 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2906 printExtraErrorInfo(err);
2908 return QRhi::FrameOpDeviceLost;
2910 qWarning(
"Failed to allocate frame command buffer: %d", err);
2911 return QRhi::FrameOpError;
2915 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2916 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2918 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2919 if (err != VK_SUCCESS) {
2920 if (err == VK_ERROR_DEVICE_LOST) {
2921 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2922 printExtraErrorInfo(err);
2924 return QRhi::FrameOpDeviceLost;
2926 qWarning(
"Failed to begin frame command buffer: %d", err);
2927 return QRhi::FrameOpError;
2930 return QRhi::FrameOpSuccess;
2934 VkSemaphore *waitSem, VkSemaphore *signalSem)
2936 VkResult err =
df->vkEndCommandBuffer(cb);
2937 if (err != VK_SUCCESS) {
2938 if (err == VK_ERROR_DEVICE_LOST) {
2939 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2940 printExtraErrorInfo(err);
2942 return QRhi::FrameOpDeviceLost;
2944 qWarning(
"Failed to end frame command buffer: %d", err);
2945 return QRhi::FrameOpError;
2948 VkSubmitInfo submitInfo = {};
2949 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2950 submitInfo.commandBufferCount = 1;
2951 submitInfo.pCommandBuffers = &cb;
2954 waitSemaphoresForQueueSubmit.append(*waitSem);
2956 signalSemaphoresForQueueSubmit.append(*signalSem);
2958 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2959 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2960 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2961 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2962 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2964 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
2965 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
2966 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
2969 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
2971 waitSemaphoresForQueueSubmit.clear();
2972 signalSemaphoresForQueueSubmit.clear();
2974 if (err != VK_SUCCESS) {
2975 if (err == VK_ERROR_DEVICE_LOST) {
2976 qWarning(
"Device loss detected in vkQueueSubmit()");
2977 printExtraErrorInfo(err);
2979 return QRhi::FrameOpDeviceLost;
2981 qWarning(
"Failed to submit to graphics queue: %d", err);
2982 return QRhi::FrameOpError;
2985 return QRhi::FrameOpSuccess;
2990 for (QVkSwapChain *sc : std::as_const(swapchains)) {
2991 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
2992 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
2993 if (frame.cmdFenceWaitable) {
2994 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2996 if (err != VK_SUCCESS) {
2997 if (err == VK_ERROR_DEVICE_LOST) {
2998 qWarning(
"Device loss detected in vkWaitForFences()");
2999 printExtraErrorInfo(err);
3001 return QRhi::FrameOpDeviceLost;
3003 qWarning(
"Failed to wait for fence: %d", err);
3004 return QRhi::FrameOpError;
3007 df->vkResetFences(dev, 1, &frame.cmdFence);
3008 frame.cmdFenceWaitable =
false;
3012 return QRhi::FrameOpSuccess;
3026 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3028 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3029 if (waitResult != QRhi::FrameOpSuccess)
3035 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3036 if (cbres != QRhi::FrameOpSuccess)
3042 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3043 int timestampQueryIdx = -1;
3044 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3045 if (!timestampQueryPoolMap.testBit(i)) {
3046 timestampQueryPoolMap.setBit(i);
3047 timestampQueryIdx = i * 2;
3051 if (timestampQueryIdx >= 0) {
3052 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3054 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3055 timestampQueryPool, uint32_t(timestampQueryIdx));
3056 ofr.timestampQueryIndex = timestampQueryIdx;
3061 return QRhi::FrameOpSuccess;
3067 Q_ASSERT(ofr.active);
3074 if (ofr.timestampQueryIndex >= 0) {
3075 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3076 timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
3079 if (!ofr.cmdFence) {
3080 VkFenceCreateInfo fenceInfo = {};
3081 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3082 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence);
3083 if (err != VK_SUCCESS) {
3084 qWarning(
"Failed to create command buffer fence: %d", err);
3085 return QRhi::FrameOpError;
3089 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence,
nullptr,
nullptr);
3090 if (submitres != QRhi::FrameOpSuccess)
3094 df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
3095 df->vkResetFences(dev, 1, &ofr.cmdFence);
3102 if (ofr.timestampQueryIndex >= 0) {
3103 quint64 timestamp[2] = { 0, 0 };
3104 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
3105 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3106 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3107 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
3108 ofr.timestampQueryIndex = -1;
3109 if (err == VK_SUCCESS) {
3111 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3115 qWarning(
"Failed to query timestamp: %d", err);
3119 return QRhi::FrameOpSuccess;
3141 swapChainD->cbWrapper.resetCommands();
3142 cb = swapChainD->cbWrapper.cb;
3144 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3145 if (submitres != QRhi::FrameOpSuccess)
3149 df->vkQueueWaitIdle(gfxQueue);
3156 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3159 startPrimaryCommandBuffer(&frame.cmdBuf);
3160 swapChainD->cbWrapper.cb = frame.cmdBuf;
3167 return QRhi::FrameOpSuccess;
3174 u
.access =
int(bufUsage.access);
3175 u
.stage =
int(bufUsage.stage);
3183 u
.access =
int(texUsage.access);
3184 u
.stage =
int(texUsage.stage);
3190 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3193 rtD->lastActiveFrameSlot = currentFrameSlot;
3194 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3196 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3204 texD->lastActiveFrameSlot = currentFrameSlot;
3209 rbD->lastActiveFrameSlot = currentFrameSlot;
3215 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3218 if (rtD->m_desc.depthStencilBuffer()) {
3220 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3227 rbD->lastActiveFrameSlot = currentFrameSlot;
3229 if (rtD->m_desc.depthTexture()) {
3234 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3236 if (rtD->m_desc.depthResolveTexture()) {
3241 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3243 if (rtD->m_desc.shadingRateMap()) {
3248 texD->lastActiveFrameSlot = currentFrameSlot;
3262 VkCommandBuffer secondaryCb;
3264 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3265 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3266 freeSecondaryCbs[currentFrameSlot].removeLast();
3268 VkCommandBufferAllocateInfo cmdBufInfo = {};
3269 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3270 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3271 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3272 cmdBufInfo.commandBufferCount = 1;
3274 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3275 if (err != VK_SUCCESS) {
3276 qWarning(
"Failed to create secondary command buffer: %d", err);
3277 return VK_NULL_HANDLE;
3281 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3282 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3283 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3284 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3285 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3286 cmdBufInheritInfo.subpass = 0;
3288 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3289 cmdBufInheritInfo.framebuffer = rtD->fb;
3291 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3293 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3294 if (err != VK_SUCCESS) {
3295 qWarning(
"Failed to begin secondary command buffer: %d", err);
3296 return VK_NULL_HANDLE;
3304 VkResult err =
df->vkEndCommandBuffer(cb);
3305 if (err != VK_SUCCESS)
3306 qWarning(
"Failed to end secondary command buffer: %d", err);
3310 cmd.args.executeSecondary.cb = cb;
3314 e.lastActiveFrameSlot = currentFrameSlot;
3315 e.secondaryCommandBuffer.cb = cb;
3316 releaseQueue.append(e);
3320 QRhiRenderTarget *rt,
3321 const QColor &colorClearValue,
3322 const QRhiDepthStencilClearValue &depthStencilClearValue,
3323 QRhiResourceUpdateBatch *resourceUpdates,
3324 QRhiCommandBuffer::BeginPassFlags flags)
3329 if (resourceUpdates)
3339 switch (rt->resourceType()) {
3340 case QRhiResource::SwapChainRenderTarget:
3342 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3352 texD->lastActiveFrameSlot = currentFrameSlot;
3355 case QRhiResource::TextureRenderTarget:
3369 cbD->currentTarget = rt;
3374 VkRenderPassBeginInfo rpBeginInfo = {};
3375 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3376 rpBeginInfo.renderPass = rtD
->rp->rp;
3377 rpBeginInfo.framebuffer = rtD->fb;
3378 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3379 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3381 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3382 [](
const VkAttachmentDescription &attDesc) {
3383 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3384 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3387 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3388 if (rpHasAnyClearOp) {
3391 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3392 colorClearValue.alphaF() } };
3397 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3402 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3403 colorClearValue.alphaF() } };
3408 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3413 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3417 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3418 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3422 cmd.args.beginRenderPass.desc = rpBeginInfo;
3423 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3425 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3428 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3433 rateCmd.args.setShadingRate.w = 1;
3434 rateCmd.args.setShadingRate.h = 1;
3446 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3447 cbD->activeSecondaryCbStack.removeLast();
3448 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3455 cbD->currentTarget =
nullptr;
3457 if (resourceUpdates)
3462 QRhiResourceUpdateBatch *resourceUpdates,
3463 QRhiCommandBuffer::BeginPassFlags flags)
3468 if (resourceUpdates)
3476 cbD->computePassState.reset();
3479 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3490 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3491 cbD->activeSecondaryCbStack.removeLast();
3492 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3497 if (resourceUpdates)
3504 Q_ASSERT(psD->pipeline);
3508 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3510 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3514 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3515 cmd.args.bindPipeline.pipeline = psD->pipeline;
3518 cbD->currentGraphicsPipeline =
nullptr;
3519 cbD->currentComputePipeline = ps;
3520 cbD->currentPipelineGeneration = psD->generation;
3523 psD->lastActiveFrameSlot = currentFrameSlot;
3528 QRhiShaderResourceBinding::Type bindingType,
3529 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3531 VkAccessFlags access = 0;
3532 if (bindingType == loadTypeVal) {
3533 access = VK_ACCESS_SHADER_READ_BIT;
3535 access = VK_ACCESS_SHADER_WRITE_BIT;
3536 if (bindingType == loadStoreTypeVal)
3537 access |= VK_ACCESS_SHADER_READ_BIT;
3539 auto it = writtenResources->find(resource);
3540 if (it != writtenResources->end())
3541 it->second.accessFlags |= access;
3542 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3543 writtenResources->insert(resource, { access,
true });
3553 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3554 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3555 if (cbD->currentComputeSrb) {
3559 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3560 accessAndIsNewFlag = { 0,
false };
3563 for (
auto &binding : srbD->m_bindings) {
3564 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3566 case QRhiShaderResourceBinding::ImageLoad:
3567 case QRhiShaderResourceBinding::ImageStore:
3568 case QRhiShaderResourceBinding::ImageLoadStore:
3569 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3572 QRhiShaderResourceBinding::ImageLoad,
3573 QRhiShaderResourceBinding::ImageStore,
3574 QRhiShaderResourceBinding::ImageLoadStore);
3576 case QRhiShaderResourceBinding::BufferLoad:
3577 case QRhiShaderResourceBinding::BufferStore:
3578 case QRhiShaderResourceBinding::BufferLoadStore:
3579 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3582 QRhiShaderResourceBinding::BufferLoad,
3583 QRhiShaderResourceBinding::BufferStore,
3584 QRhiShaderResourceBinding::BufferLoadStore);
3591 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3592 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3593 const bool isNewInThisDispatch = it->second.isNew;
3594 if (accessInThisDispatch && !isNewInThisDispatch) {
3595 if (it.key()->resourceType() == QRhiResource::Texture) {
3597 VkImageMemoryBarrier barrier = {};
3598 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3599 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3601 barrier.subresourceRange.baseMipLevel = 0;
3602 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3603 barrier.subresourceRange.baseArrayLayer = 0;
3604 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3605 barrier.oldLayout = texD->usageState.layout;
3606 barrier.newLayout = texD->usageState.layout;
3607 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3608 barrier.dstAccessMask = accessInThisDispatch;
3609 barrier.image = texD->image;
3610 imageBarriers.append(barrier);
3613 VkBufferMemoryBarrier barrier = {};
3614 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3615 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3616 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3617 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3618 barrier.dstAccessMask = accessInThisDispatch;
3619 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3620 barrier.size = VK_WHOLE_SIZE;
3621 bufferBarriers.append(barrier);
3627 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3628 it = cbD->computePassState.writtenResources.erase(it);
3635 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3636 if (!imageBarriers.isEmpty()) {
3637 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3640 imageBarriers.size(), imageBarriers.constData());
3642 if (!bufferBarriers.isEmpty()) {
3643 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3645 bufferBarriers.size(), bufferBarriers.constData(),
3648 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3650 if (!imageBarriers.isEmpty()) {
3653 cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3654 cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3655 cmd.args.imageBarrier.count = imageBarriers.size();
3656 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3657 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3659 if (!bufferBarriers.isEmpty()) {
3662 cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3663 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3664 cmd.args.bufferBarrier.count = bufferBarriers.size();
3665 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3666 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3670 cmd.args.dispatch.x = x;
3671 cmd.args.dispatch.y = y;
3672 cmd.args.dispatch.z = z;
3678 VkShaderModuleCreateInfo shaderInfo = {};
3679 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3680 shaderInfo.codeSize = size_t(spirv.size());
3681 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3682 VkShaderModule shaderModule;
3683 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3684 if (err != VK_SUCCESS) {
3685 qWarning(
"Failed to create shader module: %d", err);
3686 return VK_NULL_HANDLE;
3688 return shaderModule;
3696 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3697 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3698 pipelineCacheInfo.initialDataSize = initialDataSize;
3699 pipelineCacheInfo.pInitialData = initialData;
3700 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3701 if (err != VK_SUCCESS) {
3702 qWarning(
"Failed to create pipeline cache: %d", err);
3712 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3713 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3714 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3715 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3716 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3718 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3719 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3722 VkWriteDescriptorSet writeInfo = {};
3723 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3724 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3725 writeInfo.dstBinding = uint32_t(b->binding);
3726 writeInfo.descriptorCount = 1;
3728 int bufferInfoIndex = -1;
3729 int imageInfoIndex = -1;
3732 case QRhiShaderResourceBinding::UniformBuffer:
3734 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3735 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3736 QRhiBuffer *buf = b->u.ubuf.buf;
3738 bd.ubuf.id = bufD->m_id;
3739 bd.ubuf.generation = bufD->generation;
3740 VkDescriptorBufferInfo bufInfo;
3741 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3742 bufInfo.offset = b->u.ubuf.offset;
3743 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3745 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3746 bufferInfoIndex = bufferInfos.size();
3747 bufferInfos.append(bufInfo);
3750 case QRhiShaderResourceBinding::SampledTexture:
3752 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3753 writeInfo.descriptorCount = data->count;
3754 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3755 ArrayOfImageDesc imageInfo(data->count);
3756 for (
int elem = 0; elem < data->count; ++elem) {
3759 bd.stex.d[elem].texId = texD->m_id;
3760 bd.stex.d[elem].texGeneration = texD->generation;
3761 bd.stex.d[elem].samplerId = samplerD->m_id;
3762 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3763 imageInfo[elem].sampler = samplerD->sampler;
3764 imageInfo[elem].imageView = texD->imageView;
3765 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3767 bd.stex.count = data->count;
3768 imageInfoIndex = imageInfos.size();
3769 imageInfos.append(imageInfo);
3772 case QRhiShaderResourceBinding::Texture:
3774 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3775 writeInfo.descriptorCount = data->count;
3776 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3777 ArrayOfImageDesc imageInfo(data->count);
3778 for (
int elem = 0; elem < data->count; ++elem) {
3780 bd.stex.d[elem].texId = texD->m_id;
3781 bd.stex.d[elem].texGeneration = texD->generation;
3782 bd.stex.d[elem].samplerId = 0;
3783 bd.stex.d[elem].samplerGeneration = 0;
3784 imageInfo[elem].sampler = VK_NULL_HANDLE;
3785 imageInfo[elem].imageView = texD->imageView;
3786 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3788 bd.stex.count = data->count;
3789 imageInfoIndex = imageInfos.size();
3790 imageInfos.append(imageInfo);
3793 case QRhiShaderResourceBinding::Sampler:
3796 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3797 bd.stex.d[0].texId = 0;
3798 bd.stex.d[0].texGeneration = 0;
3799 bd.stex.d[0].samplerId = samplerD->m_id;
3800 bd.stex.d[0].samplerGeneration = samplerD->generation;
3801 ArrayOfImageDesc imageInfo(1);
3802 imageInfo[0].sampler = samplerD->sampler;
3803 imageInfo[0].imageView = VK_NULL_HANDLE;
3804 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3805 imageInfoIndex = imageInfos.size();
3806 imageInfos.append(imageInfo);
3809 case QRhiShaderResourceBinding::ImageLoad:
3810 case QRhiShaderResourceBinding::ImageStore:
3811 case QRhiShaderResourceBinding::ImageLoadStore:
3814 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3816 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3817 bd.simage.id = texD->m_id;
3818 bd.simage.generation = texD->generation;
3819 ArrayOfImageDesc imageInfo(1);
3820 imageInfo[0].sampler = VK_NULL_HANDLE;
3821 imageInfo[0].imageView = view;
3822 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3823 imageInfoIndex = imageInfos.size();
3824 imageInfos.append(imageInfo);
3828 case QRhiShaderResourceBinding::BufferLoad:
3829 case QRhiShaderResourceBinding::BufferStore:
3830 case QRhiShaderResourceBinding::BufferLoadStore:
3833 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3834 bd.sbuf.id = bufD->m_id;
3835 bd.sbuf.generation = bufD->generation;
3836 VkDescriptorBufferInfo bufInfo;
3837 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3838 bufInfo.offset = b->u.sbuf.offset;
3839 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3840 bufferInfoIndex = bufferInfos.size();
3841 bufferInfos.append(bufInfo);
3848 writeInfos.append(writeInfo);
3849 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3852 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3853 const int bufferInfoIndex = infoIndices[i].first;
3854 const int imageInfoIndex = infoIndices[i].second;
3855 if (bufferInfoIndex >= 0)
3856 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3857 else if (imageInfoIndex >= 0)
3858 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3861 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3866 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3867 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3868 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3869 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3870 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3871 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3875 VkAccessFlags access, VkPipelineStageFlags stage)
3878 Q_ASSERT(access && stage);
3886 if (s.access == access && s.stage == stage) {
3889 if (!accessIsWrite(access))
3893 VkBufferMemoryBarrier bufMemBarrier = {};
3894 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3895 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3896 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3897 bufMemBarrier.srcAccessMask = s.access;
3898 bufMemBarrier.dstAccessMask = access;
3899 bufMemBarrier.buffer = bufD->buffers[slot];
3900 bufMemBarrier.size = VK_WHOLE_SIZE;
3904 cmd.args.bufferBarrier.srcStageMask = s.stage;
3905 cmd.args.bufferBarrier.dstStageMask = stage;
3906 cmd.args.bufferBarrier.count = 1;
3907 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3908 cbD->pools.bufferBarrier.append(bufMemBarrier);
3915 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3918 Q_ASSERT(layout && access && stage);
3920 if (s.access == access && s.stage == stage && s.layout == layout) {
3921 if (!accessIsWrite(access))
3925 VkImageMemoryBarrier barrier = {};
3926 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3927 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3928 barrier.subresourceRange.baseMipLevel = 0;
3929 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3930 barrier.subresourceRange.baseArrayLayer = 0;
3931 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3932 barrier.oldLayout = s.layout;
3933 barrier.newLayout = layout;
3934 barrier.srcAccessMask = s.access;
3935 barrier.dstAccessMask = access;
3936 barrier.image = texD->image;
3938 VkPipelineStageFlags srcStage = s.stage;
3941 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3945 cmd.args.imageBarrier.srcStageMask = srcStage;
3946 cmd.args.imageBarrier.dstStageMask = stage;
3947 cmd.args.imageBarrier.count = 1;
3948 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3949 cbD->pools.imageBarrier.append(barrier);
3960 VkImageMemoryBarrier barrier = {};
3961 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3962 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
3963 barrier.subresourceRange.baseMipLevel = 0;
3964 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3965 barrier.subresourceRange.baseArrayLayer = 0;
3966 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3967 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3968 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
3969 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3970 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
3971 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3972 barrier.image = rbD->image;
3974 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
3975 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
3979 cmd.args.imageBarrier.srcStageMask = stages;
3980 cmd.args.imageBarrier.dstStageMask = stages;
3981 cmd.args.imageBarrier.count = 1;
3982 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3983 cbD->pools.imageBarrier.append(barrier);
3987 VkImageLayout oldLayout, VkImageLayout newLayout,
3988 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
3989 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
3990 int startLayer,
int layerCount,
3991 int startLevel,
int levelCount)
3994 VkImageMemoryBarrier barrier = {};
3995 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3996 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3997 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
3998 barrier.subresourceRange.levelCount = uint32_t(levelCount);
3999 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4000 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4001 barrier.oldLayout = oldLayout;
4002 barrier.newLayout = newLayout;
4003 barrier.srcAccessMask = srcAccess;
4004 barrier.dstAccessMask = dstAccess;
4005 barrier.image = image;
4009 cmd.args.imageBarrier.srcStageMask = srcStage;
4010 cmd.args.imageBarrier.dstStageMask = dstStage;
4011 cmd.args.imageBarrier.count = 1;
4012 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4013 cbD->pools.imageBarrier.append(barrier);
4018 VkDeviceSize size = 0;
4019 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4020 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4021 if (imageSizeBytes > 0)
4022 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4027 const QRhiTextureSubresourceUploadDescription &subresDesc,
4028 size_t *curOfs,
void *mp,
4029 BufferImageCopyList *copyInfos)
4031 qsizetype copySizeBytes = 0;
4032 qsizetype imageSizeBytes = 0;
4033 const void *src =
nullptr;
4034 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4035 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4037 VkBufferImageCopy copyInfo = {};
4038 copyInfo.bufferOffset = *curOfs;
4039 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4040 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4041 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4042 copyInfo.imageSubresource.layerCount = 1;
4043 copyInfo.imageExtent.depth = 1;
4045 copyInfo.imageOffset.z = uint32_t(layer);
4047 copyInfo.imageOffset.y = uint32_t(layer);
4049 const QByteArray rawData = subresDesc.data();
4050 const QPoint dp = subresDesc.destinationTopLeft();
4051 QImage image = subresDesc.image();
4052 if (!image.isNull()) {
4053 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4054 QSize size = image.size();
4055 src = image.constBits();
4058 int bpc = qMax(1, image.depth() / 8);
4060 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4061 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4062 const int sx = subresDesc.sourceTopLeft().x();
4063 const int sy = subresDesc.sourceTopLeft().y();
4064 if (!subresDesc.sourceSize().isEmpty())
4065 size = subresDesc.sourceSize();
4066 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4067 if (size.width() == image.width()) {
4070 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4071 copySizeBytes = size.height() * image.bytesPerLine();
4073 image = image.copy(sx, sy, size.width(), size.height());
4074 src = image.constBits();
4077 copySizeBytes = image.sizeInBytes();
4078 bpc = qMax(1, image.depth() / 8);
4079 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4082 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4084 copyInfo.imageOffset.x = dp.x();
4085 copyInfo.imageOffset.y = dp.y();
4086 copyInfo.imageExtent.width = uint32_t(size.width());
4087 copyInfo.imageExtent.height = uint32_t(size.height());
4088 copyInfos->append(copyInfo);
4089 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4090 copySizeBytes = imageSizeBytes = rawData.size();
4091 src = rawData.constData();
4092 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4093 const int subresw = size.width();
4094 const int subresh = size.height();
4095 if (!subresDesc.sourceSize().isEmpty())
4096 size = subresDesc.sourceSize();
4097 const int w = size.width();
4098 const int h = size.height();
4100 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4102 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4103 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4106 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4107 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4108 copyInfos->append(copyInfo);
4109 }
else if (!rawData.isEmpty()) {
4110 copySizeBytes = imageSizeBytes = rawData.size();
4111 src = rawData.constData();
4112 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4113 if (subresDesc.dataStride()) {
4114 quint32 bytesPerPixel = 0;
4115 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4117 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4119 if (!subresDesc.sourceSize().isEmpty())
4120 size = subresDesc.sourceSize();
4121 copyInfo.imageOffset.x = dp.x();
4122 copyInfo.imageOffset.y = dp.y();
4123 copyInfo.imageExtent.width = uint32_t(size.width());
4124 copyInfo.imageExtent.height = uint32_t(size.height());
4125 copyInfos->append(copyInfo);
4127 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4131 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4132 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4138 if (err == VK_ERROR_DEVICE_LOST)
4140 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4141 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4146#ifdef VK_EXT_device_fault
4147 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4150 VkDeviceFaultCountsEXT faultCounts{};
4151 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4152 faultCounts.pNext =
nullptr;
4154 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4155 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4156 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4159 faultCounts.vendorBinarySize = 0;
4161 QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
4162 addressInfos.resize(faultCounts.addressInfoCount);
4164 QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
4165 vendorInfos.resize(faultCounts.vendorInfoCount);
4167 VkDeviceFaultInfoEXT info{};
4168 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4169 info.pNext =
nullptr;
4170 info.pAddressInfos = addressInfos.isEmpty() ?
nullptr : addressInfos.data();
4171 info.pVendorInfos = vendorInfos.isEmpty() ?
nullptr : vendorInfos.data();
4172 info.pVendorBinaryData =
nullptr;
4174 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4175 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4176 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4180 const char *desc = info.description[0] ? info.description :
"n/a";
4181 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4182 faultCounts.addressInfoCount,
4183 faultCounts.vendorInfoCount,
4184 (
unsigned long long)faultCounts.vendorBinarySize,
4187 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4188 const auto &a = addressInfos[i];
4189 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4191 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4192 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4193 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4194 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4195 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4196 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4197 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4198 default:
return "UNKNOWN";
4201 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4203 addressTypeString(a.addressType),
4204 (
unsigned long long)a.reportedAddress,
4205 (
unsigned long long)a.addressPrecision);
4208 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4209 const auto &v = vendorInfos[i];
4210 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4212 (
unsigned long long)v.vendorFaultCode,
4213 (
unsigned long long)v.vendorFaultData,
4227 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4229 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4230 bufD->pendingDynamicUpdates[i].clear();
4231 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4235 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4236 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4238 if (!bufD->stagingBuffers[currentFrameSlot]) {
4239 VkBufferCreateInfo bufferInfo = {};
4240 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4243 bufferInfo.size = bufD->m_size;
4244 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4246 VmaAllocationCreateInfo allocInfo = {};
4247 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4249 VmaAllocation allocation;
4250 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4251 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4252 if (err == VK_SUCCESS) {
4253 bufD->stagingAllocations[currentFrameSlot] = allocation;
4254 setAllocationName(allocation, bufD->name());
4256 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4257 printExtraErrorInfo(err);
4262 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4263 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4264 u.offset, u
.data.size());
4265 if (err != VK_SUCCESS) {
4266 qWarning(
"Failed to copy memory to buffer: %d", err);
4270 trackedBufferBarrier(cbD, bufD, 0,
4271 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4273 VkBufferCopy copyInfo = {};
4274 copyInfo.srcOffset = u.offset;
4275 copyInfo.dstOffset = u.offset;
4276 copyInfo.size = u
.data.size();
4280 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4281 cmd.args.copyBuffer.dst = bufD->buffers[0];
4282 cmd.args.copyBuffer.desc = copyInfo;
4291 bufD->lastActiveFrameSlot = currentFrameSlot;
4293 if (bufD->m_type == QRhiBuffer::Immutable) {
4296 e.lastActiveFrameSlot = currentFrameSlot;
4297 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4298 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4299 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4300 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4301 releaseQueue.append(e);
4305 if (bufD->m_type == QRhiBuffer::Dynamic) {
4307 u.result->data.resizeForOverwrite(u.readSize);
4308 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4309 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4310 u.offset, u.result->data.data(), u.readSize);
4311 if (err != VK_SUCCESS) {
4312 qWarning(
"Failed to copy memory from buffer: %d", err);
4313 u.result->data.clear();
4315 if (u.result->completed)
4316 u.result->completed();
4325 readback.activeFrameSlot = currentFrameSlot;
4326 readback.result = u.result;
4327 readback.byteSize = u.readSize;
4329 VkBufferCreateInfo bufferInfo = {};
4330 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4331 bufferInfo.size = readback.byteSize;
4332 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4334 VmaAllocationCreateInfo allocInfo = {};
4335 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4337 VmaAllocation allocation;
4338 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4339 if (err == VK_SUCCESS) {
4341 setAllocationName(allocation, bufD->name());
4343 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4344 printExtraErrorInfo(err);
4348 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4350 VkBufferCopy copyInfo = {};
4351 copyInfo.srcOffset = u.offset;
4352 copyInfo.size = u.readSize;
4356 cmd.args.copyBuffer.src = bufD->buffers[0];
4357 cmd.args.copyBuffer.dst = readback.stagingBuf;
4358 cmd.args.copyBuffer.desc = copyInfo;
4360 bufD->lastActiveFrameSlot = currentFrameSlot;
4362 activeBufferReadbacks.append(readback);
4372 VkDeviceSize stagingSize = 0;
4373 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4374 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4375 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4376 stagingSize += subresUploadByteSize(subresDesc);
4380 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4381 VkBufferCreateInfo bufferInfo = {};
4382 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4383 bufferInfo.size = stagingSize;
4384 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4386 VmaAllocationCreateInfo allocInfo = {};
4387 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4389 VmaAllocation allocation;
4390 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4391 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4392 if (err != VK_SUCCESS) {
4393 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4394 printExtraErrorInfo(err);
4397 utexD->stagingAllocations[currentFrameSlot] = allocation;
4398 setAllocationName(allocation, utexD->name());
4400 BufferImageCopyList copyInfos;
4403 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4404 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4405 if (err != VK_SUCCESS) {
4406 qWarning(
"Failed to map image data: %d", err);
4410 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4411 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4412 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4415 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4416 prepareUploadSubres(utexD, layer, level,
4417 subresDesc, &curOfs, mp, ©Infos);
4421 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4422 vmaUnmapMemory(toVmaAllocator(allocator), a);
4424 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4425 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4429 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4430 cmd.args.copyBufferToImage.dst = utexD->image;
4431 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4432 cmd.args.copyBufferToImage.count = copyInfos.size();
4433 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4434 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4439 e.lastActiveFrameSlot = currentFrameSlot;
4440 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4441 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4442 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4443 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4444 releaseQueue.append(e);
4449 utexD->lastActiveFrameSlot = currentFrameSlot;
4453 qWarning(
"Texture copy with matching source and destination is not supported");
4458 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4459 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4461 VkImageCopy region = {};
4462 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4463 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4464 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4465 region.srcSubresource.layerCount = 1;
4467 region.srcOffset.x = u.desc.sourceTopLeft().x();
4468 region.srcOffset.y = u.desc.sourceTopLeft().y();
4470 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4472 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4473 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4474 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4475 region.dstSubresource.layerCount = 1;
4477 region.dstOffset.x = u.desc.destinationTopLeft().x();
4478 region.dstOffset.y = u.desc.destinationTopLeft().y();
4480 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4482 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4483 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4484 region.extent.width = uint32_t(copySize.width());
4485 region.extent.height = uint32_t(copySize.height());
4486 region.extent.depth = 1;
4488 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4489 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4490 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4491 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4495 cmd.args.copyImage.src = srcD->image;
4496 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4497 cmd.args.copyImage.dst = dstD->image;
4498 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4499 cmd.args.copyImage.desc = region;
4501 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4504 readback.activeFrameSlot = currentFrameSlot;
4505 readback.desc = u.rb;
4506 readback.result = u.result;
4512 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4513 qWarning(
"Multisample texture cannot be read back");
4516 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4517 if (u.rb.rect().isValid())
4518 readback.rect = u.rb.rect();
4520 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4521 readback.format = texD->m_format;
4522 texD->lastActiveFrameSlot = currentFrameSlot;
4527 qWarning(
"Swapchain does not support readback");
4530 if (u.rb.rect().isValid())
4531 readback.rect = u.rb.rect();
4533 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4534 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4535 if (readback.format == QRhiTexture::UnknownFormat)
4541 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4544 VkBufferCreateInfo bufferInfo = {};
4545 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4546 bufferInfo.size = readback.byteSize;
4547 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4549 VmaAllocationCreateInfo allocInfo = {};
4550 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4552 VmaAllocation allocation;
4553 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4554 if (err == VK_SUCCESS) {
4556 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4558 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4559 printExtraErrorInfo(err);
4564 VkBufferImageCopy copyDesc = {};
4565 copyDesc.bufferOffset = 0;
4566 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4567 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4568 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4569 copyDesc.imageSubresource.layerCount = 1;
4570 copyDesc.imageOffset.x = readback.rect.x();
4571 copyDesc.imageOffset.y = readback.rect.y();
4573 copyDesc.imageOffset.z = u.rb.layer();
4574 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4575 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4576 copyDesc.imageExtent.depth = 1;
4579 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4580 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4583 cmd.args.copyImageToBuffer.src = texD->image;
4584 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4585 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4586 cmd.args.copyImageToBuffer.desc = copyDesc;
4590 VkImage image = imageRes.image;
4593 qWarning(
"Attempted to read back undefined swapchain image content, "
4594 "results are undefined. (do a render pass first)");
4596 subresourceBarrier(cbD, image,
4597 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4598 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4599 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4607 cmd.args.copyImageToBuffer.src = image;
4608 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4609 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4610 cmd.args.copyImageToBuffer.desc = copyDesc;
4613 activeTextureReadbacks.append(readback);
4616 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4617 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4618 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4619 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4621 VkImageLayout origLayout = utexD->usageState.layout;
4622 VkAccessFlags origAccess = utexD->usageState.access;
4623 VkPipelineStageFlags origStage = utexD->usageState.stage;
4625 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4627 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4628 int w = utexD->m_pixelSize.width();
4629 int h = utexD->m_pixelSize.height();
4630 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4631 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4633 subresourceBarrier(cbD, utexD->image,
4634 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4635 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4636 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4640 subresourceBarrier(cbD, utexD->image,
4641 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4642 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4643 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4648 subresourceBarrier(cbD, utexD->image,
4649 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4650 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4651 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4655 VkImageBlit region = {};
4656 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4657 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4658 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4659 region.srcSubresource.layerCount = 1;
4661 region.srcOffsets[1].x = qMax(1, w);
4662 region.srcOffsets[1].y = qMax(1, h);
4663 region.srcOffsets[1].z = qMax(1, depth);
4665 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4666 region.dstSubresource.mipLevel = uint32_t(level);
4667 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4668 region.dstSubresource.layerCount = 1;
4670 region.dstOffsets[1].x = qMax(1, w >> 1);
4671 region.dstOffsets[1].y = qMax(1, h >> 1);
4672 region.dstOffsets[1].z = qMax(1, depth >> 1);
4676 cmd.args.blitImage.src = utexD->image;
4677 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4678 cmd.args.blitImage.dst = utexD->image;
4679 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4680 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4681 cmd.args.blitImage.desc = region;
4688 if (utexD->mipLevelCount > 1) {
4689 subresourceBarrier(cbD, utexD->image,
4690 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4691 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4692 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4694 0,
int(utexD->mipLevelCount) - 1);
4695 subresourceBarrier(cbD, utexD->image,
4696 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4697 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4698 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4700 int(utexD->mipLevelCount) - 1, 1);
4703 utexD->lastActiveFrameSlot = currentFrameSlot;
4712 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4715 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4717 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4721 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4722 if (err != VK_SUCCESS) {
4723 qWarning(
"Failed to map buffer: %d", err);
4726 quint32 changeBegin = UINT32_MAX;
4727 quint32 changeEnd = 0;
4728 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4729 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4730 if (u.offset < changeBegin)
4731 changeBegin = u.offset;
4732 if (u.offset + u.data.size() > changeEnd)
4733 changeEnd = u.offset + u.data.size();
4735 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4736 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4737 vmaUnmapMemory(toVmaAllocator(allocator), a);
4739 bufD->pendingDynamicUpdates[slot].clear();
4745 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4746 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4752 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4753 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4754 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4759 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4760 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4762 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4763 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4764 if (e.texture.extraImageViews[i])
4765 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4771 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4776 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4778 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4781 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4782 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4785 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4786 if (e.shaderResourceBindings.poolIndex >= 0) {
4787 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4788 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4795 qrhivk_releaseRenderBuffer(e, dev,
df);
4801 qrhivk_releaseSampler(e, dev,
df);
4804 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4806 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4807 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4809 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4810 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4811 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4814 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4817 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4819 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4820 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4826 releaseQueue.removeAt(i);
4833 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4835 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4837 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4838 readback.result->format = readback.format;
4839 readback.result->pixelSize = readback.rect.size();
4840 readback.result->data.resizeForOverwrite(readback.byteSize);
4841 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4842 toVmaAllocation(readback.stagingAlloc),
4843 0, readback.result->data.data(), readback.byteSize);
4844 if (err != VK_SUCCESS) {
4845 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4846 readback.result->data.clear();
4849 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4851 if (readback.result->completed)
4852 completedCallbacks.append(readback.result->completed);
4854 activeTextureReadbacks.remove(i);
4858 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4860 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4861 readback.result->data.resizeForOverwrite(readback.byteSize);
4862 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4863 toVmaAllocation(readback.stagingAlloc),
4864 0, readback.result->data.data(), readback.byteSize);
4865 if (err != VK_SUCCESS) {
4866 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4867 readback.result->data.clear();
4870 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4872 if (readback.result->completed)
4873 completedCallbacks.append(readback.result->completed);
4875 activeBufferReadbacks.remove(i);
4879 for (
const auto &f : completedCallbacks)
4886} qvk_sampleCounts[] = {
4888 { VK_SAMPLE_COUNT_1_BIT, 1 },
4889 { VK_SAMPLE_COUNT_2_BIT, 2 },
4890 { VK_SAMPLE_COUNT_4_BIT, 4 },
4891 { VK_SAMPLE_COUNT_8_BIT, 8 },
4892 { VK_SAMPLE_COUNT_16_BIT, 16 },
4893 { VK_SAMPLE_COUNT_32_BIT, 32 },
4894 { VK_SAMPLE_COUNT_64_BIT, 64 }
4899 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4900 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4901 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4902 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4905 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4906 if ((color & qvk_sampleCount.mask)
4907 && (depth & qvk_sampleCount.mask)
4908 && (stencil & qvk_sampleCount.mask))
4910 result.append(qvk_sampleCount.count);
4919 const int s = effectiveSampleCount(sampleCount);
4921 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4922 if (qvk_sampleCount.count == s)
4923 return qvk_sampleCount.mask;
4926 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4931 QList<QSize> result;
4932#ifdef VK_KHR_fragment_shading_rate
4933 sampleCount = qMax(1, sampleCount);
4934 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4935 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4936 if (qvk_sampleCount.count == sampleCount) {
4937 mask = qvk_sampleCount.mask;
4941 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4942 if (s.sampleCounts & mask)
4943 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4946 Q_UNUSED(sampleCount);
4947 result.append(QSize(1, 1));
4954 cbD->passResTrackers.emplace_back();
4959 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
4966 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
4970 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
4971 1, &cmd.args.copyBuffer.desc);
4974 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
4975 cmd.args.copyBufferToImage.dstLayout,
4976 uint32_t(cmd.args.copyBufferToImage.count),
4977 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
4980 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
4981 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
4982 1, &cmd.args.copyImage.desc);
4985 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
4986 cmd.args.copyImageToBuffer.dst,
4987 1, &cmd.args.copyImageToBuffer.desc);
4990 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
4991 0, 0,
nullptr, 0,
nullptr,
4992 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
4995 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
4997 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5001 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5002 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5003 1, &cmd.args.blitImage.desc,
5004 cmd.args.blitImage.filter);
5007 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5008 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5009 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5010 : VK_SUBPASS_CONTENTS_INLINE);
5013 VkMemoryBarrier barrier;
5014 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5015 barrier.pNext =
nullptr;
5016 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5017 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5018 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5024 df->vkCmdEndRenderPass(cbD->cb);
5027 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5031 const uint32_t *offsets =
nullptr;
5032 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5033 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5034 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5035 cmd.args.bindDescriptorSet.pipelineLayout,
5036 0, 1, &cmd.args.bindDescriptorSet.descSet,
5037 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5042 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5043 uint32_t(cmd.args.bindVertexBuffer.count),
5044 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5045 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5048 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5049 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5052 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5055 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5058 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5061 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5064 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5065 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5068 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5069 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5070 cmd.args.drawIndexed.firstInstance);
5073 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5074 cmd.args.drawIndirect.indirectBufferOffset,
5075 cmd.args.drawIndirect.drawCount,
5076 cmd.args.drawIndirect.stride);
5079 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5080 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5081 cmd.args.drawIndexedIndirect.drawCount,
5082 cmd.args.drawIndexedIndirect.stride);
5085#ifdef VK_EXT_debug_utils
5086 cmd.args.debugMarkerBegin.label.pLabelName =
5087 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5088 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5092#ifdef VK_EXT_debug_utils
5093 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5097#ifdef VK_EXT_debug_utils
5098 cmd.args.debugMarkerInsert.label.pLabelName =
5099 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5100 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5107 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5110 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5114#ifdef VK_KHR_fragment_shading_rate
5115 VkFragmentShadingRateCombinerOpKHR op[2] = {
5116 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5117 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5119 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5120 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5133 case QRhiPassResourceTracker::BufIndirectDraw:
5134 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5135 case QRhiPassResourceTracker::BufVertexInput:
5136 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5137 case QRhiPassResourceTracker::BufIndexRead:
5138 return VK_ACCESS_INDEX_READ_BIT;
5139 case QRhiPassResourceTracker::BufUniformRead:
5140 return VK_ACCESS_UNIFORM_READ_BIT;
5141 case QRhiPassResourceTracker::BufStorageLoad:
5142 return VK_ACCESS_SHADER_READ_BIT;
5143 case QRhiPassResourceTracker::BufStorageStore:
5144 return VK_ACCESS_SHADER_WRITE_BIT;
5145 case QRhiPassResourceTracker::BufStorageLoadStore:
5146 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5157 case QRhiPassResourceTracker::BufIndirectDrawStage:
5158 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5159 case QRhiPassResourceTracker::BufVertexInputStage:
5160 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5161 case QRhiPassResourceTracker::BufVertexStage:
5162 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5163 case QRhiPassResourceTracker::BufTCStage:
5164 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5165 case QRhiPassResourceTracker::BufTEStage:
5166 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5167 case QRhiPassResourceTracker::BufFragmentStage:
5168 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5169 case QRhiPassResourceTracker::BufComputeStage:
5170 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5171 case QRhiPassResourceTracker::BufGeometryStage:
5172 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5183 u.access = VkAccessFlags(usage
.access);
5184 u.stage = VkPipelineStageFlags(usage
.stage);
5191 case QRhiPassResourceTracker::TexSample:
5192 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5193 case QRhiPassResourceTracker::TexColorOutput:
5194 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5195 case QRhiPassResourceTracker::TexDepthOutput:
5196 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5197 case QRhiPassResourceTracker::TexStorageLoad:
5198 case QRhiPassResourceTracker::TexStorageStore:
5199 case QRhiPassResourceTracker::TexStorageLoadStore:
5200 return VK_IMAGE_LAYOUT_GENERAL;
5201 case QRhiPassResourceTracker::TexShadingRate:
5202#ifdef VK_KHR_fragment_shading_rate
5203 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5205 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5211 return VK_IMAGE_LAYOUT_GENERAL;
5217 case QRhiPassResourceTracker::TexSample:
5218 return VK_ACCESS_SHADER_READ_BIT;
5219 case QRhiPassResourceTracker::TexColorOutput:
5220 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5221 case QRhiPassResourceTracker::TexDepthOutput:
5222 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5223 case QRhiPassResourceTracker::TexStorageLoad:
5224 return VK_ACCESS_SHADER_READ_BIT;
5225 case QRhiPassResourceTracker::TexStorageStore:
5226 return VK_ACCESS_SHADER_WRITE_BIT;
5227 case QRhiPassResourceTracker::TexStorageLoadStore:
5228 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5241 case QRhiPassResourceTracker::TexVertexStage:
5242 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5243 case QRhiPassResourceTracker::TexTCStage:
5244 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5245 case QRhiPassResourceTracker::TexTEStage:
5246 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5247 case QRhiPassResourceTracker::TexFragmentStage:
5248 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5249 case QRhiPassResourceTracker::TexColorOutputStage:
5250 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5251 case QRhiPassResourceTracker::TexDepthOutputStage:
5252 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5253 case QRhiPassResourceTracker::TexComputeStage:
5254 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5255 case QRhiPassResourceTracker::TexGeometryStage:
5256 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5267 u.layout = VkImageLayout(usage
.layout);
5268 u.access = VkAccessFlags(usage
.access);
5269 u.stage = VkPipelineStageFlags(usage
.stage);
5280 const VkAccessFlags newAccess = toVkAccess(access);
5281 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5282 if (u.access == newAccess && u.stage == newStage) {
5283 if (!accessIsWrite(access))
5287 u.access = newAccess;
5297 const VkAccessFlags newAccess = toVkAccess(access);
5298 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5299 const VkImageLayout newLayout = toVkLayout(access);
5300 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5301 if (!accessIsWrite(access))
5305 u.layout = newLayout;
5306 u.access = newAccess;
5315 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5316 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5317 VkAccessFlags access = toVkAccess(trackedB.access);
5318 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5319 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5322 if (s.access == access && s.stage == stage) {
5323 if (!accessIsWrite(access))
5326 VkBufferMemoryBarrier bufMemBarrier = {};
5327 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5328 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5329 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5330 bufMemBarrier.srcAccessMask = s.access;
5331 bufMemBarrier.dstAccessMask = access;
5332 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5333 bufMemBarrier.size = VK_WHOLE_SIZE;
5334 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5340 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5341 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5342 VkImageLayout layout = toVkLayout(trackedT.access);
5343 VkAccessFlags access = toVkAccess(trackedT.access);
5344 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5345 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5346 if (s.access == access && s.stage == stage && s.layout == layout) {
5347 if (!accessIsWrite(access))
5350 VkImageMemoryBarrier barrier = {};
5351 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5352 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5353 barrier.subresourceRange.baseMipLevel = 0;
5354 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5355 barrier.subresourceRange.baseArrayLayer = 0;
5356 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5357 barrier.oldLayout = s.layout;
5358 barrier.newLayout = layout;
5359 barrier.srcAccessMask = s.access;
5360 barrier.dstAccessMask = access;
5361 barrier.image = texD->image;
5362 VkPipelineStageFlags srcStage = s.stage;
5365 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5366 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5375 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5376 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5377 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5379 qWarning(
"Physical device surface queries not available");
5383 return new QVkSwapChain(
this);
5386QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5388 return new QVkBuffer(
this, type, usage, size);
5393 return int(ubufAlign);
5415 static QMatrix4x4 m;
5416 if (m.isIdentity()) {
5418 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5419 0.0f, -1.0f, 0.0f, 0.0f,
5420 0.0f, 0.0f, 0.5f, 0.5f,
5421 0.0f, 0.0f, 0.0f, 1.0f);
5431 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5432 if (!physDevFeatures.textureCompressionBC)
5436 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5437 if (!physDevFeatures.textureCompressionETC2)
5441 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5442 if (!physDevFeatures.textureCompressionASTC_LDR)
5446 VkFormat vkformat = toVkTextureFormat(format, flags);
5447 VkFormatProperties props;
5448 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5449 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5455 case QRhi::MultisampleTexture:
5457 case QRhi::MultisampleRenderBuffer:
5459 case QRhi::DebugMarkers:
5460 return caps.debugUtils;
5461 case QRhi::Timestamps:
5462 return timestampValidBits != 0;
5463 case QRhi::Instancing:
5465 case QRhi::CustomInstanceStepRate:
5466 return caps.vertexAttribDivisor;
5467 case QRhi::PrimitiveRestart:
5469 case QRhi::NonDynamicUniformBuffers:
5471 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5473 case QRhi::NPOTTextureRepeat:
5475 case QRhi::RedOrAlpha8IsRed:
5477 case QRhi::ElementIndexUint:
5480 return caps.compute;
5481 case QRhi::WideLines:
5482 return caps.wideLines;
5483 case QRhi::VertexShaderPointSize:
5485 case QRhi::BaseVertex:
5487 case QRhi::BaseInstance:
5489 case QRhi::TriangleFanTopology:
5491 case QRhi::ReadBackNonUniformBuffer:
5493 case QRhi::ReadBackNonBaseMipLevel:
5495 case QRhi::TexelFetch:
5497 case QRhi::RenderToNonBaseMipLevel:
5499 case QRhi::IntAttributes:
5501 case QRhi::ScreenSpaceDerivatives:
5503 case QRhi::ReadBackAnyTextureFormat:
5505 case QRhi::PipelineCacheDataLoadSave:
5507 case QRhi::ImageDataStride:
5509 case QRhi::RenderBufferImport:
5511 case QRhi::ThreeDimensionalTextures:
5513 case QRhi::RenderTo3DTextureSlice:
5514 return caps.texture3DSliceAs2D;
5515 case QRhi::TextureArrays:
5517 case QRhi::Tessellation:
5518 return caps.tessellation;
5519 case QRhi::GeometryShader:
5520 return caps.geometryShader;
5521 case QRhi::TextureArrayRange:
5523 case QRhi::NonFillPolygonMode:
5524 return caps.nonFillPolygonMode;
5525 case QRhi::OneDimensionalTextures:
5527 case QRhi::OneDimensionalTextureMipmaps:
5529 case QRhi::HalfAttributes:
5531 case QRhi::RenderToOneDimensionalTexture:
5533 case QRhi::ThreeDimensionalTextureMipmaps:
5535 case QRhi::MultiView:
5536 return caps.multiView;
5537 case QRhi::TextureViewFormat:
5539 case QRhi::ResolveDepthStencil:
5540 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5541 case QRhi::VariableRateShading:
5542 return caps.renderPass2KHR && caps.perDrawShadingRate;
5543 case QRhi::VariableRateShadingMap:
5544 case QRhi::VariableRateShadingMapWithTexture:
5545 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5546 case QRhi::PerRenderTargetBlending:
5547 case QRhi::SampleVariables:
5549 case QRhi::InstanceIndexIncludesBaseInstance:
5551 case QRhi::DepthClamp:
5553 case QRhi::DrawIndirect:
5555 case QRhi::DrawIndirectMulti:
5556 return caps.drawIndirectMulti;
5558 Q_UNREACHABLE_RETURN(
false);
5565 case QRhi::TextureSizeMin:
5567 case QRhi::TextureSizeMax:
5568 return int(physDevProperties.limits.maxImageDimension2D);
5569 case QRhi::MaxColorAttachments:
5570 return int(physDevProperties.limits.maxColorAttachments);
5571 case QRhi::FramesInFlight:
5573 case QRhi::MaxAsyncReadbackFrames:
5575 case QRhi::MaxThreadGroupsPerDimension:
5576 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5577 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5578 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5579 case QRhi::MaxThreadsPerThreadGroup:
5580 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5581 case QRhi::MaxThreadGroupX:
5582 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5583 case QRhi::MaxThreadGroupY:
5584 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5585 case QRhi::MaxThreadGroupZ:
5586 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5587 case QRhi::TextureArraySizeMax:
5588 return int(physDevProperties.limits.maxImageArrayLayers);
5589 case QRhi::MaxUniformBufferRange:
5590 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5591 case QRhi::MaxVertexInputs:
5592 return physDevProperties.limits.maxVertexInputAttributes;
5593 case QRhi::MaxVertexOutputs:
5594 return physDevProperties.limits.maxVertexOutputComponents / 4;
5595 case QRhi::ShadingRateImageTileSize:
5596 return caps.imageBasedShadingRateTileSize;
5598 Q_UNREACHABLE_RETURN(0);
5604 return &nativeHandlesStruct;
5609 return driverInfoStruct;
5615 result.totalPipelineCreationTime = totalPipelineCreationTime();
5617 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5618 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5620 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5621 for (uint32_t i = 0; i < count; ++i) {
5622 const VmaStatistics &stats(budgets[i].statistics);
5623 result.blockCount += stats.blockCount;
5624 result.allocCount += stats.allocationCount;
5625 result.usedBytes += stats.allocationBytes;
5626 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5640 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5644 waitSemaphoresForQueueSubmit.clear();
5645 if (sp->waitSemaphoreCount)
5646 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5648 signalSemaphoresForQueueSubmit.clear();
5649 if (sp->signalSemaphoreCount)
5650 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5652 waitSemaphoresForPresent.clear();
5653 if (sp->presentWaitSemaphoreCount)
5654 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5684 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5687 size_t dataSize = 0;
5688 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5689 if (err != VK_SUCCESS) {
5690 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5691 return QByteArray();
5694 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5695 data.resize(dataOffset + dataSize);
5696 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5697 if (err != VK_SUCCESS) {
5698 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5699 return QByteArray();
5703 header.rhiId = pipelineCacheRhiId();
5704 header.arch = quint32(
sizeof(
void*));
5705 header.driverVersion = physDevProperties.driverVersion;
5706 header.vendorId = physDevProperties.vendorID;
5707 header.deviceId = physDevProperties.deviceID;
5708 header.dataSize = quint32(dataSize);
5709 header.uuidSize = VK_UUID_SIZE;
5710 header.reserved = 0;
5711 memcpy(data.data(), &header, headerSize);
5712 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5723 if (data.size() < qsizetype(headerSize)) {
5724 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5728 memcpy(&header, data.constData(), headerSize);
5730 const quint32 rhiId = pipelineCacheRhiId();
5731 if (header.rhiId != rhiId) {
5732 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5733 rhiId, header.rhiId);
5736 const quint32 arch = quint32(
sizeof(
void*));
5737 if (header.arch != arch) {
5738 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5742 if (header.driverVersion != physDevProperties.driverVersion) {
5743 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5744 physDevProperties.driverVersion, header.driverVersion);
5747 if (header.vendorId != physDevProperties.vendorID) {
5748 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5749 physDevProperties.vendorID, header.vendorId);
5752 if (header.deviceId != physDevProperties.deviceID) {
5753 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5754 physDevProperties.deviceID, header.deviceId);
5757 if (header.uuidSize != VK_UUID_SIZE) {
5758 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5759 quint32(VK_UUID_SIZE), header.uuidSize);
5763 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5764 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5767 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5768 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5772 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5773 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5774 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5778 if (pipelineCache) {
5779 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5780 pipelineCache = VK_NULL_HANDLE;
5783 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5784 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5785 int(header.dataSize));
5787 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5791QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5792 int sampleCount, QRhiRenderBuffer::Flags flags,
5793 QRhiTexture::Format backingFormatHint)
5795 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5799 const QSize &pixelSize,
int depth,
int arraySize,
5800 int sampleCount, QRhiTexture::Flags flags)
5802 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5806 QRhiSampler::Filter mipmapMode,
5807 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5809 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5814 return new QVkShadingRateMap(
this);
5818 QRhiTextureRenderTarget::Flags flags)
5825 return new QVkGraphicsPipeline(
this);
5830 return new QVkComputePipeline(
this);
5835 return new QVkShaderResourceBindings(
this);
5841 Q_ASSERT(psD->pipeline);
5845 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5847 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5851 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5852 cmd.args.bindPipeline.pipeline = psD->pipeline;
5855 cbD->currentGraphicsPipeline = ps;
5856 cbD->currentComputePipeline =
nullptr;
5857 cbD->currentPipelineGeneration = psD->generation;
5863 psD->lastActiveFrameSlot = currentFrameSlot;
5867 int dynamicOffsetCount,
5868 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5878 srb = gfxPsD->m_shaderResourceBindings;
5880 srb = compPsD->m_shaderResourceBindings;
5884 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5885 bool rewriteDescSet =
false;
5886 bool addWriteBarrier =
false;
5887 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5888 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5892 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5893 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5896 case QRhiShaderResourceBinding::UniformBuffer:
5899 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5900 sanityCheckResourceOwnership(bufD);
5902 if (bufD->m_type == QRhiBuffer::Dynamic)
5905 bufD->lastActiveFrameSlot = currentFrameSlot;
5906 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5908 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5914 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5915 rewriteDescSet =
true;
5916 bd.ubuf.id = bufD->m_id;
5917 bd.ubuf.generation = bufD->generation;
5921 case QRhiShaderResourceBinding::SampledTexture:
5922 case QRhiShaderResourceBinding::Texture:
5923 case QRhiShaderResourceBinding::Sampler:
5925 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5926 if (bd.stex.count != data->count) {
5927 bd.stex.count = data->count;
5928 rewriteDescSet =
true;
5930 for (
int elem = 0; elem < data->count; ++elem) {
5936 Q_ASSERT(texD || samplerD);
5937 sanityCheckResourceOwnership(texD);
5938 sanityCheckResourceOwnership(samplerD);
5940 texD->lastActiveFrameSlot = currentFrameSlot;
5946 samplerD->lastActiveFrameSlot = currentFrameSlot;
5947 const quint64 texId = texD ? texD->m_id : 0;
5948 const uint texGen = texD ? texD->generation : 0;
5949 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
5950 const uint samplerGen = samplerD ? samplerD->generation : 0;
5951 if (texGen != bd.stex.d[elem].texGeneration
5952 || texId != bd.stex.d[elem].texId
5953 || samplerGen != bd.stex.d[elem].samplerGeneration
5954 || samplerId != bd.stex.d[elem].samplerId)
5956 rewriteDescSet =
true;
5957 bd.stex.d[elem].texId = texId;
5958 bd.stex.d[elem].texGeneration = texGen;
5959 bd.stex.d[elem].samplerId = samplerId;
5960 bd.stex.d[elem].samplerGeneration = samplerGen;
5965 case QRhiShaderResourceBinding::ImageLoad:
5966 case QRhiShaderResourceBinding::ImageStore:
5967 case QRhiShaderResourceBinding::ImageLoadStore:
5970 sanityCheckResourceOwnership(texD);
5971 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
5972 texD->lastActiveFrameSlot = currentFrameSlot;
5974 if (b->type == QRhiShaderResourceBinding::ImageLoad)
5976 else if (b->type == QRhiShaderResourceBinding::ImageStore)
5981 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
5982 const auto prevAccess = passResTracker.textures().find(texD);
5983 if (prevAccess != passResTracker.textures().end()) {
5987 addWriteBarrier =
true;
5988 writeBarrierDstStageMask |= toVkPipelineStage(stage);
5989 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
5997 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
5998 rewriteDescSet =
true;
5999 bd.simage.id = texD->m_id;
6000 bd.simage.generation = texD->generation;
6004 case QRhiShaderResourceBinding::BufferLoad:
6005 case QRhiShaderResourceBinding::BufferStore:
6006 case QRhiShaderResourceBinding::BufferLoadStore:
6009 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6010 sanityCheckResourceOwnership(bufD);
6012 if (bufD->m_type == QRhiBuffer::Dynamic)
6015 bufD->lastActiveFrameSlot = currentFrameSlot;
6017 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6019 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6024 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6025 const auto prevAccess = passResTracker.buffers().find(bufD);
6026 if (prevAccess != passResTracker.buffers().end()) {
6030 addWriteBarrier =
true;
6031 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6032 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6035 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6039 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6040 rewriteDescSet =
true;
6041 bd.sbuf.id = bufD->m_id;
6042 bd.sbuf.generation = bufD->generation;
6052 if (addWriteBarrier) {
6054 VkMemoryBarrier barrier;
6055 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6056 barrier.pNext =
nullptr;
6057 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6058 barrier.srcAccessMask = barrier.dstAccessMask;
6059 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6066 cmd.args.memoryBarrier.dependencyFlags = 0;
6067 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6068 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6069 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6070 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6076 updateShaderResourceBindings(srb);
6080 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot || srbD->hasDynamicOffset;
6082 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6084 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6085 QVarLengthArray<uint32_t, 4> dynOfs;
6091 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
6092 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
6093 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
6094 uint32_t offset = 0;
6095 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6096 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6097 if (bindingOffsetPair.first == b->binding) {
6098 offset = bindingOffsetPair.second;
6102 dynOfs.append(offset);
6108 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6109 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6110 gfxPsD ? gfxPsD->layout : compPsD->layout,
6111 0, 1, &srbD->descSets[currentFrameSlot],
6112 uint32_t(dynOfs.size()),
6113 dynOfs.size() ? dynOfs.constData() :
nullptr);
6117 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6118 : VK_PIPELINE_BIND_POINT_COMPUTE;
6119 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6120 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6121 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6122 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6123 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6127 cbD->currentGraphicsSrb = srb;
6128 cbD->currentComputeSrb =
nullptr;
6130 cbD->currentGraphicsSrb =
nullptr;
6131 cbD->currentComputeSrb = srb;
6133 cbD->currentSrbGeneration = srbD->generation;
6134 cbD->currentDescSetSlot = currentFrameSlot;
6137 srbD->lastActiveFrameSlot = currentFrameSlot;
6141 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6142 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6148 bool needsBindVBuf =
false;
6149 for (
int i = 0; i < bindingCount; ++i) {
6150 const int inputSlot = startBinding + i;
6152 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6153 bufD->lastActiveFrameSlot = currentFrameSlot;
6154 if (bufD->m_type == QRhiBuffer::Dynamic)
6157 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6158 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6159 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6161 needsBindVBuf =
true;
6162 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6163 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6167 if (needsBindVBuf) {
6168 QVarLengthArray<VkBuffer, 4> bufs;
6169 QVarLengthArray<VkDeviceSize, 4> ofs;
6170 for (
int i = 0; i < bindingCount; ++i) {
6172 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6173 bufs.append(bufD->buffers[slot]);
6174 ofs.append(bindings[i].second);
6181 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6182 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6186 cmd.args.bindVertexBuffer.startBinding = startBinding;
6187 cmd.args.bindVertexBuffer.count = bufs.size();
6188 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6189 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6190 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6191 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6197 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6198 ibufD->lastActiveFrameSlot = currentFrameSlot;
6199 if (ibufD->m_type == QRhiBuffer::Dynamic)
6202 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6203 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6204 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6205 : VK_INDEX_TYPE_UINT32;
6207 if (cbD->currentIndexBuffer != vkindexbuf
6208 || cbD->currentIndexOffset != indexOffset
6209 || cbD->currentIndexFormat != type)
6211 cbD->currentIndexBuffer = vkindexbuf;
6212 cbD->currentIndexOffset = indexOffset;
6213 cbD->currentIndexFormat = type;
6216 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6220 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6221 cmd.args.bindIndexBuffer.ofs = indexOffset;
6222 cmd.args.bindIndexBuffer.type = type;
6236 const QSize outputSize = cbD->currentTarget->pixelSize();
6237 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6238 float x = 0, y = 0, w = 0, h = 0;
6240 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6243 w = outputSize.width();
6244 h = outputSize.height();
6247 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6251 VkRect2D *s = &cmd.args.setScissor.scissor;
6252 s->offset.x = int32_t(x);
6253 s->offset.y = int32_t(y);
6254 s->extent.width = uint32_t(w);
6255 s->extent.height = uint32_t(h);
6258 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6259 cbD->commands.unget();
6269 const QSize outputSize = cbD->currentTarget->pixelSize();
6273 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6277 VkViewport *vp = &cmd.args.setViewport.viewport;
6282 vp->minDepth = viewport.minDepth();
6283 vp->maxDepth = viewport.maxDepth();
6286 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6287 cbD->commands.unget();
6292 cbD->currentViewport = viewport;
6293 if (cbD->currentGraphicsPipeline
6294 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6304 Q_ASSERT(!cbD->currentGraphicsPipeline
6306 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6307 const QSize outputSize = cbD->currentTarget->pixelSize();
6311 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6315 VkRect2D *s = &cmd.args.setScissor.scissor;
6318 s->extent.width = uint32_t(w);
6319 s->extent.height = uint32_t(h);
6322 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6323 cbD->commands.unget();
6337 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6338 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6342 cmd.args.setBlendConstants.c[0] = c.redF();
6343 cmd.args.setBlendConstants.c[1] = c.greenF();
6344 cmd.args.setBlendConstants.c[2] = c.blueF();
6345 cmd.args.setBlendConstants.c[3] = c.alphaF();
6355 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6359 cmd.args.setStencilRef.ref = refValue;
6365#ifdef VK_KHR_fragment_shading_rate
6366 if (!vkCmdSetFragmentShadingRateKHR)
6369 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6370 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6371 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6373 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6374 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6375 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6377 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6378 if (cbD->passUsesSecondaryCb) {
6379 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6381 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6382 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6383 cmd.args.setShadingRate.w = size.width;
6384 cmd.args.setShadingRate.h = size.height;
6386 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6387 cbD->hasShadingRateSet =
true;
6390 Q_UNUSED(coarsePixelSize);
6395 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6401 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6405 cmd.args.draw.vertexCount = vertexCount;
6406 cmd.args.draw.instanceCount = instanceCount;
6407 cmd.args.draw.firstVertex = firstVertex;
6408 cmd.args.draw.firstInstance = firstInstance;
6413 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6419 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6420 firstIndex, vertexOffset, firstInstance);
6424 cmd.args.drawIndexed.indexCount = indexCount;
6425 cmd.args.drawIndexed.instanceCount = instanceCount;
6426 cmd.args.drawIndexed.firstIndex = firstIndex;
6427 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6428 cmd.args.drawIndexed.firstInstance = firstInstance;
6433 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6440 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6441 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6443 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6447 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6450 if (caps.drawIndirectMulti) {
6451 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6452 indirectBufVk, indirectBufferOffset,
6455 VkDeviceSize offset = indirectBufferOffset;
6456 for (quint32 i = 0; i < drawCount; ++i) {
6457 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6458 indirectBufVk, offset,
6464 if (caps.drawIndirectMulti) {
6467 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6468 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6469 cmd.args.drawIndirect.drawCount = drawCount;
6470 cmd.args.drawIndirect.stride = stride;
6472 VkDeviceSize offset = indirectBufferOffset;
6473 for (quint32 i = 0; i < drawCount; ++i) {
6476 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6477 cmd.args.drawIndirect.indirectBufferOffset = offset;
6478 cmd.args.drawIndirect.drawCount = 1;
6479 cmd.args.drawIndirect.stride = stride;
6487 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6494 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6495 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6497 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6501 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6504 if (caps.drawIndirectMulti) {
6505 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6506 indirectBufVk, indirectBufferOffset,
6509 VkDeviceSize offset = indirectBufferOffset;
6510 for (quint32 i = 0; i < drawCount; ++i) {
6511 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6512 indirectBufVk, offset,
6518 if (caps.drawIndirectMulti) {
6521 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6522 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
6523 cmd.args.drawIndexedIndirect.drawCount = drawCount;
6524 cmd.args.drawIndexedIndirect.stride = stride;
6526 VkDeviceSize offset = indirectBufferOffset;
6527 for (quint32 i = 0; i < drawCount; ++i) {
6530 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6531 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
6532 cmd.args.drawIndexedIndirect.drawCount = 1;
6533 cmd.args.drawIndexedIndirect.stride = stride;
6542#ifdef VK_EXT_debug_utils
6543 if (!debugMarkers || !caps.debugUtils)
6546 VkDebugUtilsLabelEXT label = {};
6547 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6549 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6550 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6551 label.pLabelName = name.constData();
6552 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6554 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6555 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6556 cmd.args.debugMarkerBegin.label = label;
6557 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6558 cbD->pools.debugMarkerData.append(name);
6568#ifdef VK_EXT_debug_utils
6569 if (!debugMarkers || !caps.debugUtils)
6572 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6573 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6574 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6576 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6577 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6586#ifdef VK_EXT_debug_utils
6587 if (!debugMarkers || !caps.debugUtils)
6590 VkDebugUtilsLabelEXT label = {};
6591 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6593 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6594 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6595 label.pLabelName = msg.constData();
6596 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6598 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6599 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6600 cmd.args.debugMarkerInsert.label = label;
6601 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6602 cbD->pools.debugMarkerData.append(msg);
6612 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6617 Q_ASSERT(cbD->currentTarget);
6620 switch (cbD->currentTarget->resourceType()) {
6621 case QRhiResource::SwapChainRenderTarget:
6624 case QRhiResource::TextureRenderTarget:
6656 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6657 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6661 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6662 cbD->activeSecondaryCbStack.removeLast();
6663 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6665 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6667 cbD->activeSecondaryCbStack.append(extCb);
6679 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6680 cbD->activeSecondaryCbStack.removeLast();
6681 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6682 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6696 if (!debugMarkers || name.isEmpty())
6699 QByteArray decoratedName = name;
6701 decoratedName +=
'/';
6702 decoratedName += QByteArray::number(slot);
6704 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6709#ifdef VK_EXT_debug_utils
6710 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6713 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6714 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6715 nameInfo.objectType = type;
6716 nameInfo.objectHandle = object;
6717 QByteArray decoratedName = name;
6719 decoratedName +=
'/';
6720 decoratedName += QByteArray::number(slot);
6722 nameInfo.pObjectName = decoratedName.constData();
6723 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6735 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6736 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6737 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6738 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6739 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6740 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6741 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6742 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6743 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
6744 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
6745 return VkBufferUsageFlagBits(u);
6751 case QRhiSampler::Nearest:
6752 return VK_FILTER_NEAREST;
6753 case QRhiSampler::Linear:
6754 return VK_FILTER_LINEAR;
6756 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6763 case QRhiSampler::None:
6764 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6765 case QRhiSampler::Nearest:
6766 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6767 case QRhiSampler::Linear:
6768 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6770 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6777 case QRhiSampler::Repeat:
6778 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6779 case QRhiSampler::ClampToEdge:
6780 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6781 case QRhiSampler::Mirror:
6782 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6784 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6791 case QRhiShaderStage::Vertex:
6792 return VK_SHADER_STAGE_VERTEX_BIT;
6793 case QRhiShaderStage::TessellationControl:
6794 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6795 case QRhiShaderStage::TessellationEvaluation:
6796 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6797 case QRhiShaderStage::Fragment:
6798 return VK_SHADER_STAGE_FRAGMENT_BIT;
6799 case QRhiShaderStage::Compute:
6800 return VK_SHADER_STAGE_COMPUTE_BIT;
6801 case QRhiShaderStage::Geometry:
6802 return VK_SHADER_STAGE_GEOMETRY_BIT;
6804 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6811 case QRhiVertexInputAttribute::Float4:
6812 return VK_FORMAT_R32G32B32A32_SFLOAT;
6813 case QRhiVertexInputAttribute::Float3:
6814 return VK_FORMAT_R32G32B32_SFLOAT;
6815 case QRhiVertexInputAttribute::Float2:
6816 return VK_FORMAT_R32G32_SFLOAT;
6817 case QRhiVertexInputAttribute::Float:
6818 return VK_FORMAT_R32_SFLOAT;
6819 case QRhiVertexInputAttribute::UNormByte4:
6820 return VK_FORMAT_R8G8B8A8_UNORM;
6821 case QRhiVertexInputAttribute::UNormByte2:
6822 return VK_FORMAT_R8G8_UNORM;
6823 case QRhiVertexInputAttribute::UNormByte:
6824 return VK_FORMAT_R8_UNORM;
6825 case QRhiVertexInputAttribute::UInt4:
6826 return VK_FORMAT_R32G32B32A32_UINT;
6827 case QRhiVertexInputAttribute::UInt3:
6828 return VK_FORMAT_R32G32B32_UINT;
6829 case QRhiVertexInputAttribute::UInt2:
6830 return VK_FORMAT_R32G32_UINT;
6831 case QRhiVertexInputAttribute::UInt:
6832 return VK_FORMAT_R32_UINT;
6833 case QRhiVertexInputAttribute::SInt4:
6834 return VK_FORMAT_R32G32B32A32_SINT;
6835 case QRhiVertexInputAttribute::SInt3:
6836 return VK_FORMAT_R32G32B32_SINT;
6837 case QRhiVertexInputAttribute::SInt2:
6838 return VK_FORMAT_R32G32_SINT;
6839 case QRhiVertexInputAttribute::SInt:
6840 return VK_FORMAT_R32_SINT;
6841 case QRhiVertexInputAttribute::Half4:
6842 return VK_FORMAT_R16G16B16A16_SFLOAT;
6843 case QRhiVertexInputAttribute::Half3:
6844 return VK_FORMAT_R16G16B16_SFLOAT;
6845 case QRhiVertexInputAttribute::Half2:
6846 return VK_FORMAT_R16G16_SFLOAT;
6847 case QRhiVertexInputAttribute::Half:
6848 return VK_FORMAT_R16_SFLOAT;
6849 case QRhiVertexInputAttribute::UShort4:
6850 return VK_FORMAT_R16G16B16A16_UINT;
6851 case QRhiVertexInputAttribute::UShort3:
6852 return VK_FORMAT_R16G16B16_UINT;
6853 case QRhiVertexInputAttribute::UShort2:
6854 return VK_FORMAT_R16G16_UINT;
6855 case QRhiVertexInputAttribute::UShort:
6856 return VK_FORMAT_R16_UINT;
6857 case QRhiVertexInputAttribute::SShort4:
6858 return VK_FORMAT_R16G16B16A16_SINT;
6859 case QRhiVertexInputAttribute::SShort3:
6860 return VK_FORMAT_R16G16B16_SINT;
6861 case QRhiVertexInputAttribute::SShort2:
6862 return VK_FORMAT_R16G16_SINT;
6863 case QRhiVertexInputAttribute::SShort:
6864 return VK_FORMAT_R16_SINT;
6866 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6873 case QRhiGraphicsPipeline::Triangles:
6874 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6875 case QRhiGraphicsPipeline::TriangleStrip:
6876 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6877 case QRhiGraphicsPipeline::TriangleFan:
6878 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6879 case QRhiGraphicsPipeline::Lines:
6880 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6881 case QRhiGraphicsPipeline::LineStrip:
6882 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6883 case QRhiGraphicsPipeline::Points:
6884 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6885 case QRhiGraphicsPipeline::Patches:
6886 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6888 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6895 case QRhiGraphicsPipeline::None:
6896 return VK_CULL_MODE_NONE;
6897 case QRhiGraphicsPipeline::Front:
6898 return VK_CULL_MODE_FRONT_BIT;
6899 case QRhiGraphicsPipeline::Back:
6900 return VK_CULL_MODE_BACK_BIT;
6902 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6909 case QRhiGraphicsPipeline::CCW:
6910 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6911 case QRhiGraphicsPipeline::CW:
6912 return VK_FRONT_FACE_CLOCKWISE;
6914 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6921 if (c.testFlag(QRhiGraphicsPipeline::R))
6922 f |= VK_COLOR_COMPONENT_R_BIT;
6923 if (c.testFlag(QRhiGraphicsPipeline::G))
6924 f |= VK_COLOR_COMPONENT_G_BIT;
6925 if (c.testFlag(QRhiGraphicsPipeline::B))
6926 f |= VK_COLOR_COMPONENT_B_BIT;
6927 if (c.testFlag(QRhiGraphicsPipeline::A))
6928 f |= VK_COLOR_COMPONENT_A_BIT;
6929 return VkColorComponentFlags(f);
6935 case QRhiGraphicsPipeline::Zero:
6936 return VK_BLEND_FACTOR_ZERO;
6937 case QRhiGraphicsPipeline::One:
6938 return VK_BLEND_FACTOR_ONE;
6939 case QRhiGraphicsPipeline::SrcColor:
6940 return VK_BLEND_FACTOR_SRC_COLOR;
6941 case QRhiGraphicsPipeline::OneMinusSrcColor:
6942 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6943 case QRhiGraphicsPipeline::DstColor:
6944 return VK_BLEND_FACTOR_DST_COLOR;
6945 case QRhiGraphicsPipeline::OneMinusDstColor:
6946 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6947 case QRhiGraphicsPipeline::SrcAlpha:
6948 return VK_BLEND_FACTOR_SRC_ALPHA;
6949 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6950 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6951 case QRhiGraphicsPipeline::DstAlpha:
6952 return VK_BLEND_FACTOR_DST_ALPHA;
6953 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6954 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
6955 case QRhiGraphicsPipeline::ConstantColor:
6956 return VK_BLEND_FACTOR_CONSTANT_COLOR;
6957 case QRhiGraphicsPipeline::OneMinusConstantColor:
6958 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
6959 case QRhiGraphicsPipeline::ConstantAlpha:
6960 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
6961 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6962 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
6963 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6964 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
6965 case QRhiGraphicsPipeline::Src1Color:
6966 return VK_BLEND_FACTOR_SRC1_COLOR;
6967 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6968 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
6969 case QRhiGraphicsPipeline::Src1Alpha:
6970 return VK_BLEND_FACTOR_SRC1_ALPHA;
6971 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6972 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
6974 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
6981 case QRhiGraphicsPipeline::Add:
6982 return VK_BLEND_OP_ADD;
6983 case QRhiGraphicsPipeline::Subtract:
6984 return VK_BLEND_OP_SUBTRACT;
6985 case QRhiGraphicsPipeline::ReverseSubtract:
6986 return VK_BLEND_OP_REVERSE_SUBTRACT;
6987 case QRhiGraphicsPipeline::Min:
6988 return VK_BLEND_OP_MIN;
6989 case QRhiGraphicsPipeline::Max:
6990 return VK_BLEND_OP_MAX;
6992 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
6999 case QRhiGraphicsPipeline::Never:
7000 return VK_COMPARE_OP_NEVER;
7001 case QRhiGraphicsPipeline::Less:
7002 return VK_COMPARE_OP_LESS;
7003 case QRhiGraphicsPipeline::Equal:
7004 return VK_COMPARE_OP_EQUAL;
7005 case QRhiGraphicsPipeline::LessOrEqual:
7006 return VK_COMPARE_OP_LESS_OR_EQUAL;
7007 case QRhiGraphicsPipeline::Greater:
7008 return VK_COMPARE_OP_GREATER;
7009 case QRhiGraphicsPipeline::NotEqual:
7010 return VK_COMPARE_OP_NOT_EQUAL;
7011 case QRhiGraphicsPipeline::GreaterOrEqual:
7012 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7013 case QRhiGraphicsPipeline::Always:
7014 return VK_COMPARE_OP_ALWAYS;
7016 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7023 case QRhiGraphicsPipeline::StencilZero:
7024 return VK_STENCIL_OP_ZERO;
7025 case QRhiGraphicsPipeline::Keep:
7026 return VK_STENCIL_OP_KEEP;
7027 case QRhiGraphicsPipeline::Replace:
7028 return VK_STENCIL_OP_REPLACE;
7029 case QRhiGraphicsPipeline::IncrementAndClamp:
7030 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7031 case QRhiGraphicsPipeline::DecrementAndClamp:
7032 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7033 case QRhiGraphicsPipeline::Invert:
7034 return VK_STENCIL_OP_INVERT;
7035 case QRhiGraphicsPipeline::IncrementAndWrap:
7036 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7037 case QRhiGraphicsPipeline::DecrementAndWrap:
7038 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7040 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7047 case QRhiGraphicsPipeline::Fill:
7048 return VK_POLYGON_MODE_FILL;
7049 case QRhiGraphicsPipeline::Line:
7050 return VK_POLYGON_MODE_LINE;
7052 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7058 dst->failOp = toVkStencilOp(src.failOp);
7059 dst->passOp = toVkStencilOp(src.passOp);
7060 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7061 dst->compareOp = toVkCompareOp(src.compareOp);
7067 case QRhiShaderResourceBinding::UniformBuffer:
7068 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7069 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7071 case QRhiShaderResourceBinding::SampledTexture:
7072 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7074 case QRhiShaderResourceBinding::Texture:
7075 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7077 case QRhiShaderResourceBinding::Sampler:
7078 return VK_DESCRIPTOR_TYPE_SAMPLER;
7080 case QRhiShaderResourceBinding::ImageLoad:
7081 case QRhiShaderResourceBinding::ImageStore:
7082 case QRhiShaderResourceBinding::ImageLoadStore:
7083 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7085 case QRhiShaderResourceBinding::BufferLoad:
7086 case QRhiShaderResourceBinding::BufferStore:
7087 case QRhiShaderResourceBinding::BufferLoadStore:
7088 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7091 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7098 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7099 s |= VK_SHADER_STAGE_VERTEX_BIT;
7100 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7101 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7102 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7103 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7104 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7105 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7106 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7107 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7108 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7109 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7110 return VkShaderStageFlags(s);
7116 case QRhiSampler::Never:
7117 return VK_COMPARE_OP_NEVER;
7118 case QRhiSampler::Less:
7119 return VK_COMPARE_OP_LESS;
7120 case QRhiSampler::Equal:
7121 return VK_COMPARE_OP_EQUAL;
7122 case QRhiSampler::LessOrEqual:
7123 return VK_COMPARE_OP_LESS_OR_EQUAL;
7124 case QRhiSampler::Greater:
7125 return VK_COMPARE_OP_GREATER;
7126 case QRhiSampler::NotEqual:
7127 return VK_COMPARE_OP_NOT_EQUAL;
7128 case QRhiSampler::GreaterOrEqual:
7129 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7130 case QRhiSampler::Always:
7131 return VK_COMPARE_OP_ALWAYS;
7133 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7141 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7161 e.buffer.buffers[i] = buffers[i];
7163 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7166 buffers[i] = VK_NULL_HANDLE;
7168 stagingBuffers[i] = VK_NULL_HANDLE;
7170 pendingDynamicUpdates[i].clear();
7178 rhiD->releaseQueue.append(e);
7179 rhiD->unregisterResource(
this);
7188 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7189 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7193 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7195 VkBufferCreateInfo bufferInfo = {};
7196 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7197 bufferInfo.size = nonZeroSize;
7198 bufferInfo.usage = toVkBufferUsage(m_usage);
7200 VmaAllocationCreateInfo allocInfo = {};
7202 if (m_type == Dynamic) {
7207 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7210 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7212 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7213 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7217 VkResult err = VK_SUCCESS;
7219 buffers[i] = VK_NULL_HANDLE;
7221 usageState[i].access = usageState[i].stage = 0;
7222 if (i == 0 || m_type == Dynamic) {
7223 VmaAllocation allocation;
7224 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7225 if (err != VK_SUCCESS)
7228 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7229 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7230 m_type == Dynamic ? i : -1);
7234 if (err != VK_SUCCESS) {
7235 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7236 rhiD->printExtraErrorInfo(err);
7242 rhiD->registerResource(
this);
7248 if (m_type == Dynamic) {
7254 b.objects[i] = &buffers[i];
7259 return { { &buffers[0] }, 1 };
7269 Q_ASSERT(m_type == Dynamic);
7271 Q_ASSERT(rhiD->inFrame);
7272 const int slot = rhiD->currentFrameSlot;
7274 VmaAllocation a = toVmaAllocation(allocations[slot]);
7275 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7276 if (err != VK_SUCCESS) {
7277 qWarning(
"Failed to map buffer: %d", err);
7280 return static_cast<
char *>(p);
7286 const int slot = rhiD->currentFrameSlot;
7287 VmaAllocation a = toVmaAllocation(allocations[slot]);
7288 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7289 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7293 int sampleCount, Flags flags,
7294 QRhiTexture::Format backingFormatHint)
7307 if (!memory && !backingTexture)
7314 e.renderBuffer.memory = memory;
7315 e.renderBuffer.image = image;
7316 e.renderBuffer.imageView = imageView;
7318 memory = VK_NULL_HANDLE;
7319 image = VK_NULL_HANDLE;
7320 imageView = VK_NULL_HANDLE;
7330 rhiD->releaseQueue.append(e);
7331 rhiD->unregisterResource(
this);
7337 if (memory || backingTexture)
7340 if (m_pixelSize.isEmpty())
7344 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7347 case QRhiRenderBuffer::Color:
7355 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7363 vkformat = backingTexture->vkformat;
7366 case QRhiRenderBuffer::DepthStencil:
7367 vkformat = rhiD->optimalDepthStencilFormat();
7368 if (!rhiD->createTransientImage(vkformat,
7370 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7371 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7380 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7389 rhiD->registerResource(
this);
7395 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7396 return m_backingFormatHint;
7398 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7402 int arraySize,
int sampleCount, Flags flags)
7406 stagingBuffers[i] = VK_NULL_HANDLE;
7409 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7410 perLevelImageViews[i] = VK_NULL_HANDLE;
7427 e.texture.image = owns ? image : VK_NULL_HANDLE;
7428 e.texture.imageView = imageView;
7432 e.texture.stagingBuffers[i] = stagingBuffers[i];
7435 stagingBuffers[i] = VK_NULL_HANDLE;
7439 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7440 e.texture.extraImageViews[i] = perLevelImageViews[i];
7441 perLevelImageViews[i] = VK_NULL_HANDLE;
7444 image = VK_NULL_HANDLE;
7445 imageView = VK_NULL_HANDLE;
7450 rhiD->releaseQueue.append(e);
7451 rhiD->unregisterResource(
this);
7461 vkformat = toVkTextureFormat(m_format, m_flags);
7462 if (m_writeViewFormat.format != UnknownFormat)
7463 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7465 viewFormat = vkformat;
7466 if (m_readViewFormat.format != UnknownFormat)
7467 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7469 viewFormatForSampling = vkformat;
7471 VkFormatProperties props;
7472 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7473 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7474 if (!canSampleOptimal) {
7475 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7479 const bool isCube = m_flags.testFlag(CubeMap);
7480 const bool isArray = m_flags.testFlag(TextureArray);
7481 const bool is3D = m_flags.testFlag(ThreeDimensional);
7482 const bool is1D = m_flags.testFlag(OneDimensional);
7483 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7485 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7486 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7488 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7489 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7490 if (mipLevelCount > maxLevels) {
7491 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7492 mipLevelCount = maxLevels;
7494 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7495 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7497 qWarning(
"Cubemap texture cannot be multisample");
7501 qWarning(
"3D texture cannot be multisample");
7505 qWarning(
"Multisample texture cannot have mipmaps");
7509 if (isCube && is3D) {
7510 qWarning(
"Texture cannot be both cube and 3D");
7513 if (isArray && is3D) {
7514 qWarning(
"Texture cannot be both array and 3D");
7517 if (isCube && is1D) {
7518 qWarning(
"Texture cannot be both cube and 1D");
7522 qWarning(
"Texture cannot be both 1D and 3D");
7525 if (m_depth > 1 && !is3D) {
7526 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7529 if (m_arraySize > 0 && !isArray) {
7530 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7533 if (m_arraySize < 1 && isArray) {
7534 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7538 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7539 usageState.access = 0;
7540 usageState.stage = 0;
7543 *adjustedSize = size;
7552 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7553 const bool isCube = m_flags.testFlag(CubeMap);
7554 const bool isArray = m_flags.testFlag(TextureArray);
7555 const bool is3D = m_flags.testFlag(ThreeDimensional);
7556 const bool is1D = m_flags.testFlag(OneDimensional);
7558 VkImageViewCreateInfo viewInfo = {};
7559 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7560 viewInfo.image = image;
7561 viewInfo.viewType = isCube
7562 ? VK_IMAGE_VIEW_TYPE_CUBE
7563 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7564 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7565 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7566 viewInfo.format = viewFormatForSampling;
7567 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7568 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7569 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7570 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7571 viewInfo.subresourceRange.aspectMask = aspectMask;
7574 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7575 viewInfo.subresourceRange.levelCount = mipLevelCount;
7576 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7577 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7578 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7580 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7583 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7584 if (err != VK_SUCCESS) {
7585 qWarning(
"Failed to create image view: %d", err);
7598 if (!prepareCreate(&size))
7602 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7603 const bool isDepth = isDepthTextureFormat(m_format);
7604 const bool isCube = m_flags.testFlag(CubeMap);
7605 const bool isArray = m_flags.testFlag(TextureArray);
7606 const bool is3D = m_flags.testFlag(ThreeDimensional);
7607 const bool is1D = m_flags.testFlag(OneDimensional);
7609 VkImageCreateInfo imageInfo = {};
7610 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7611 imageInfo.flags = 0;
7613 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7615 if (is3D && isRenderTarget) {
7621 if (!rhiD->caps.texture3DSliceAs2D)
7622 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7623#ifdef VK_VERSION_1_1
7624 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7626 imageInfo.flags |= 0x00000020;
7630 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7631 imageInfo.format = vkformat;
7632 imageInfo.extent.width = uint32_t(size.width());
7633 imageInfo.extent.height = uint32_t(size.height());
7634 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7635 imageInfo.mipLevels = mipLevelCount;
7636 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7637 imageInfo.samples = samples;
7638 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7639 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7641 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7642 if (isRenderTarget) {
7644 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7646 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7648 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7649 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7650 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7651 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7652 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7653 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7654#ifdef VK_KHR_fragment_shading_rate
7655 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7656 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7659 VmaAllocationCreateInfo allocInfo = {};
7660 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7662 VmaAllocation allocation;
7663 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7664 if (err != VK_SUCCESS) {
7665 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7666 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7667 int(imageInfo.format),
7668 imageInfo.mipLevels,
7669 imageInfo.arrayLayers,
7670 int(imageInfo.samples),
7672 rhiD->printExtraErrorInfo(err);
7676 rhiD->setAllocationName(allocation, m_objectName);
7681 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7684 rhiD->registerResource(
this);
7690 VkImage img = VkImage(src.object);
7694 if (!prepareCreate())
7702 usageState.layout = VkImageLayout(src.layout);
7706 rhiD->registerResource(
this);
7712 return {quint64(image), usageState.layout};
7717 usageState.layout = VkImageLayout(layout);
7722 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7723 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7724 return perLevelImageViews[level];
7726 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7727 const bool isCube = m_flags.testFlag(CubeMap);
7728 const bool isArray = m_flags.testFlag(TextureArray);
7729 const bool is3D = m_flags.testFlag(ThreeDimensional);
7730 const bool is1D = m_flags.testFlag(OneDimensional);
7732 VkImageViewCreateInfo viewInfo = {};
7733 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7734 viewInfo.image = image;
7735 viewInfo.viewType = isCube
7736 ? VK_IMAGE_VIEW_TYPE_CUBE
7737 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7738 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7739 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7740 viewInfo.format = viewFormat;
7741 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7742 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7743 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7744 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7745 viewInfo.subresourceRange.aspectMask = aspectMask;
7746 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7747 viewInfo.subresourceRange.levelCount = 1;
7748 viewInfo.subresourceRange.baseArrayLayer = 0;
7749 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7751 VkImageView v = VK_NULL_HANDLE;
7753 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7754 if (err != VK_SUCCESS) {
7755 qWarning(
"Failed to create image view: %d", err);
7756 return VK_NULL_HANDLE;
7759 perLevelImageViews[level] = v;
7764 AddressMode u, AddressMode v, AddressMode w)
7783 e.sampler.sampler = sampler;
7784 sampler = VK_NULL_HANDLE;
7788 rhiD->releaseQueue.append(e);
7789 rhiD->unregisterResource(
this);
7798 VkSamplerCreateInfo samplerInfo = {};
7799 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7800 samplerInfo.magFilter = toVkFilter(m_magFilter);
7801 samplerInfo.minFilter = toVkFilter(m_minFilter);
7802 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7803 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7804 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7805 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7806 samplerInfo.maxAnisotropy = 1.0f;
7807 samplerInfo.compareEnable = m_compareOp != Never;
7808 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7809 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7812 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7813 if (err != VK_SUCCESS) {
7814 qWarning(
"Failed to create sampler: %d", err);
7820 rhiD->registerResource(
this);
7827 serializedFormatData.reserve(64);
7841 rp = VK_NULL_HANDLE;
7849 e.renderPass.rp = rp;
7851 rp = VK_NULL_HANDLE;
7855 rhiD->releaseQueue.append(e);
7856 rhiD->unregisterResource(
this);
7862 return a.format == b.format
7863 && a.samples == b.samples
7864 && a.loadOp == b.loadOp
7865 && a.storeOp == b.storeOp
7866 && a.stencilLoadOp == b.stencilLoadOp
7867 && a.stencilStoreOp == b.stencilStoreOp
7868 && a.initialLayout == b.initialLayout
7869 && a.finalLayout == b.finalLayout;
7882 if (attDescs.size() != o->attDescs.size())
7884 if (colorRefs.size() != o->colorRefs.size())
7886 if (resolveRefs.size() != o->resolveRefs.size())
7892 if (multiViewCount != o->multiViewCount)
7897 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7898 const uint32_t attIdx = colorRefs[i].attachment;
7899 if (attIdx != o->colorRefs[i].attachment)
7901 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7906 const uint32_t attIdx = dsRef.attachment;
7907 if (attIdx != o->dsRef.attachment)
7909 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7913 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7914 const uint32_t attIdx = resolveRefs[i].attachment;
7915 if (attIdx != o->resolveRefs[i].attachment)
7917 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7922 const uint32_t attIdx = dsResolveRef.attachment;
7923 if (attIdx != o->dsResolveRef.attachment)
7925 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7930 const uint32_t attIdx = shadingRateRef.attachment;
7931 if (attIdx != o->shadingRateRef.attachment)
7933 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7944 serializedFormatData.clear();
7945 auto p =
std::back_inserter(serializedFormatData);
7947 *p++ = attDescs.size();
7948 *p++ = colorRefs.size();
7949 *p++ = resolveRefs.size();
7953 *p++ = multiViewCount;
7955 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
7956 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
7957 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
7958 *p++ = used ? a->format : 0;
7959 *p++ = used ? a->samples : 0;
7960 *p++ = used ? a->loadOp : 0;
7961 *p++ = used ? a->storeOp : 0;
7962 *p++ = used ? a->stencilLoadOp : 0;
7963 *p++ = used ? a->stencilStoreOp : 0;
7964 *p++ = used ? a->initialLayout : 0;
7965 *p++ = used ? a->finalLayout : 0;
7968 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7969 const uint32_t attIdx = colorRefs[i].attachment;
7971 serializeAttachmentData(attIdx);
7975 const uint32_t attIdx = dsRef.attachment;
7977 serializeAttachmentData(attIdx);
7980 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7981 const uint32_t attIdx = resolveRefs[i].attachment;
7983 serializeAttachmentData(attIdx);
7987 const uint32_t attIdx = dsResolveRef.attachment;
7989 serializeAttachmentData(attIdx);
7993 const uint32_t attIdx = shadingRateRef.attachment;
7995 serializeAttachmentData(attIdx);
8004 rpD->attDescs = attDescs;
8005 rpD->colorRefs = colorRefs;
8006 rpD->resolveRefs = resolveRefs;
8007 rpD->subpassDeps = subpassDeps;
8011 rpD->multiViewCount = multiViewCount;
8013 rpD->dsResolveRef = dsResolveRef;
8014 rpD->shadingRateRef = shadingRateRef;
8016 VkRenderPassCreateInfo rpInfo;
8017 VkSubpassDescription subpassDesc;
8018 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8022 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8027#ifdef VK_KHR_create_renderpass2
8028 if (rhiD->caps.renderPass2KHR) {
8030 VkRenderPassCreateInfo2KHR rpInfo2;
8031 RenderPass2SetupHelper rp2Helper(rhiD);
8032 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8036 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8037 if (err != VK_SUCCESS) {
8038 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8045 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8046 if (err != VK_SUCCESS) {
8047 qWarning(
"Failed to create renderpass: %d", err);
8054 rhiD->registerResource(rpD);
8060 return serializedFormatData;
8065 nativeHandlesStruct.renderPass = rp;
8066 return &nativeHandlesStruct;
8092 texture =
QRHI_RES(QVkTexture, src);
8124 return d.sampleCount;
8128 const QRhiTextureRenderTargetDescription &desc,
8133 rtv[att] = VK_NULL_HANDLE;
8134 resrtv[att] = VK_NULL_HANDLE;
8152 e.textureRenderTarget.fb = d.fb;
8153 d.fb = VK_NULL_HANDLE;
8156 e.textureRenderTarget.rtv[att] = rtv[att];
8157 e.textureRenderTarget.resrtv[att] = resrtv[att];
8158 rtv[att] = VK_NULL_HANDLE;
8159 resrtv[att] = VK_NULL_HANDLE;
8162 e.textureRenderTarget.dsv = dsv;
8163 dsv = VK_NULL_HANDLE;
8164 e.textureRenderTarget.resdsv = resdsv;
8165 resdsv = VK_NULL_HANDLE;
8167 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8168 shadingRateMapView = VK_NULL_HANDLE;
8172 rhiD->releaseQueue.append(e);
8173 rhiD->unregisterResource(
this);
8183 if (!rhiD->createOffscreenRenderPass(rp,
8184 m_desc.cbeginColorAttachments(),
8185 m_desc.cendColorAttachments(),
8186 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8187 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8188 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8189 m_desc.depthStencilBuffer(),
8190 m_desc.depthTexture(),
8191 m_desc.depthResolveTexture(),
8192 m_desc.shadingRateMap()))
8200 rhiD->registerResource(rp);
8209 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8210 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8211 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8214 QVarLengthArray<VkImageView, 8> views;
8215 d.multiViewCount = 0;
8217 d.colorAttCount = 0;
8219 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8220 d.colorAttCount += 1;
8223 Q_ASSERT(texD || rbD);
8225 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8226 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8227 const bool isMultiView = it->multiViewCount() >= 2;
8228 if (isMultiView && d.multiViewCount == 0)
8229 d.multiViewCount = it->multiViewCount();
8230 VkImageViewCreateInfo viewInfo = {};
8231 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8232 viewInfo.image = texD->image;
8233 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8234 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8235 : VK_IMAGE_VIEW_TYPE_2D);
8236 viewInfo.format = texD->viewFormat;
8237 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8238 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8239 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8240 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8241 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8242 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8243 viewInfo.subresourceRange.levelCount = 1;
8244 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8245 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8246 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8247 if (err != VK_SUCCESS) {
8248 qWarning(
"Failed to create render target image view: %d", err);
8251 views.append(rtv[attIndex]);
8252 if (attIndex == 0) {
8253 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8254 d.sampleCount = texD->samples;
8259 if (attIndex == 0) {
8260 d.pixelSize = rbD->pixelSize();
8261 d.sampleCount = rbD->samples;
8267 if (hasDepthStencil) {
8268 if (m_desc.depthTexture()) {
8271 VkImageViewCreateInfo viewInfo = {};
8272 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8273 viewInfo.image = depthTexD->image;
8274 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8275 viewInfo.format = depthTexD->viewFormat;
8276 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8277 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8278 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8279 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8280 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8281 viewInfo.subresourceRange.levelCount = 1;
8282 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8283 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8284 if (err != VK_SUCCESS) {
8285 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8289 if (d.colorAttCount == 0) {
8290 d.pixelSize = depthTexD->pixelSize();
8291 d.sampleCount = depthTexD->samples;
8295 views.append(depthRbD->imageView);
8296 if (d.colorAttCount == 0) {
8297 d.pixelSize = depthRbD->pixelSize();
8298 d.sampleCount = depthRbD->samples;
8306 d.resolveAttCount = 0;
8308 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8309 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8310 if (it->resolveTexture()) {
8312 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8313 d.resolveAttCount += 1;
8315 VkImageViewCreateInfo viewInfo = {};
8316 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8317 viewInfo.image = resTexD->image;
8318 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8319 : VK_IMAGE_VIEW_TYPE_2D;
8320 viewInfo.format = resTexD->viewFormat;
8321 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8322 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8323 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8324 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8325 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8326 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8327 viewInfo.subresourceRange.levelCount = 1;
8328 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8329 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8330 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8331 if (err != VK_SUCCESS) {
8332 qWarning(
"Failed to create render target resolve image view: %d", err);
8335 views.append(resrtv[attIndex]);
8339 if (m_desc.depthResolveTexture()) {
8341 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8343 VkImageViewCreateInfo viewInfo = {};
8344 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8345 viewInfo.image = resTexD->image;
8346 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8347 : VK_IMAGE_VIEW_TYPE_2D;
8348 viewInfo.format = resTexD->viewFormat;
8349 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8350 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8351 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8352 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8353 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8354 viewInfo.subresourceRange.baseMipLevel = 0;
8355 viewInfo.subresourceRange.levelCount = 1;
8356 viewInfo.subresourceRange.baseArrayLayer = 0;
8357 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8358 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8359 if (err != VK_SUCCESS) {
8360 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8363 views.append(resdsv);
8364 d.dsResolveAttCount = 1;
8366 d.dsResolveAttCount = 0;
8369 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8371 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8373 VkImageViewCreateInfo viewInfo = {};
8374 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8375 viewInfo.image = texD->image;
8376 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8377 : VK_IMAGE_VIEW_TYPE_2D;
8378 viewInfo.format = texD->viewFormat;
8379 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8380 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8381 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8382 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8383 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8384 viewInfo.subresourceRange.baseMipLevel = 0;
8385 viewInfo.subresourceRange.levelCount = 1;
8386 viewInfo.subresourceRange.baseArrayLayer = 0;
8387 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8388 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8389 if (err != VK_SUCCESS) {
8390 qWarning(
"Failed to create render target shading rate map view: %d", err);
8393 views.append(shadingRateMapView);
8394 d.shadingRateAttCount = 1;
8396 d.shadingRateAttCount = 0;
8399 if (!m_renderPassDesc)
8400 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8402 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8403 Q_ASSERT(d.rp && d.rp->rp);
8405 VkFramebufferCreateInfo fbInfo = {};
8406 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8407 fbInfo.renderPass = d.rp->rp;
8408 fbInfo.attachmentCount = uint32_t(views.count());
8409 fbInfo.pAttachments = views.constData();
8410 fbInfo.width = uint32_t(d.pixelSize.width());
8411 fbInfo.height = uint32_t(d.pixelSize.height());
8414 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8415 if (err != VK_SUCCESS) {
8416 qWarning(
"Failed to create framebuffer: %d", err);
8420 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8423 rhiD->registerResource(
this);
8429 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8442 return d.sampleCount;
8460 sortedBindings.clear();
8466 e.shaderResourceBindings.poolIndex =
poolIndex;
8467 e.shaderResourceBindings.layout = layout;
8470 layout = VK_NULL_HANDLE;
8471 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8472 descSets[i] = VK_NULL_HANDLE;
8476 rhiD->releaseQueue.append(e);
8477 rhiD->unregisterResource(
this);
8487 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8490 rhiD->updateLayoutDesc(
this);
8492 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8493 descSets[i] = VK_NULL_HANDLE;
8495 sortedBindings.clear();
8496 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8497 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8500 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8501 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8502 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8503 if (b->u.ubuf.hasDynamicOffset)
8504 hasDynamicOffset =
true;
8508 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
8509 vkbindings.reserve(sortedBindings.size());
8510 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8511 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8512 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
8513 vkbinding.binding = uint32_t(b->binding);
8514 vkbinding.descriptorType = toVkDescriptorType(b);
8515 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8516 vkbinding.descriptorCount = b->u.stex.count;
8518 vkbinding.descriptorCount = 1;
8519 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8522 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8523 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8524 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8525 layoutInfo.pBindings = vkbindings.constData();
8527 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8528 if (err != VK_SUCCESS) {
8529 qWarning(
"Failed to create descriptor set layout: %d", err);
8532 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
8534 VkDescriptorSetAllocateInfo allocInfo = {};
8535 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8538 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8539 layouts[i] = layout;
8540 allocInfo.pSetLayouts = layouts;
8541 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8545 boundResourceData[i].resize(sortedBindings.size());
8546 for (BoundResourceData &bd : boundResourceData[i])
8547 memset(&bd, 0,
sizeof(BoundResourceData));
8551 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
8555 rhiD->registerResource(
this);
8561 sortedBindings.clear();
8562 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8563 if (!flags.testFlag(BindingsAreSorted))
8564 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8576 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8577 for (BoundResourceData &bd : boundResourceData[i])
8578 memset(&bd, 0,
sizeof(BoundResourceData));
8596 if (!pipeline && !layout)
8603 e.pipelineState.pipeline = pipeline;
8604 e.pipelineState.layout = layout;
8606 pipeline = VK_NULL_HANDLE;
8607 layout = VK_NULL_HANDLE;
8611 rhiD->releaseQueue.append(e);
8612 rhiD->unregisterResource(
this);
8622 rhiD->pipelineCreationStart();
8623 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8626 if (!rhiD->ensurePipelineCache())
8629 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8630 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8631 pipelineLayoutInfo.setLayoutCount = 1;
8633 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8634 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8635 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8636 if (err != VK_SUCCESS) {
8637 qWarning(
"Failed to create pipeline layout: %d", err);
8641 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8642 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8644 QVarLengthArray<VkShaderModule, 4> shaders;
8645 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8646 QVarLengthArray<QByteArray, 4> entryPointNames;
8647 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8648 const QShader bakedShader = shaderStage.shader();
8649 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8650 if (spirv.shader().isEmpty()) {
8651 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8654 VkShaderModule shader = rhiD->createShader(spirv.shader());
8656 shaders.append(shader);
8657 VkPipelineShaderStageCreateInfo shaderInfo = {};
8658 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8659 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8660 shaderInfo.module = shader;
8661 entryPointNames.append(spirv.entryPoint());
8662 shaderInfo.pName =
nullptr;
8663 shaderStageCreateInfos.append(shaderInfo);
8666 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
8667 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
8669 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8670 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8672 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8673#ifdef VK_EXT_vertex_attribute_divisor
8674 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8676 int bindingIndex = 0;
8677 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8678 it != itEnd; ++it, ++bindingIndex)
8680 VkVertexInputBindingDescription bindingInfo = {
8681 uint32_t(bindingIndex),
8683 it->classification() == QRhiVertexInputBinding::PerVertex
8684 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8686 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8687#ifdef VK_EXT_vertex_attribute_divisor
8688 if (rhiD->caps.vertexAttribDivisor) {
8689 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8693 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8694 "VK_EXT_vertex_attribute_divisor on the device and "
8695 "VK_KHR_get_physical_device_properties2 on the instance");
8698 vertexBindings.append(bindingInfo);
8700 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8701 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8704 VkVertexInputAttributeDescription attributeInfo = {
8705 uint32_t(it->location()),
8706 uint32_t(it->binding()),
8707 toVkAttributeFormat(it->format()),
8710 vertexAttributes.append(attributeInfo);
8712 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8713 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8714 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8715 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8716 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8717 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8718#ifdef VK_EXT_vertex_attribute_divisor
8719 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8720 if (!nonOneStepRates.isEmpty()) {
8721 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8722 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8723 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8724 vertexInputInfo.pNext = &divisorInfo;
8727 pipelineInfo.pVertexInputState = &vertexInputInfo;
8729 QVarLengthArray<VkDynamicState, 8> dynEnable;
8730 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8731 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8732 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8733 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8734 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8735 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8736#ifdef VK_KHR_fragment_shading_rate
8737 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8738 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8741 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8742 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8743 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8744 dynamicInfo.pDynamicStates = dynEnable.constData();
8745 pipelineInfo.pDynamicState = &dynamicInfo;
8747 VkPipelineViewportStateCreateInfo viewportInfo = {};
8748 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8749 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8750 pipelineInfo.pViewportState = &viewportInfo;
8752 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8753 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8754 inputAsmInfo.topology = toVkTopology(m_topology);
8755 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8756 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8758 VkPipelineTessellationStateCreateInfo tessInfo = {};
8759#ifdef VK_VERSION_1_1
8760 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8762 if (m_topology == Patches) {
8763 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8764 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8771#ifdef VK_VERSION_1_1
8772 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8773 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8774 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8775 tessInfo.pNext = &originInfo;
8777 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8780 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8783 pipelineInfo.pTessellationState = &tessInfo;
8786 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8787 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8788 if (m_depthClamp && rhiD->caps.depthClamp)
8789 rastInfo.depthClampEnable = m_depthClamp;
8790 rastInfo.cullMode = toVkCullMode(m_cullMode);
8791 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8792 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8793 rastInfo.depthBiasEnable =
true;
8794 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8795 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8797 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8798 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8799 pipelineInfo.pRasterizationState = &rastInfo;
8801 VkPipelineMultisampleStateCreateInfo msInfo = {};
8802 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8803 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8804 pipelineInfo.pMultisampleState = &msInfo;
8806 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8807 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8808 dsInfo.depthTestEnable = m_depthTest;
8809 dsInfo.depthWriteEnable = m_depthWrite;
8810 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8811 dsInfo.stencilTestEnable = m_stencilTest;
8812 if (m_stencilTest) {
8813 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8814 dsInfo.front.compareMask = m_stencilReadMask;
8815 dsInfo.front.writeMask = m_stencilWriteMask;
8816 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8817 dsInfo.back.compareMask = m_stencilReadMask;
8818 dsInfo.back.writeMask = m_stencilWriteMask;
8820 pipelineInfo.pDepthStencilState = &dsInfo;
8822 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8823 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8824 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8825 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8826 VkPipelineColorBlendAttachmentState blend = {};
8827 blend.blendEnable = b.enable;
8828 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8829 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8830 blend.colorBlendOp = toVkBlendOp(b.opColor);
8831 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8832 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8833 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8834 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8835 vktargetBlends.append(blend);
8837 if (vktargetBlends.isEmpty()) {
8838 VkPipelineColorBlendAttachmentState blend = {};
8839 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8840 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8841 vktargetBlends.append(blend);
8843 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8844 blendInfo.pAttachments = vktargetBlends.constData();
8845 pipelineInfo.pColorBlendState = &blendInfo;
8847 pipelineInfo.layout = layout;
8849 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8850 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8852 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8854 for (VkShaderModule shader : shaders)
8855 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8857 if (err != VK_SUCCESS) {
8858 qWarning(
"Failed to create graphics pipeline: %d", err);
8862 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8864 rhiD->pipelineCreationEnd();
8867 rhiD->registerResource(
this);
8883 if (!pipeline && !layout)
8890 e.pipelineState.pipeline = pipeline;
8891 e.pipelineState.layout = layout;
8893 pipeline = VK_NULL_HANDLE;
8894 layout = VK_NULL_HANDLE;
8898 rhiD->releaseQueue.append(e);
8899 rhiD->unregisterResource(
this);
8909 rhiD->pipelineCreationStart();
8910 if (!rhiD->ensurePipelineCache())
8913 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8914 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8915 pipelineLayoutInfo.setLayoutCount = 1;
8917 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8918 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8919 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8920 if (err != VK_SUCCESS) {
8921 qWarning(
"Failed to create pipeline layout: %d", err);
8925 VkComputePipelineCreateInfo pipelineInfo = {};
8926 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8927 pipelineInfo.layout = layout;
8929 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
8930 qWarning(
"Compute pipeline requires a compute shader stage");
8933 const QShader bakedShader = m_shaderStage.shader();
8934 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
8935 if (spirv.shader().isEmpty()) {
8936 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8939 if (bakedShader.stage() != QShader::ComputeStage) {
8940 qWarning() << bakedShader <<
"is not a compute shader";
8943 VkShaderModule shader = rhiD->createShader(spirv.shader());
8944 VkPipelineShaderStageCreateInfo shaderInfo = {};
8945 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8946 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8947 shaderInfo.module = shader;
8948 const QByteArray entryPointName = spirv.entryPoint();
8949 shaderInfo.pName = entryPointName.constData();
8950 pipelineInfo.stage = shaderInfo;
8952 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8953 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8954 if (err != VK_SUCCESS) {
8955 qWarning(
"Failed to create graphics pipeline: %d", err);
8959 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8961 rhiD->pipelineCreationEnd();
8964 rhiD->registerResource(
this);
8993 nativeHandlesStruct.commandBuffer = cb;
8995 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
8996 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
8998 nativeHandlesStruct.commandBuffer = cb;
9001 return &nativeHandlesStruct;
9019 if (sc == VK_NULL_HANDLE)
9024 rhiD->swapchains.remove(
this);
9030 frame.cmdBuf = VK_NULL_HANDLE;
9034 surface = lastConnectedSurface = VK_NULL_HANDLE;
9037 rhiD->unregisterResource(
this);
9052 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9062 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9064 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9065 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9066 if (bufferSize.width == uint32_t(-1)) {
9067 Q_ASSERT(bufferSize.height == uint32_t(-1));
9068 return m_window->size() * m_window->devicePixelRatio();
9070 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9076 case QRhiSwapChain::HDRExtendedSrgbLinear:
9077 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9078 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9079 case QRhiSwapChain::HDR10:
9080 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9081 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9082 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9083 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9084 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9097 qWarning(
"Attempted to call isFormatSupported() without a window set");
9102 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9105 uint32_t formatCount = 0;
9106 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9107 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9109 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9110 for (uint32_t i = 0; i < formatCount; ++i) {
9111 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9123 QRHI_RES_RHI(QRhiVulkan);
9125 if (m_window && rhiD->adapterLuidValid)
9126 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9140 if (!rhiD->createDefaultRenderPass(rp,
9141 m_depthStencil !=
nullptr,
9152 rhiD->registerResource(rp);
9159 case VK_FORMAT_R8_SRGB:
9160 case VK_FORMAT_R8G8_SRGB:
9161 case VK_FORMAT_R8G8B8_SRGB:
9162 case VK_FORMAT_B8G8R8_SRGB:
9163 case VK_FORMAT_R8G8B8A8_SRGB:
9164 case VK_FORMAT_B8G8R8A8_SRGB:
9165 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9180 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9182 qWarning(
"Failed to get surface for window");
9185 if (surface == surf)
9191 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9192 qWarning(
"Presenting not supported on this window");
9196 quint32 formatCount = 0;
9197 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9198 QList<VkSurfaceFormatKHR> formats(formatCount);
9199 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9203 colorFormat = formats.constFirst().format;
9204 colorSpace = formats.constFirst().colorSpace;
9207 const bool srgbRequested = m_flags.testFlag(sRGB);
9208 bool foundBestFormat =
false;
9209 if (m_format == SDR) {
9210 for (
int i = 0; i <
int(formatCount); ++i) {
9212 if (srgbRequested) {
9213 ok = defaultSrgbColorFormat == formats[i].format;
9215 ok = defaultColorFormat == formats[i].format;
9218 foundBestFormat =
true;
9219 colorFormat = formats[i].format;
9220 colorSpace = formats[i].colorSpace;
9227 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9228 for (
int i = 0; i <
int(formatCount); ++i) {
9230 if (m_format != SDR) {
9231 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9232 }
else if (srgbRequested) {
9233 ok = isSrgbFormat(formats[i].format);
9236 colorFormat = formats[i].format;
9237 colorSpace = formats[i].colorSpace;
9244 if (m_format != SDR) {
9245 VkSurfaceFormatKHR format{};
9246 format.format = colorFormat;
9247 format.colorSpace = colorSpace;
9248 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9249 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9253 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9254 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9259#if QT_CONFIG(wayland)
9264 const bool hasPassThrough =
9265 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9266 return fmt.format == colorFormat
9267 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9269 if (hasPassThrough) {
9270 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9274 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9276 quint32 presModeCount = 0;
9277 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9278 supportedPresentationModes.resize(presModeCount);
9279 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9280 supportedPresentationModes.data());
9288 const bool needsRegistration = !window || window != m_window;
9295 if (window && window != m_window)
9299 m_currentPixelSize = surfacePixelSize();
9300 pixelSize = m_currentPixelSize;
9303 qWarning(
"Failed to create new swapchain");
9307 if (needsRegistration || !rhiD->swapchains.contains(
this))
9308 rhiD->swapchains.insert(
this);
9310 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9311 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9312 m_depthStencil->sampleCount(), m_sampleCount);
9314 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9315 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9316 m_depthStencil->setPixelSize(pixelSize);
9317 if (!m_depthStencil->create())
9318 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9319 pixelSize.width(), pixelSize.height());
9321 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9322 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9323 pixelSize.width(), pixelSize.height());
9327 if (!m_renderPassDesc)
9328 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9330 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9331 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9332 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9334 rtWrapper.d.pixelSize = pixelSize;
9335 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9336 rtWrapper.d.sampleCount = samples;
9337 rtWrapper.d.colorAttCount = 1;
9338 if (m_depthStencil) {
9339 rtWrapper.d.dsAttCount = 1;
9340 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9342 rtWrapper.d.dsAttCount = 0;
9345 rtWrapper.d.dsResolveAttCount = 0;
9346 if (samples > VK_SAMPLE_COUNT_1_BIT)
9347 rtWrapper.d.resolveAttCount = 1;
9349 rtWrapper.d.resolveAttCount = 0;
9351 if (shadingRateMapView)
9352 rtWrapper.d.shadingRateAttCount = 1;
9354 rtWrapper.d.shadingRateAttCount = 0;
9359 QVarLengthArray<VkImageView, 4> views;
9360 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9362 views.append(
ds->imageView);
9363 if (samples > VK_SAMPLE_COUNT_1_BIT)
9364 views.append(image.imageView);
9365 if (shadingRateMapView)
9366 views.append(shadingRateMapView);
9368 VkFramebufferCreateInfo fbInfo = {};
9369 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9370 fbInfo.renderPass = rtWrapper.d.rp->rp;
9371 fbInfo.attachmentCount = uint32_t(views.count());
9372 fbInfo.pAttachments = views.constData();
9373 fbInfo.width = uint32_t(pixelSize.width());
9374 fbInfo.height = uint32_t(pixelSize.height());
9377 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9378 if (err != VK_SUCCESS) {
9379 qWarning(
"Failed to create framebuffer: %d", err);
9385 rtWrapperRight.setRenderPassDescriptor(
9387 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9388 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9390 rtWrapperRight.d.pixelSize = pixelSize;
9391 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9392 rtWrapperRight.d.sampleCount = samples;
9393 rtWrapperRight.d.colorAttCount = 1;
9394 if (m_depthStencil) {
9395 rtWrapperRight.d.dsAttCount = 1;
9396 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9398 rtWrapperRight.d.dsAttCount = 0;
9401 rtWrapperRight.d.dsResolveAttCount = 0;
9402 if (samples > VK_SAMPLE_COUNT_1_BIT)
9403 rtWrapperRight.d.resolveAttCount = 1;
9405 rtWrapperRight.d.resolveAttCount = 0;
9410 QVarLengthArray<VkImageView, 4> views;
9411 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9413 views.append(
ds->imageView);
9414 if (samples > VK_SAMPLE_COUNT_1_BIT)
9415 views.append(image.imageView);
9416 if (shadingRateMapView)
9417 views.append(shadingRateMapView);
9419 VkFramebufferCreateInfo fbInfo = {};
9420 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9421 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9422 fbInfo.attachmentCount = uint32_t(views.count());
9423 fbInfo.pAttachments = views.constData();
9424 fbInfo.width = uint32_t(pixelSize.width());
9425 fbInfo.height = uint32_t(pixelSize.height());
9428 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9429 if (err != VK_SUCCESS) {
9430 qWarning(
"Failed to create framebuffer: %d", err);
9438 if (needsRegistration)
9439 rhiD->registerResource(
this);
const char * constData() const
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker)
VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD=nullptr)
QRhiSwapChain * createSwapChain() override
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
int resourceLimit(QRhi::ResourceLimit limit) const override
bool isDeviceLost() const override
void prepareUploadSubres(QVkTexture *texD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, size_t *curOfs, void *mp, BufferImageCopyList *copyInfos)
void executeDeferredReleases(bool forced=false)
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex)
QRhi::FrameOpResult finish() override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples, VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count)
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void releaseCachedResources() override
QVkSwapChain * currentSwapChain
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams=nullptr)
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
QList< int > supportedSampleCounts() const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb)
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, QRhiShadingRateMap *shadingRateMap)
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot, VkAccessFlags access, VkPipelineStageFlags stage)
QRhi::FrameOpResult waitCommandCompletion(int frameSlot)
void endExternal(QRhiCommandBuffer *cb) override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex)
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
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)
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)