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 for (
const char *ext : inst->extensions())
551 qCDebug(QRHI_LOG_INFO,
" %s", ext);
555 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
557 QList<VkQueueFamilyProperties> queueFamilyProps;
558 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
559 uint32_t queueCount = 0;
560 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
561 queueFamilyProps.resize(
int(queueCount));
562 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
567 uint32_t physDevCount = 0;
568 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
570 qWarning(
"No physical devices");
573 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
574 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
575 if (err != VK_SUCCESS || !physDevCount) {
576 qWarning(
"Failed to enumerate physical devices: %d", err);
580 int physDevIndex = -1;
581 int requestedPhysDevIndex = -1;
582 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
583 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
585 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
586 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
587 for (
int i = 0; i <
int(physDevCount); ++i) {
588 if (physDevs[i] == requestedPhysDev) {
589 requestedPhysDevIndex = i;
595 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
596 for (
int i = 0; i <
int(physDevCount); ++i) {
597 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
598 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
599 requestedPhysDevIndex = i;
605 for (
int i = 0; i <
int(physDevCount); ++i) {
606 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
607 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
609 physDevProperties.deviceName,
610 VK_VERSION_MAJOR(physDevProperties.driverVersion),
611 VK_VERSION_MINOR(physDevProperties.driverVersion),
612 VK_VERSION_PATCH(physDevProperties.driverVersion),
613 VK_VERSION_MAJOR(physDevProperties.apiVersion),
614 VK_VERSION_MINOR(physDevProperties.apiVersion),
615 VK_VERSION_PATCH(physDevProperties.apiVersion),
616 physDevProperties.vendorID,
617 physDevProperties.deviceID,
618 physDevProperties.deviceType);
619 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
621 qCDebug(QRHI_LOG_INFO,
" using this physical device");
625 if (physDevIndex < 0) {
626 qWarning(
"No matching physical device");
629 physDev = physDevs[physDevIndex];
630 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
632 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
633 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
634 physDevProperties.deviceName,
635 VK_VERSION_MAJOR(physDevProperties.driverVersion),
636 VK_VERSION_MINOR(physDevProperties.driverVersion),
637 VK_VERSION_PATCH(physDevProperties.driverVersion),
638 VK_VERSION_MAJOR(physDevProperties.apiVersion),
639 VK_VERSION_MINOR(physDevProperties.apiVersion),
640 VK_VERSION_PATCH(physDevProperties.apiVersion),
641 physDevProperties.vendorID,
642 physDevProperties.deviceID,
643 physDevProperties.deviceType);
646 caps.apiVersion = inst->apiVersion();
652 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
653 VK_VERSION_MINOR(physDevProperties.apiVersion));
654 if (physDevApiVersion < caps.apiVersion) {
655 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
656 <<
"whereas the chosen physical device has" << physDevApiVersion
657 <<
"- restricting to the latter";
658 caps.apiVersion = physDevApiVersion;
663 QVulkanInfoVector<QVulkanExtension> devExts;
664 uint32_t devExtCount = 0;
665 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
667 QList<VkExtensionProperties> extProps(devExtCount);
668 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
669 for (
const VkExtensionProperties &p : std::as_const(extProps))
670 devExts.append({ p.extensionName, p.specVersion });
672 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
674 bool featuresQueried =
false;
676 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
677 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
680#ifdef VK_KHR_fragment_shading_rate
681 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
682 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
683 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
684 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
686#ifdef VK_EXT_device_fault
687 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
688 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
689 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
690 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
696 if (!featuresQueried) {
698 if (caps.apiVersion >= QVersionNumber(1, 2)) {
699 physDevFeatures11IfApi12OrNewer = {};
700 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
701 physDevFeatures12 = {};
702 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
704 physDevFeatures13 = {};
705 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
707 physDevFeatures14 = {};
708 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
711 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
712 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
714 if (caps.apiVersion >= QVersionNumber(1, 3))
715 physDevFeatures12.pNext = &physDevFeatures13;
717 if (caps.apiVersion >= QVersionNumber(1, 4))
718 physDevFeatures13.pNext = &physDevFeatures14;
721 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
722 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
723 featuresQueried =
true;
730 if (!featuresQueried) {
738 if (caps.apiVersion == QVersionNumber(1, 1)) {
739 multiviewFeaturesIfApi11 = {};
740 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
741 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
742 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
743 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
744 featuresQueried =
true;
749 if (!featuresQueried) {
752 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
753 featuresQueried =
true;
761 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
762 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
763 queryQueueFamilyProps();
764 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
765 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
766 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
767 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
768 if (!gfxQueueFamilyIdxOpt.has_value()
769 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
770 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
772 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
773 gfxQueueFamilyIdxOpt = i;
774 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
775 computelessGfxQueueCandidateIdxOpt = i;
778 if (gfxQueueFamilyIdxOpt.has_value()) {
779 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
781 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
782 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
784 qWarning(
"No graphics (or no graphics+present) queue family found");
789 VkDeviceQueueCreateInfo queueInfo = {};
790 const float prio[] = { 0 };
791 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
792 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
793 queueInfo.queueCount = 1;
794 queueInfo.pQueuePriorities = prio;
796 QList<
const char *> devLayers;
797 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
798 devLayers.append(
"VK_LAYER_KHRONOS_validation");
800 QList<
const char *> requestedDevExts;
801 requestedDevExts.append(
"VK_KHR_swapchain");
803 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
805 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
806 if (hasPhysDevProp2) {
807 requestedDevExts.append(
"VK_KHR_portability_subset");
809 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
810 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
815#ifdef VK_EXT_vertex_attribute_divisor
816 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
817 if (hasPhysDevProp2) {
818 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
819 caps.vertexAttribDivisor =
true;
824#ifdef VK_KHR_create_renderpass2
825 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
826 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
827 caps.renderPass2KHR =
true;
831#ifdef VK_KHR_depth_stencil_resolve
832 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
833 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
834 caps.depthStencilResolveKHR =
true;
838#ifdef VK_KHR_fragment_shading_rate
839 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
840 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
843#ifdef VK_EXT_device_fault
844 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
845 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
846 caps.deviceFault =
true;
850 for (
const QByteArray &ext : requestedDeviceExtensions) {
851 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
852 if (devExts.contains(ext)) {
853 requestedDevExts.append(ext.constData());
855 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
861 QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
862 for (
const QByteArray &ext : envExtList) {
863 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
864 if (devExts.contains(ext)) {
865 requestedDevExts.append(ext.constData());
867 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
873 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
874 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
875 for (
const char *ext : requestedDevExts)
876 qCDebug(QRHI_LOG_INFO,
" %s", ext);
879 VkDeviceCreateInfo devInfo = {};
880 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
881 devInfo.queueCreateInfoCount = 1;
882 devInfo.pQueueCreateInfos = &queueInfo;
883 devInfo.enabledLayerCount = uint32_t(devLayers.size());
884 devInfo.ppEnabledLayerNames = devLayers.constData();
885 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
886 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
902 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
905 physDevFeatures13.robustImageAccess = VK_FALSE;
909 if (caps.apiVersion >= QVersionNumber(1, 1)) {
916 devInfo.pNext = &physDevFeaturesChainable;
920 physDevFeatures.robustBufferAccess = VK_FALSE;
921 devInfo.pEnabledFeatures = &physDevFeatures;
924 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
925 if (err != VK_SUCCESS) {
926 qWarning(
"Failed to create device: %d", err);
930 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
935 caps.deviceFault =
true;
936 caps.vertexAttribDivisor =
true;
937 caps.renderPass2KHR =
true;
938 caps.depthStencilResolveKHR =
true;
941 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
942 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
943 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
944 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
945 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
946 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
948 df = inst->deviceFunctions(dev);
950 VkCommandPoolCreateInfo poolInfo = {};
951 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
952 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
954 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
955 if (err != VK_SUCCESS) {
956 qWarning(
"Failed to create command pool: %d", err);
961 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
962 gfxQueueFamilyIdx, gfxQueueIdx);
964 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
966 if (queueFamilyProps.isEmpty())
967 queryQueueFamilyProps();
969 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
970 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
972 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
975 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
977 caps.depthClamp = physDevFeatures.depthClamp;
979 caps.wideLines = physDevFeatures.wideLines;
981 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
983 caps.tessellation = physDevFeatures.tessellationShader;
984 caps.geometryShader = physDevFeatures.geometryShader;
986 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
988 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
991 if (caps.apiVersion >= QVersionNumber(1, 2))
992 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
996 if (caps.apiVersion == QVersionNumber(1, 1))
997 caps.multiView = multiviewFeaturesIfApi11.multiview;
1000#ifdef VK_KHR_fragment_shading_rate
1001 fragmentShadingRates.clear();
1002 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1003 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1004 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1005 if (caps.imageBasedShadingRate) {
1006 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1007 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1008 VkPhysicalDeviceProperties2 props2 = {};
1009 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1010 props2.pNext = &shadingRateProps;
1011 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1012 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1015 if (caps.perDrawShadingRate) {
1016 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1017 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1018 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1019 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1021 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1022 fragmentShadingRates.resize(count);
1023 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1025 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1027 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1029 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1030 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1039#ifdef VK_KHR_create_renderpass2
1040 if (caps.renderPass2KHR) {
1041 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1042 if (!vkCreateRenderPass2KHR)
1043 caps.renderPass2KHR =
false;
1049 adapterLuidValid =
false;
1051#ifdef VK_VERSION_1_2
1052 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1053 VkPhysicalDeviceVulkan11Properties v11props = {};
1054 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1055 VkPhysicalDeviceProperties2 props2 = {};
1056 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1057 props2.pNext = &v11props;
1058 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1059 if (v11props.deviceLUIDValid) {
1060 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1061 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1062 adapterLuidValid =
true;
1063 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1064 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1065 adapterLuid.LowPart, adapterLuid.HighPart);
1072 VmaVulkanFunctions funcs = {};
1073 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1074 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1076 VmaAllocatorCreateInfo allocatorInfo = {};
1079 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1080 allocatorInfo.physicalDevice = physDev;
1081 allocatorInfo.device = dev;
1082 allocatorInfo.pVulkanFunctions = &funcs;
1083 allocatorInfo.instance = inst->vkInstance();
1091#ifdef VK_VERSION_1_4
1092 if (caps.apiVersion >= QVersionNumber(1, 4))
1093 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1096#ifdef VK_VERSION_1_3
1097 if (caps.apiVersion >= QVersionNumber(1, 3))
1098 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1101#ifdef VK_VERSION_1_2
1102 if (caps.apiVersion >= QVersionNumber(1, 2))
1103 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1106#ifdef VK_VERSION_1_1
1107 if (caps.apiVersion >= QVersionNumber(1, 1))
1108 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1111#ifdef VK_VERSION_1_0
1112 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1115 VmaAllocator vmaallocator;
1116 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1117 if (err != VK_SUCCESS) {
1118 qWarning(
"Failed to create allocator: %d", err);
1124 inst->installDebugOutputFilter(qvk_debug_filter);
1126 VkDescriptorPool pool;
1127 VkResult err = createDescriptorPool(&pool);
1128 if (err == VK_SUCCESS)
1129 descriptorPools.append(pool);
1131 qWarning(
"Failed to create initial descriptor pool: %d", err);
1133 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1134 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1135 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1137 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1138 if (err != VK_SUCCESS) {
1139 qWarning(
"Failed to create timestamp query pool: %d", err);
1142 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1143 timestampQueryPoolMap.fill(
false);
1145#ifdef VK_EXT_debug_utils
1146 if (caps.debugUtils) {
1147 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1148 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1149 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1150 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1154#ifdef VK_EXT_device_fault
1155 if (caps.deviceFault) {
1156 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1162 nativeHandlesStruct.physDev = physDev;
1163 nativeHandlesStruct.dev = dev;
1164 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1165 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1166 nativeHandlesStruct.gfxQueue = gfxQueue;
1167 nativeHandlesStruct.vmemAllocator = allocator;
1168 nativeHandlesStruct.inst = inst;
1179 df->vkDeviceWaitIdle(dev);
1186 dxgiHdrInfo =
nullptr;
1190 df->vkDestroyFence(dev, ofr.cmdFence,
nullptr);
1191 ofr.cmdFence = VK_NULL_HANDLE;
1194 if (pipelineCache) {
1195 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1196 pipelineCache = VK_NULL_HANDLE;
1199 for (
const DescriptorPoolData &pool : descriptorPools)
1200 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1202 descriptorPools.clear();
1204 if (timestampQueryPool) {
1205 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1206 timestampQueryPool = VK_NULL_HANDLE;
1210 vmaDestroyAllocator(toVmaAllocator(allocator));
1216 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1217 cmdPool[i] = VK_NULL_HANDLE;
1219 freeSecondaryCbs[i].clear();
1220 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1223 if (!importedDevice && dev) {
1224 df->vkDestroyDevice(dev,
nullptr);
1225 inst->resetDeviceFunctions(dev);
1226 dev = VK_NULL_HANDLE;
1236QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1238 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1239 if (nativeHandles) {
1240 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1241 requestedPhysDev = h->physDev;
1244 QRhi::AdapterList list;
1245 QVulkanFunctions *f = inst->functions();
1246 uint32_t physDevCount = 0;
1247 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1251 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1252 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1253 if (err != VK_SUCCESS || !physDevCount)
1256 VkPhysicalDeviceProperties physDevProperties = {};
1257 for (uint32_t i = 0; i < physDevCount; ++i) {
1258 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1261 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1262 QVulkanAdapter *a =
new QVulkanAdapter;
1263 a->physDev = physDevs[i];
1264 fillDriverInfo(&a->adapterInfo, physDevProperties);
1278 VkDescriptorPoolSize descPoolSizes[] = {
1279 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1280 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1281 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1282 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1283 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1284 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1285 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1287 VkDescriptorPoolCreateInfo descPoolInfo = {};
1288 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1292 descPoolInfo.flags = 0;
1294 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1295 descPoolInfo.pPoolSizes = descPoolSizes;
1296 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1301 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1302 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1303 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1304 if (r == VK_SUCCESS)
1305 descriptorPools[poolIndex].refCount += 1;
1309 int lastPoolIdx = descriptorPools.size() - 1;
1310 for (
int i = lastPoolIdx; i >= 0; --i) {
1311 if (descriptorPools[i].refCount == 0) {
1312 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1313 descriptorPools[i].allocedDescSets = 0;
1315 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1316 VkResult err = tryAllocate(i);
1317 if (err == VK_SUCCESS) {
1318 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1319 *resultPoolIndex = i;
1325 VkDescriptorPool newPool;
1326 VkResult poolErr = createDescriptorPool(&newPool);
1327 if (poolErr == VK_SUCCESS) {
1328 descriptorPools.append(newPool);
1329 lastPoolIdx = descriptorPools.size() - 1;
1330 VkResult err = tryAllocate(lastPoolIdx);
1331 if (err != VK_SUCCESS) {
1332 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1335 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1336 *resultPoolIndex = lastPoolIdx;
1339 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1346 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1348 case QRhiTexture::RGBA8:
1349 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1350 case QRhiTexture::BGRA8:
1351 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1352 case QRhiTexture::R8:
1353 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1354 case QRhiTexture::RG8:
1355 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1356 case QRhiTexture::R16:
1357 return VK_FORMAT_R16_UNORM;
1358 case QRhiTexture::RG16:
1359 return VK_FORMAT_R16G16_UNORM;
1360 case QRhiTexture::RED_OR_ALPHA8:
1361 return VK_FORMAT_R8_UNORM;
1363 case QRhiTexture::RGBA16F:
1364 return VK_FORMAT_R16G16B16A16_SFLOAT;
1365 case QRhiTexture::RGBA32F:
1366 return VK_FORMAT_R32G32B32A32_SFLOAT;
1367 case QRhiTexture::R16F:
1368 return VK_FORMAT_R16_SFLOAT;
1369 case QRhiTexture::R32F:
1370 return VK_FORMAT_R32_SFLOAT;
1372 case QRhiTexture::RGB10A2:
1374 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1376 case QRhiTexture::R8SI:
1377 return VK_FORMAT_R8_SINT;
1378 case QRhiTexture::R32SI:
1379 return VK_FORMAT_R32_SINT;
1380 case QRhiTexture::RG32SI:
1381 return VK_FORMAT_R32G32_SINT;
1382 case QRhiTexture::RGBA32SI:
1383 return VK_FORMAT_R32G32B32A32_SINT;
1385 case QRhiTexture::R8UI:
1386 return VK_FORMAT_R8_UINT;
1387 case QRhiTexture::R32UI:
1388 return VK_FORMAT_R32_UINT;
1389 case QRhiTexture::RG32UI:
1390 return VK_FORMAT_R32G32_UINT;
1391 case QRhiTexture::RGBA32UI:
1392 return VK_FORMAT_R32G32B32A32_UINT;
1394 case QRhiTexture::D16:
1395 return VK_FORMAT_D16_UNORM;
1396 case QRhiTexture::D24:
1397 return VK_FORMAT_X8_D24_UNORM_PACK32;
1398 case QRhiTexture::D24S8:
1399 return VK_FORMAT_D24_UNORM_S8_UINT;
1400 case QRhiTexture::D32F:
1401 return VK_FORMAT_D32_SFLOAT;
1402 case QRhiTexture::D32FS8:
1403 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1405 case QRhiTexture::BC1:
1406 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1407 case QRhiTexture::BC2:
1408 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1409 case QRhiTexture::BC3:
1410 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1411 case QRhiTexture::BC4:
1412 return VK_FORMAT_BC4_UNORM_BLOCK;
1413 case QRhiTexture::BC5:
1414 return VK_FORMAT_BC5_UNORM_BLOCK;
1415 case QRhiTexture::BC6H:
1416 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1417 case QRhiTexture::BC7:
1418 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1420 case QRhiTexture::ETC2_RGB8:
1421 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1422 case QRhiTexture::ETC2_RGB8A1:
1423 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1424 case QRhiTexture::ETC2_RGBA8:
1425 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1427 case QRhiTexture::ASTC_4x4:
1428 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1429 case QRhiTexture::ASTC_5x4:
1430 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1431 case QRhiTexture::ASTC_5x5:
1432 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1433 case QRhiTexture::ASTC_6x5:
1434 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1435 case QRhiTexture::ASTC_6x6:
1436 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1437 case QRhiTexture::ASTC_8x5:
1438 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1439 case QRhiTexture::ASTC_8x6:
1440 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1441 case QRhiTexture::ASTC_8x8:
1442 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1443 case QRhiTexture::ASTC_10x5:
1444 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1445 case QRhiTexture::ASTC_10x6:
1446 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1447 case QRhiTexture::ASTC_10x8:
1448 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1449 case QRhiTexture::ASTC_10x10:
1450 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1451 case QRhiTexture::ASTC_12x10:
1452 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1453 case QRhiTexture::ASTC_12x12:
1454 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1457 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1464 case VK_FORMAT_R8G8B8A8_UNORM:
1465 return QRhiTexture::RGBA8;
1466 case VK_FORMAT_R8G8B8A8_SRGB:
1468 (*flags) |= QRhiTexture::sRGB;
1469 return QRhiTexture::RGBA8;
1470 case VK_FORMAT_B8G8R8A8_UNORM:
1471 return QRhiTexture::BGRA8;
1472 case VK_FORMAT_B8G8R8A8_SRGB:
1474 (*flags) |= QRhiTexture::sRGB;
1475 return QRhiTexture::BGRA8;
1476 case VK_FORMAT_R16G16B16A16_SFLOAT:
1477 return QRhiTexture::RGBA16F;
1478 case VK_FORMAT_R32G32B32A32_SFLOAT:
1479 return QRhiTexture::RGBA32F;
1480 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1481 return QRhiTexture::RGB10A2;
1483 qWarning(
"VkFormat %d cannot be read back", format);
1486 return QRhiTexture::UnknownFormat;
1492 case QRhiTexture::Format::D16:
1493 case QRhiTexture::Format::D24:
1494 case QRhiTexture::Format::D24S8:
1495 case QRhiTexture::Format::D32F:
1496 case QRhiTexture::Format::D32FS8:
1507 case QRhiTexture::Format::D24S8:
1508 case QRhiTexture::Format::D32FS8:
1518 if (isDepthTextureFormat(format)) {
1519 if (isStencilTextureFormat(format))
1520 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1522 return VK_IMAGE_ASPECT_DEPTH_BIT;
1524 return VK_IMAGE_ASPECT_COLOR_BIT;
1535 VkPhysicalDeviceMemoryProperties physDevMemProps;
1536 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1538 VkMemoryRequirements memReq;
1539 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1540 uint32_t memTypeIndex = uint32_t(-1);
1542 if (memReq.memoryTypeBits) {
1544 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1545 bool foundDevLocal =
false;
1546 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1547 if (memReq.memoryTypeBits & (1 << i)) {
1548 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1549 if (!foundDevLocal) {
1550 foundDevLocal =
true;
1553 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1562 return memTypeIndex;
1566 const QSize &pixelSize,
1567 VkImageUsageFlags usage,
1568 VkImageAspectFlags aspectMask,
1569 VkSampleCountFlagBits samples,
1570 VkDeviceMemory *mem,
1575 VkMemoryRequirements memReq;
1578 for (
int i = 0; i < count; ++i) {
1579 VkImageCreateInfo imgInfo = {};
1580 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1581 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1582 imgInfo.format = format;
1583 imgInfo.extent.width = uint32_t(pixelSize.width());
1584 imgInfo.extent.height = uint32_t(pixelSize.height());
1585 imgInfo.extent.depth = 1;
1586 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1587 imgInfo.samples = samples;
1588 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1589 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1590 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1592 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1593 if (err != VK_SUCCESS) {
1594 qWarning(
"Failed to create image: %d", err);
1601 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1604 VkMemoryAllocateInfo memInfo = {};
1605 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1606 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1608 uint32_t startIndex = 0;
1610 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1611 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1612 qWarning(
"No suitable memory type found");
1615 startIndex = memInfo.memoryTypeIndex + 1;
1616 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1617 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1618 qWarning(
"Failed to allocate image memory: %d", err);
1621 }
while (err != VK_SUCCESS);
1623 VkDeviceSize ofs = 0;
1624 for (
int i = 0; i < count; ++i) {
1625 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1626 if (err != VK_SUCCESS) {
1627 qWarning(
"Failed to bind image memory: %d", err);
1630 ofs += aligned(memReq.size, memReq.alignment);
1632 VkImageViewCreateInfo imgViewInfo = {};
1633 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1634 imgViewInfo.image = images[i];
1635 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1636 imgViewInfo.format = format;
1637 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1638 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1639 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1640 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1641 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1642 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1644 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1645 if (err != VK_SUCCESS) {
1646 qWarning(
"Failed to create image view: %d", err);
1656 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1657 return optimalDsFormat;
1659 const VkFormat dsFormatCandidates[] = {
1660 VK_FORMAT_D24_UNORM_S8_UINT,
1661 VK_FORMAT_D32_SFLOAT_S8_UINT,
1662 VK_FORMAT_D16_UNORM_S8_UINT
1664 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1665 int dsFormatIdx = 0;
1666 while (dsFormatIdx < dsFormatCandidateCount) {
1667 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1668 VkFormatProperties fmtProp;
1669 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1670 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1674 if (dsFormatIdx == dsFormatCandidateCount)
1675 qWarning(
"Failed to find an optimal depth-stencil format");
1677 return optimalDsFormat;
1682 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1684 if (multiViewCount < 2)
1686 if (!multiViewCap) {
1687 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1690#ifdef VK_VERSION_1_1
1691 uint32_t allViewsMask = 0;
1692 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1693 allViewsMask |= (1 << i);
1694 multiViewMask = allViewsMask;
1695 multiViewCorrelationMask = allViewsMask;
1696 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1697 multiViewInfo.subpassCount = 1;
1698 multiViewInfo.pViewMasks = &multiViewMask;
1699 multiViewInfo.correlationMaskCount = 1;
1700 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1701 rpInfo->pNext = &multiViewInfo;
1706#ifdef VK_VERSION_1_1
1713#ifdef VK_KHR_create_renderpass2
1717struct RenderPass2SetupHelper
1719 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1721 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1725 if (multiViewCount >= 2) {
1726 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1727 viewMask |= (1 << i);
1730 attDescs2.resize(rpInfo->attachmentCount);
1731 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1732 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1733 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1735 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1736 att2.flags = att.flags;
1737 att2.format = att.format;
1738 att2.samples = att.samples;
1739 att2.loadOp = att.loadOp;
1740 att2.storeOp = att.storeOp;
1741 att2.stencilLoadOp = att.stencilLoadOp;
1742 att2.stencilStoreOp = att.stencilStoreOp;
1743 att2.initialLayout = att.initialLayout;
1744 att2.finalLayout = att.finalLayout;
1749 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1750 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1751 subpass2.flags = subpassDesc.flags;
1752 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1753 if (multiViewCount >= 2)
1754 subpass2.viewMask = viewMask;
1757 qsizetype startIndex = attRefs2.count();
1758 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1759 attRefs2.append({});
1760 VkAttachmentReference2KHR &attref2(attRefs2.last());
1761 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1762 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1763 attref2.attachment = attref.attachment;
1764 attref2.layout = attref.layout;
1765 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1767 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1768 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1771 if (subpassDesc.pResolveAttachments) {
1772 startIndex = attRefs2.count();
1773 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1774 attRefs2.append({});
1775 VkAttachmentReference2KHR &attref2(attRefs2.last());
1776 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1777 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1778 attref2.attachment = attref.attachment;
1779 attref2.layout = attref.layout;
1780 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1782 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1786 if (subpassDesc.pDepthStencilAttachment) {
1787 startIndex = attRefs2.count();
1788 attRefs2.append({});
1789 VkAttachmentReference2KHR &attref2(attRefs2.last());
1790 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1791 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1792 attref2.attachment = attref.attachment;
1793 attref2.layout = attref.layout;
1794 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1795 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1799#ifdef VK_KHR_depth_stencil_resolve
1801 if (rpD->hasDepthStencilResolve) {
1802 startIndex = attRefs2.count();
1803 attRefs2.append({});
1804 VkAttachmentReference2KHR &attref2(attRefs2.last());
1805 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1806 attref2.attachment = rpD->dsResolveRef.attachment;
1807 attref2.layout = rpD->dsResolveRef.layout;
1808 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1809 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1810 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1811 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1812 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1813 addToChain(&subpass2, &dsResolveDesc);
1817#ifdef VK_KHR_fragment_shading_rate
1818 shadingRateAttInfo = {};
1819 if (rpD->hasShadingRateMap) {
1820 startIndex = attRefs2.count();
1821 attRefs2.append({});
1822 VkAttachmentReference2KHR &attref2(attRefs2.last());
1823 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1824 attref2.attachment = rpD->shadingRateRef.attachment;
1825 attref2.layout = rpD->shadingRateRef.layout;
1826 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1827 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1828 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1829 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1830 addToChain(&subpass2, &shadingRateAttInfo);
1836 subpassDeps2.clear();
1837 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1838 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1839 subpassDeps2.append({});
1840 VkSubpassDependency2 &dep2(subpassDeps2.last());
1841 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1842 dep2.srcSubpass = dep.srcSubpass;
1843 dep2.dstSubpass = dep.dstSubpass;
1844 dep2.srcStageMask = dep.srcStageMask;
1845 dep2.dstStageMask = dep.dstStageMask;
1846 dep2.srcAccessMask = dep.srcAccessMask;
1847 dep2.dstAccessMask = dep.dstAccessMask;
1848 dep2.dependencyFlags = dep.dependencyFlags;
1851 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1852 rpInfo2->pNext =
nullptr;
1853 rpInfo2->flags = rpInfo->flags;
1854 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1855 rpInfo2->pAttachments = attDescs2.constData();
1856 rpInfo2->subpassCount = 1;
1857 rpInfo2->pSubpasses = &subpass2;
1858 rpInfo2->dependencyCount = subpassDeps2.count();
1859 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1860 if (multiViewCount >= 2) {
1861 rpInfo2->correlatedViewMaskCount = 1;
1862 rpInfo2->pCorrelatedViewMasks = &viewMask;
1868 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1869 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1870 VkSubpassDescription2KHR subpass2;
1871 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1872#ifdef VK_KHR_depth_stencil_resolve
1873 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1875#ifdef VK_KHR_fragment_shading_rate
1876 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1883 VkSubpassDescription *subpassDesc,
1886 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1887 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1888 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1889 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1890 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1891 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1893 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1894 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1895 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1896 rpInfo->pAttachments = rpD->attDescs.constData();
1897 rpInfo->subpassCount = 1;
1898 rpInfo->pSubpasses = subpassDesc;
1899 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1900 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1904 bool hasDepthStencil,
1905 VkSampleCountFlagBits samples,
1906 VkFormat colorFormat,
1907 QRhiShadingRateMap *shadingRateMap)
1911 VkAttachmentDescription attDesc = {};
1912 attDesc.format = colorFormat;
1913 attDesc.samples = samples;
1914 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1915 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1916 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1917 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1918 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1919 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1920 rpD->attDescs.append(attDesc);
1922 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1927 rpD->multiViewCount = 0;
1929 if (hasDepthStencil) {
1933 attDesc.format = optimalDepthStencilFormat();
1934 attDesc.samples = samples;
1935 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1936 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1937 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1938 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1939 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1940 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1941 rpD->attDescs.append(attDesc);
1943 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1948 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1950 attDesc.format = colorFormat;
1951 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1952 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1953 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1954 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1955 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1956 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1957 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1958 rpD->attDescs.append(attDesc);
1960 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1963 rpD->dsResolveRef = {};
1965 rpD->shadingRateRef = {};
1966#ifdef VK_KHR_fragment_shading_rate
1967 if (shadingRateMap) {
1969 attDesc.format = VK_FORMAT_R8_UINT;
1970 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1971 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1972 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1973 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1974 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1975 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1976 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1977 rpD->attDescs.append(attDesc);
1979 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
1984 VkSubpassDependency subpassDep = {};
1985 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1986 subpassDep.dstSubpass = 0;
1987 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1988 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1989 subpassDep.srcAccessMask = 0;
1990 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1991 rpD->subpassDeps.append(subpassDep);
1992 if (hasDepthStencil) {
1993 memset(&subpassDep, 0,
sizeof(subpassDep));
1994 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1995 subpassDep.dstSubpass = 0;
1996 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1997 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1998 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1999 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2000 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2001 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2002 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2003 rpD->subpassDeps.append(subpassDep);
2006 VkRenderPassCreateInfo rpInfo;
2007 VkSubpassDescription subpassDesc;
2008 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2010#ifdef VK_KHR_create_renderpass2
2011 if (caps.renderPass2KHR) {
2013 VkRenderPassCreateInfo2KHR rpInfo2;
2014 RenderPass2SetupHelper rp2Helper(
this);
2015 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2017 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2018 if (err != VK_SUCCESS) {
2019 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2026 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2027 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2028 if (err != VK_SUCCESS) {
2029 qWarning(
"Failed to create renderpass: %d", err);
2038 const QRhiColorAttachment *colorAttachmentsBegin,
2039 const QRhiColorAttachment *colorAttachmentsEnd,
2043 QRhiRenderBuffer *depthStencilBuffer,
2044 QRhiTexture *depthTexture,
2045 QRhiTexture *depthResolveTexture,
2046 QRhiShadingRateMap *shadingRateMap)
2050 int multiViewCount = 0;
2051 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2054 Q_ASSERT(texD || rbD);
2055 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2056 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2058 VkAttachmentDescription attDesc = {};
2059 attDesc.format = vkformat;
2060 attDesc.samples = samples;
2061 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2062 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2063 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2064 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2066 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2067 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2068 rpD->attDescs.append(attDesc);
2070 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2071 rpD->colorRefs.append(ref);
2073 if (it->multiViewCount() >= 2) {
2074 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2075 qWarning(
"Inconsistent multiViewCount in color attachment set");
2077 multiViewCount = it->multiViewCount();
2078 }
else if (multiViewCount > 0) {
2079 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2082 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2083 rpD->multiViewCount = uint32_t(multiViewCount);
2087 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2088 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2089 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2090 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2091 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2092 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2093 VkAttachmentDescription attDesc = {};
2094 attDesc.format = dsFormat;
2095 attDesc.samples = samples;
2096 attDesc.loadOp = loadOp;
2097 attDesc.storeOp = storeOp;
2098 attDesc.stencilLoadOp = loadOp;
2099 attDesc.stencilStoreOp = storeOp;
2100 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2101 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2102 rpD->attDescs.append(attDesc);
2103 if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
2104 multiViewCount = depthTexture->arraySize();
2105 rpD->multiViewCount = multiViewCount;
2107 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2112 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2113 if (it->resolveTexture()) {
2115 const VkFormat dstFormat = rtexD->vkformat;
2116 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2117 qWarning(
"Resolving into a multisample texture is not supported");
2121 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2122 if (srcFormat != dstFormat) {
2126 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2127 int(srcFormat),
int(dstFormat));
2130 VkAttachmentDescription attDesc = {};
2131 attDesc.format = rtexD->viewFormat;
2132 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2133 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2134 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2135 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2136 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2137 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2138 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2139 rpD->attDescs.append(attDesc);
2141 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2142 rpD->resolveRefs.append(ref);
2144 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2145 rpD->resolveRefs.append(ref);
2148 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2153 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2154 qWarning(
"Resolving into a multisample depth texture is not supported");
2157 if (texD->vkformat != rtexD->vkformat) {
2158 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2159 int(texD->vkformat),
int(rtexD->vkformat));
2162 VkAttachmentDescription attDesc = {};
2163 attDesc.format = rtexD->viewFormat;
2164 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2165 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2166 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2167 attDesc.stencilLoadOp = attDesc.loadOp;
2168 attDesc.stencilStoreOp = attDesc.storeOp;
2169 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2170 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2171 rpD->attDescs.append(attDesc);
2172 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2174 rpD->dsResolveRef = {};
2178 rpD->shadingRateRef = {};
2179#ifdef VK_KHR_fragment_shading_rate
2180 if (shadingRateMap) {
2181 VkAttachmentDescription attDesc = {};
2182 attDesc.format = VK_FORMAT_R8_UINT;
2183 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2184 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2185 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2186 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2187 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2188 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2189 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2190 rpD->attDescs.append(attDesc);
2191 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2196 VkSubpassDependency selfDependency;
2197 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
2198 selfDependency.srcSubpass = 0;
2199 selfDependency.dstSubpass = 0;
2200 selfDependency.srcStageMask = stageMask;
2201 selfDependency.dstStageMask = stageMask;
2202 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2203 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2204#ifdef VK_VERSION_1_1
2205 selfDependency.dependencyFlags = rpD->multiViewCount >= 2 ? VK_DEPENDENCY_VIEW_LOCAL_BIT : 0;
2207 selfDependency.dependencyFlags = 0;
2209 rpD->subpassDeps.append(selfDependency);
2216 VkRenderPassCreateInfo rpInfo;
2217 VkSubpassDescription subpassDesc;
2218 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2221 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2224#ifdef VK_KHR_create_renderpass2
2225 if (caps.renderPass2KHR) {
2227 VkRenderPassCreateInfo2KHR rpInfo2;
2228 RenderPass2SetupHelper rp2Helper(
this);
2229 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2232 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2233 if (err != VK_SUCCESS) {
2234 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2241 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2242 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2245 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2246 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2247 if (err != VK_SUCCESS) {
2248 qWarning(
"Failed to create renderpass: %d", err);
2259 if (swapChainD->pixelSize.isEmpty()) {
2260 qWarning(
"Surface size is 0, cannot create swapchain");
2264 df->vkDeviceWaitIdle(dev);
2266 if (!vkCreateSwapchainKHR) {
2267 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2268 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2269 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2270 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2271 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2272 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2273 qWarning(
"Swapchain functions not available");
2278 VkSurfaceCapabilitiesKHR surfaceCaps;
2279 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2280 quint32 reqBufferCount;
2281 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2282 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2284 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2286 VkSurfaceTransformFlagBitsKHR preTransform =
2287 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2288 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2289 : surfaceCaps.currentTransform;
2315 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2316 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2317 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2318 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2320 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2321 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2322 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2323 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2324 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2325 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2326 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2327 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2328 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2329 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2332 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2333 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2334 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2335 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2337 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2338 && surfaceCaps.maxImageArrayLayers > 1;
2341 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2342 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2346 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2347 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2348 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2349 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2357 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2359 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2360 reuseExisting ?
"recycled" :
"new",
2361 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2363 VkSwapchainCreateInfoKHR swapChainInfo = {};
2364 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2365 swapChainInfo.surface = swapChainD->surface;
2366 swapChainInfo.minImageCount = reqBufferCount;
2367 swapChainInfo.imageFormat = swapChainD->colorFormat;
2368 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2369 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2370 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2371 swapChainInfo.imageUsage = usage;
2372 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2373 swapChainInfo.preTransform = preTransform;
2374 swapChainInfo.compositeAlpha = compositeAlpha;
2375 swapChainInfo.presentMode = presentMode;
2376 swapChainInfo.clipped =
true;
2377 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2379 VkSwapchainKHR newSwapChain;
2380 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2381 if (err != VK_SUCCESS) {
2382 qWarning(
"Failed to create swapchain: %d", err);
2385 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2390 swapChainD->sc = newSwapChain;
2391 swapChainD->lastConnectedSurface = swapChainD->surface;
2393 quint32 actualSwapChainBufferCount = 0;
2394 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2395 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2396 qWarning(
"Failed to get swapchain images: %d", err);
2400 if (actualSwapChainBufferCount != reqBufferCount)
2401 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2404 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2405 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2406 if (err != VK_SUCCESS) {
2407 qWarning(
"Failed to get swapchain images: %d", err);
2411 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2412 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2413 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2414 if (!createTransientImage(swapChainD->colorFormat,
2415 swapChainD->pixelSize,
2416 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2417 VK_IMAGE_ASPECT_COLOR_BIT,
2418 swapChainD->samples,
2419 &swapChainD->msaaImageMem,
2422 swapChainD->bufferCount))
2424 qWarning(
"Failed to create transient image for MSAA color buffer");
2429 VkFenceCreateInfo fenceInfo = {};
2430 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2431 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2434 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2438 image.image = swapChainImages[i];
2439 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2440 image.msaaImage = msaaImages[i];
2441 image.msaaImageView = msaaViews[i];
2444 VkImageViewCreateInfo imgViewInfo = {};
2445 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2446 imgViewInfo.image = swapChainImages[i];
2447 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2448 imgViewInfo.format = swapChainD->colorFormat;
2449 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2450 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2451 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2452 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2453 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2454 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2455 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2456 if (err != VK_SUCCESS) {
2457 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2463 VkSemaphoreCreateInfo semInfo = {};
2464 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2465 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2470 image.image = swapChainImages[i];
2471 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2472 image.msaaImage = msaaImages[i];
2473 image.msaaImageView = msaaViews[i];
2476 VkImageViewCreateInfo imgViewInfo = {};
2477 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2478 imgViewInfo.image = swapChainImages[i];
2479 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2480 imgViewInfo.format = swapChainD->colorFormat;
2481 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2482 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2483 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2484 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2485 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2486 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2487 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2488 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2489 if (err != VK_SUCCESS) {
2490 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2494 VkSemaphoreCreateInfo semInfo = {};
2495 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2496 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2502 swapChainD->currentImageIndex = 0;
2504 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2506 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2507 VkImageViewCreateInfo viewInfo = {};
2508 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2509 viewInfo.image = texD->image;
2510 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2511 viewInfo.format = texD->viewFormat;
2512 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2513 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2514 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2515 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2516 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2517 viewInfo.subresourceRange.baseMipLevel = 0;
2518 viewInfo.subresourceRange.levelCount = 1;
2519 viewInfo.subresourceRange.baseArrayLayer = 0;
2520 viewInfo.subresourceRange.layerCount = 1;
2521 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2522 if (err != VK_SUCCESS) {
2523 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2528 VkSemaphoreCreateInfo semInfo = {};
2529 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2537 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2539 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2540 if (err != VK_SUCCESS) {
2541 qWarning(
"Failed to create command buffer fence: %d", err);
2547 swapChainD->currentFrameSlot = 0;
2556 if (swapChainD->sc == VK_NULL_HANDLE)
2560 df->vkDeviceWaitIdle(dev);
2564 if (frame.cmdFence) {
2566 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2567 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2568 frame.cmdFence = VK_NULL_HANDLE;
2571 if (frame.imageSem) {
2572 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2573 frame.imageSem = VK_NULL_HANDLE;
2580 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2581 image.fb = VK_NULL_HANDLE;
2583 if (image.imageView) {
2584 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2585 image.imageView = VK_NULL_HANDLE;
2587 if (image.msaaImageView) {
2588 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2589 image.msaaImageView = VK_NULL_HANDLE;
2591 if (image.msaaImage) {
2592 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2593 image.msaaImage = VK_NULL_HANDLE;
2595 if (image.drawSem) {
2596 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2597 image.drawSem = VK_NULL_HANDLE;
2601 if (swapChainD->msaaImageMem) {
2602 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2603 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2606 if (swapChainD->shadingRateMapView) {
2607 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2608 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2611 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2612 swapChainD->sc = VK_NULL_HANDLE;
2619 VkCommandPoolResetFlags flags = 0;
2624 if (releaseCachedResourcesCalledBeforeFrameStart)
2625 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2628 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2634 for (quint64 i = 0; i < timestampValidBits; i += 8)
2635 mask |= 0xFFULL << i;
2636 const quint64 ts0 = timestamp[0] & mask;
2637 const quint64 ts1 = timestamp[1] & mask;
2638 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2639 if (!qFuzzyIsNull(nsecsPerTick)) {
2640 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2641 const double elapsedSec = elapsedMs / 1000.0;
2652 const int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2655 inst->handle()->beginFrame(swapChainD->window);
2665 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2666 if (waitResult != QRhi::FrameOpSuccess)
2671 uint32_t imageIndex = 0;
2672 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2673 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2675 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2676 swapChainD->currentImageIndex = imageIndex;
2679 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2680 return QRhi::FrameOpSwapChainOutOfDate;
2682 if (err == VK_ERROR_DEVICE_LOST) {
2683 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2684 printExtraErrorInfo(err);
2686 return QRhi::FrameOpDeviceLost;
2688 qWarning(
"Failed to acquire next swapchain image: %d", err);
2689 return QRhi::FrameOpError;
2693 currentFrameSlot =
int(swapChainD->currentFrameSlot);
2696 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2702 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2703 if (cbres != QRhi::FrameOpSuccess)
2706 swapChainD->cbWrapper.cb = frame.cmdBuf;
2709 swapChainD->rtWrapper.d.fb = image.fb;
2713 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2714 swapChainD->rtWrapperRight.d.fb = image.fb;
2721 quint64 timestamp[2] = { 0, 0 };
2722 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2723 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2724 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2725 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2727 if (err == VK_SUCCESS) {
2729 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2731 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2733 qWarning(
"Failed to query timestamp: %d", err);
2738 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2739 int timestampQueryIdx = -1;
2740 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2741 if (!timestampQueryPoolMap.testBit(i)) {
2742 timestampQueryPoolMap.setBit(i);
2743 timestampQueryIdx = i * 2;
2747 if (timestampQueryIdx >= 0) {
2748 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2750 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2751 timestampQueryPool, uint32_t(timestampQueryIdx));
2756 return QRhi::FrameOpSuccess;
2764 auto cleanup = qScopeGuard([
this, swapChainD] {
2765 inst->handle()->endFrame(swapChainD->window);
2770 int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2775 VkImageMemoryBarrier presTrans = {};
2776 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2777 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2778 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2779 presTrans.image = image.image;
2780 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2781 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2785 presTrans.srcAccessMask = 0;
2786 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2787 df->vkCmdPipelineBarrier(frame.cmdBuf,
2788 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2789 0, 0,
nullptr, 0,
nullptr,
2793 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2794 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2795 df->vkCmdPipelineBarrier(frame.cmdBuf,
2796 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2797 0, 0,
nullptr, 0,
nullptr,
2805 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2811 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2812 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2814 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2815 needsPresent ? &image.drawSem :
nullptr);
2816 if (submitres != QRhi::FrameOpSuccess)
2824 VkPresentInfoKHR presInfo = {};
2825 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2826 presInfo.swapchainCount = 1;
2827 presInfo.pSwapchains = &swapChainD->sc;
2828 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2829 waitSemaphoresForPresent.append(image.drawSem);
2830 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2831 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2835 inst->presentAboutToBeQueued(swapChainD->window);
2837 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2838 waitSemaphoresForPresent.clear();
2839 if (err != VK_SUCCESS) {
2840 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2841 return QRhi::FrameOpSwapChainOutOfDate;
2842 }
else if (err != VK_SUBOPTIMAL_KHR) {
2843 if (err == VK_ERROR_DEVICE_LOST) {
2844 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2845 printExtraErrorInfo(err);
2847 return QRhi::FrameOpDeviceLost;
2849 qWarning(
"Failed to present: %d", err);
2850 return QRhi::FrameOpError;
2856 inst->presentQueued(swapChainD->window);
2866 return QRhi::FrameOpSuccess;
2885 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2895 VkCommandBufferAllocateInfo cmdBufInfo = {};
2896 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2897 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2898 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2899 cmdBufInfo.commandBufferCount = 1;
2901 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2902 if (err != VK_SUCCESS) {
2903 if (err == VK_ERROR_DEVICE_LOST) {
2904 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2905 printExtraErrorInfo(err);
2907 return QRhi::FrameOpDeviceLost;
2909 qWarning(
"Failed to allocate frame command buffer: %d", err);
2910 return QRhi::FrameOpError;
2914 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2915 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2917 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2918 if (err != VK_SUCCESS) {
2919 if (err == VK_ERROR_DEVICE_LOST) {
2920 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2921 printExtraErrorInfo(err);
2923 return QRhi::FrameOpDeviceLost;
2925 qWarning(
"Failed to begin frame command buffer: %d", err);
2926 return QRhi::FrameOpError;
2929 return QRhi::FrameOpSuccess;
2933 VkSemaphore *waitSem, VkSemaphore *signalSem)
2935 VkResult err =
df->vkEndCommandBuffer(cb);
2936 if (err != VK_SUCCESS) {
2937 if (err == VK_ERROR_DEVICE_LOST) {
2938 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2939 printExtraErrorInfo(err);
2941 return QRhi::FrameOpDeviceLost;
2943 qWarning(
"Failed to end frame command buffer: %d", err);
2944 return QRhi::FrameOpError;
2947 VkSubmitInfo submitInfo = {};
2948 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2949 submitInfo.commandBufferCount = 1;
2950 submitInfo.pCommandBuffers = &cb;
2953 waitSemaphoresForQueueSubmit.append(*waitSem);
2955 signalSemaphoresForQueueSubmit.append(*signalSem);
2957 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2958 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2959 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2960 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2961 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2963 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
2964 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
2965 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
2968 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
2970 waitSemaphoresForQueueSubmit.clear();
2971 signalSemaphoresForQueueSubmit.clear();
2973 if (err != VK_SUCCESS) {
2974 if (err == VK_ERROR_DEVICE_LOST) {
2975 qWarning(
"Device loss detected in vkQueueSubmit()");
2976 printExtraErrorInfo(err);
2978 return QRhi::FrameOpDeviceLost;
2980 qWarning(
"Failed to submit to graphics queue: %d", err);
2981 return QRhi::FrameOpError;
2984 return QRhi::FrameOpSuccess;
2989 for (QVkSwapChain *sc : std::as_const(swapchains)) {
2990 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
2991 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
2992 if (frame.cmdFenceWaitable) {
2993 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2995 if (err != VK_SUCCESS) {
2996 if (err == VK_ERROR_DEVICE_LOST) {
2997 qWarning(
"Device loss detected in vkWaitForFences()");
2998 printExtraErrorInfo(err);
3000 return QRhi::FrameOpDeviceLost;
3002 qWarning(
"Failed to wait for fence: %d", err);
3003 return QRhi::FrameOpError;
3006 df->vkResetFences(dev, 1, &frame.cmdFence);
3007 frame.cmdFenceWaitable =
false;
3011 return QRhi::FrameOpSuccess;
3025 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3027 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3028 if (waitResult != QRhi::FrameOpSuccess)
3034 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3035 if (cbres != QRhi::FrameOpSuccess)
3041 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3042 int timestampQueryIdx = -1;
3043 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3044 if (!timestampQueryPoolMap.testBit(i)) {
3045 timestampQueryPoolMap.setBit(i);
3046 timestampQueryIdx = i * 2;
3050 if (timestampQueryIdx >= 0) {
3051 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3053 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3054 timestampQueryPool, uint32_t(timestampQueryIdx));
3055 ofr.timestampQueryIndex = timestampQueryIdx;
3060 return QRhi::FrameOpSuccess;
3066 Q_ASSERT(ofr.active);
3073 if (ofr.timestampQueryIndex >= 0) {
3074 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3075 timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
3078 if (!ofr.cmdFence) {
3079 VkFenceCreateInfo fenceInfo = {};
3080 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3081 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence);
3082 if (err != VK_SUCCESS) {
3083 qWarning(
"Failed to create command buffer fence: %d", err);
3084 return QRhi::FrameOpError;
3088 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence,
nullptr,
nullptr);
3089 if (submitres != QRhi::FrameOpSuccess)
3093 df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
3094 df->vkResetFences(dev, 1, &ofr.cmdFence);
3101 if (ofr.timestampQueryIndex >= 0) {
3102 quint64 timestamp[2] = { 0, 0 };
3103 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
3104 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3105 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3106 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
3107 ofr.timestampQueryIndex = -1;
3108 if (err == VK_SUCCESS) {
3110 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3114 qWarning(
"Failed to query timestamp: %d", err);
3118 return QRhi::FrameOpSuccess;
3140 swapChainD->cbWrapper.resetCommands();
3141 cb = swapChainD->cbWrapper.cb;
3143 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3144 if (submitres != QRhi::FrameOpSuccess)
3148 df->vkQueueWaitIdle(gfxQueue);
3155 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3158 startPrimaryCommandBuffer(&frame.cmdBuf);
3159 swapChainD->cbWrapper.cb = frame.cmdBuf;
3166 return QRhi::FrameOpSuccess;
3173 u
.access =
int(bufUsage.access);
3174 u
.stage =
int(bufUsage.stage);
3182 u
.access =
int(texUsage.access);
3183 u
.stage =
int(texUsage.stage);
3189 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3192 rtD->lastActiveFrameSlot = currentFrameSlot;
3193 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3195 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3203 texD->lastActiveFrameSlot = currentFrameSlot;
3208 rbD->lastActiveFrameSlot = currentFrameSlot;
3214 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3217 if (rtD->m_desc.depthStencilBuffer()) {
3219 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3226 rbD->lastActiveFrameSlot = currentFrameSlot;
3228 if (rtD->m_desc.depthTexture()) {
3233 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3235 if (rtD->m_desc.depthResolveTexture()) {
3240 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3242 if (rtD->m_desc.shadingRateMap()) {
3247 texD->lastActiveFrameSlot = currentFrameSlot;
3261 VkCommandBuffer secondaryCb;
3263 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3264 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3265 freeSecondaryCbs[currentFrameSlot].removeLast();
3267 VkCommandBufferAllocateInfo cmdBufInfo = {};
3268 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3269 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3270 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3271 cmdBufInfo.commandBufferCount = 1;
3273 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3274 if (err != VK_SUCCESS) {
3275 qWarning(
"Failed to create secondary command buffer: %d", err);
3276 return VK_NULL_HANDLE;
3280 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3281 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3282 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3283 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3284 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3285 cmdBufInheritInfo.subpass = 0;
3287 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3288 cmdBufInheritInfo.framebuffer = rtD->fb;
3290 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3292 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3293 if (err != VK_SUCCESS) {
3294 qWarning(
"Failed to begin secondary command buffer: %d", err);
3295 return VK_NULL_HANDLE;
3303 VkResult err =
df->vkEndCommandBuffer(cb);
3304 if (err != VK_SUCCESS)
3305 qWarning(
"Failed to end secondary command buffer: %d", err);
3309 cmd.args.executeSecondary.cb = cb;
3313 e.lastActiveFrameSlot = currentFrameSlot;
3314 e.secondaryCommandBuffer.cb = cb;
3315 releaseQueue.append(e);
3319 QRhiRenderTarget *rt,
3320 const QColor &colorClearValue,
3321 const QRhiDepthStencilClearValue &depthStencilClearValue,
3322 QRhiResourceUpdateBatch *resourceUpdates,
3323 QRhiCommandBuffer::BeginPassFlags flags)
3328 if (resourceUpdates)
3338 switch (rt->resourceType()) {
3339 case QRhiResource::SwapChainRenderTarget:
3341 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3351 texD->lastActiveFrameSlot = currentFrameSlot;
3354 case QRhiResource::TextureRenderTarget:
3368 cbD->currentTarget = rt;
3373 VkRenderPassBeginInfo rpBeginInfo = {};
3374 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3375 rpBeginInfo.renderPass = rtD
->rp->rp;
3376 rpBeginInfo.framebuffer = rtD->fb;
3377 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3378 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3380 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3381 [](
const VkAttachmentDescription &attDesc) {
3382 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3383 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3386 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3387 if (rpHasAnyClearOp) {
3390 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3391 colorClearValue.alphaF() } };
3396 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3401 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3402 colorClearValue.alphaF() } };
3407 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3412 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3416 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3417 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3421 cmd.args.beginRenderPass.desc = rpBeginInfo;
3422 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3424 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3427 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3432 rateCmd.args.setShadingRate.w = 1;
3433 rateCmd.args.setShadingRate.h = 1;
3445 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3446 cbD->activeSecondaryCbStack.removeLast();
3447 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3454 cbD->currentTarget =
nullptr;
3456 if (resourceUpdates)
3461 QRhiResourceUpdateBatch *resourceUpdates,
3462 QRhiCommandBuffer::BeginPassFlags flags)
3467 if (resourceUpdates)
3475 cbD->computePassState.reset();
3478 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3489 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3490 cbD->activeSecondaryCbStack.removeLast();
3491 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3496 if (resourceUpdates)
3503 Q_ASSERT(psD->pipeline);
3507 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3509 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3513 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3514 cmd.args.bindPipeline.pipeline = psD->pipeline;
3517 cbD->currentGraphicsPipeline =
nullptr;
3518 cbD->currentComputePipeline = ps;
3519 cbD->currentPipelineGeneration = psD->generation;
3522 psD->lastActiveFrameSlot = currentFrameSlot;
3527 QRhiShaderResourceBinding::Type bindingType,
3528 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3530 VkAccessFlags access = 0;
3531 if (bindingType == loadTypeVal) {
3532 access = VK_ACCESS_SHADER_READ_BIT;
3534 access = VK_ACCESS_SHADER_WRITE_BIT;
3535 if (bindingType == loadStoreTypeVal)
3536 access |= VK_ACCESS_SHADER_READ_BIT;
3538 auto it = writtenResources->find(resource);
3539 if (it != writtenResources->end())
3540 it->second.accessFlags |= access;
3541 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3542 writtenResources->insert(resource, { access,
true });
3552 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3553 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3554 if (cbD->currentComputeSrb) {
3558 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3559 accessAndIsNewFlag = { 0,
false };
3562 for (
auto &binding : srbD->m_bindings) {
3563 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3565 case QRhiShaderResourceBinding::ImageLoad:
3566 case QRhiShaderResourceBinding::ImageStore:
3567 case QRhiShaderResourceBinding::ImageLoadStore:
3568 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3571 QRhiShaderResourceBinding::ImageLoad,
3572 QRhiShaderResourceBinding::ImageStore,
3573 QRhiShaderResourceBinding::ImageLoadStore);
3575 case QRhiShaderResourceBinding::BufferLoad:
3576 case QRhiShaderResourceBinding::BufferStore:
3577 case QRhiShaderResourceBinding::BufferLoadStore:
3578 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3581 QRhiShaderResourceBinding::BufferLoad,
3582 QRhiShaderResourceBinding::BufferStore,
3583 QRhiShaderResourceBinding::BufferLoadStore);
3590 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3591 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3592 const bool isNewInThisDispatch = it->second.isNew;
3593 if (accessInThisDispatch && !isNewInThisDispatch) {
3594 if (it.key()->resourceType() == QRhiResource::Texture) {
3596 VkImageMemoryBarrier barrier = {};
3597 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3598 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3600 barrier.subresourceRange.baseMipLevel = 0;
3601 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3602 barrier.subresourceRange.baseArrayLayer = 0;
3603 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3604 barrier.oldLayout = texD->usageState.layout;
3605 barrier.newLayout = texD->usageState.layout;
3606 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3607 barrier.dstAccessMask = accessInThisDispatch;
3608 barrier.image = texD->image;
3609 imageBarriers.append(barrier);
3612 VkBufferMemoryBarrier barrier = {};
3613 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3614 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3615 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3616 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3617 barrier.dstAccessMask = accessInThisDispatch;
3618 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3619 barrier.size = VK_WHOLE_SIZE;
3620 bufferBarriers.append(barrier);
3626 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3627 it = cbD->computePassState.writtenResources.erase(it);
3634 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3635 if (!imageBarriers.isEmpty()) {
3636 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3639 imageBarriers.size(), imageBarriers.constData());
3641 if (!bufferBarriers.isEmpty()) {
3642 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3644 bufferBarriers.size(), bufferBarriers.constData(),
3647 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3649 if (!imageBarriers.isEmpty()) {
3652 cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3653 cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3654 cmd.args.imageBarrier.count = imageBarriers.size();
3655 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3656 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3658 if (!bufferBarriers.isEmpty()) {
3661 cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3662 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3663 cmd.args.bufferBarrier.count = bufferBarriers.size();
3664 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3665 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3669 cmd.args.dispatch.x = x;
3670 cmd.args.dispatch.y = y;
3671 cmd.args.dispatch.z = z;
3677 VkShaderModuleCreateInfo shaderInfo = {};
3678 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3679 shaderInfo.codeSize = size_t(spirv.size());
3680 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3681 VkShaderModule shaderModule;
3682 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3683 if (err != VK_SUCCESS) {
3684 qWarning(
"Failed to create shader module: %d", err);
3685 return VK_NULL_HANDLE;
3687 return shaderModule;
3695 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3696 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3697 pipelineCacheInfo.initialDataSize = initialDataSize;
3698 pipelineCacheInfo.pInitialData = initialData;
3699 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3700 if (err != VK_SUCCESS) {
3701 qWarning(
"Failed to create pipeline cache: %d", err);
3711 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3712 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3713 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3714 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3715 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3717 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3718 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3721 VkWriteDescriptorSet writeInfo = {};
3722 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3723 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3724 writeInfo.dstBinding = uint32_t(b->binding);
3725 writeInfo.descriptorCount = 1;
3727 int bufferInfoIndex = -1;
3728 int imageInfoIndex = -1;
3731 case QRhiShaderResourceBinding::UniformBuffer:
3733 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3734 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3735 QRhiBuffer *buf = b->u.ubuf.buf;
3737 bd.ubuf.id = bufD->m_id;
3738 bd.ubuf.generation = bufD->generation;
3739 VkDescriptorBufferInfo bufInfo;
3740 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3741 bufInfo.offset = b->u.ubuf.offset;
3742 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3744 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3745 bufferInfoIndex = bufferInfos.size();
3746 bufferInfos.append(bufInfo);
3749 case QRhiShaderResourceBinding::SampledTexture:
3751 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3752 writeInfo.descriptorCount = data->count;
3753 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3754 ArrayOfImageDesc imageInfo(data->count);
3755 for (
int elem = 0; elem < data->count; ++elem) {
3758 bd.stex.d[elem].texId = texD->m_id;
3759 bd.stex.d[elem].texGeneration = texD->generation;
3760 bd.stex.d[elem].samplerId = samplerD->m_id;
3761 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3762 imageInfo[elem].sampler = samplerD->sampler;
3763 imageInfo[elem].imageView = texD->imageView;
3764 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3766 bd.stex.count = data->count;
3767 imageInfoIndex = imageInfos.size();
3768 imageInfos.append(imageInfo);
3771 case QRhiShaderResourceBinding::Texture:
3773 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3774 writeInfo.descriptorCount = data->count;
3775 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3776 ArrayOfImageDesc imageInfo(data->count);
3777 for (
int elem = 0; elem < data->count; ++elem) {
3779 bd.stex.d[elem].texId = texD->m_id;
3780 bd.stex.d[elem].texGeneration = texD->generation;
3781 bd.stex.d[elem].samplerId = 0;
3782 bd.stex.d[elem].samplerGeneration = 0;
3783 imageInfo[elem].sampler = VK_NULL_HANDLE;
3784 imageInfo[elem].imageView = texD->imageView;
3785 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3787 bd.stex.count = data->count;
3788 imageInfoIndex = imageInfos.size();
3789 imageInfos.append(imageInfo);
3792 case QRhiShaderResourceBinding::Sampler:
3795 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3796 bd.stex.d[0].texId = 0;
3797 bd.stex.d[0].texGeneration = 0;
3798 bd.stex.d[0].samplerId = samplerD->m_id;
3799 bd.stex.d[0].samplerGeneration = samplerD->generation;
3800 ArrayOfImageDesc imageInfo(1);
3801 imageInfo[0].sampler = samplerD->sampler;
3802 imageInfo[0].imageView = VK_NULL_HANDLE;
3803 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3804 imageInfoIndex = imageInfos.size();
3805 imageInfos.append(imageInfo);
3808 case QRhiShaderResourceBinding::ImageLoad:
3809 case QRhiShaderResourceBinding::ImageStore:
3810 case QRhiShaderResourceBinding::ImageLoadStore:
3813 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3815 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3816 bd.simage.id = texD->m_id;
3817 bd.simage.generation = texD->generation;
3818 ArrayOfImageDesc imageInfo(1);
3819 imageInfo[0].sampler = VK_NULL_HANDLE;
3820 imageInfo[0].imageView = view;
3821 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3822 imageInfoIndex = imageInfos.size();
3823 imageInfos.append(imageInfo);
3827 case QRhiShaderResourceBinding::BufferLoad:
3828 case QRhiShaderResourceBinding::BufferStore:
3829 case QRhiShaderResourceBinding::BufferLoadStore:
3832 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3833 bd.sbuf.id = bufD->m_id;
3834 bd.sbuf.generation = bufD->generation;
3835 VkDescriptorBufferInfo bufInfo;
3836 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3837 bufInfo.offset = b->u.sbuf.offset;
3838 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3839 bufferInfoIndex = bufferInfos.size();
3840 bufferInfos.append(bufInfo);
3847 writeInfos.append(writeInfo);
3848 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3851 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3852 const int bufferInfoIndex = infoIndices[i].first;
3853 const int imageInfoIndex = infoIndices[i].second;
3854 if (bufferInfoIndex >= 0)
3855 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3856 else if (imageInfoIndex >= 0)
3857 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3860 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3865 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3866 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3867 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3868 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3869 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3870 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3874 VkAccessFlags access, VkPipelineStageFlags stage)
3877 Q_ASSERT(access && stage);
3885 if (s.access == access && s.stage == stage) {
3888 if (!accessIsWrite(access))
3892 VkBufferMemoryBarrier bufMemBarrier = {};
3893 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3894 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3895 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3896 bufMemBarrier.srcAccessMask = s.access;
3897 bufMemBarrier.dstAccessMask = access;
3898 bufMemBarrier.buffer = bufD->buffers[slot];
3899 bufMemBarrier.size = VK_WHOLE_SIZE;
3903 cmd.args.bufferBarrier.srcStageMask = s.stage;
3904 cmd.args.bufferBarrier.dstStageMask = stage;
3905 cmd.args.bufferBarrier.count = 1;
3906 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3907 cbD->pools.bufferBarrier.append(bufMemBarrier);
3914 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3917 Q_ASSERT(layout && access && stage);
3919 if (s.access == access && s.stage == stage && s.layout == layout) {
3920 if (!accessIsWrite(access))
3924 VkImageMemoryBarrier barrier = {};
3925 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3926 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3927 barrier.subresourceRange.baseMipLevel = 0;
3928 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3929 barrier.subresourceRange.baseArrayLayer = 0;
3930 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3931 barrier.oldLayout = s.layout;
3932 barrier.newLayout = layout;
3933 barrier.srcAccessMask = s.access;
3934 barrier.dstAccessMask = access;
3935 barrier.image = texD->image;
3937 VkPipelineStageFlags srcStage = s.stage;
3940 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3944 cmd.args.imageBarrier.srcStageMask = srcStage;
3945 cmd.args.imageBarrier.dstStageMask = stage;
3946 cmd.args.imageBarrier.count = 1;
3947 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3948 cbD->pools.imageBarrier.append(barrier);
3959 VkImageMemoryBarrier barrier = {};
3960 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3961 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
3962 barrier.subresourceRange.baseMipLevel = 0;
3963 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3964 barrier.subresourceRange.baseArrayLayer = 0;
3965 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3966 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3967 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
3968 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3969 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
3970 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3971 barrier.image = rbD->image;
3973 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
3974 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
3978 cmd.args.imageBarrier.srcStageMask = stages;
3979 cmd.args.imageBarrier.dstStageMask = stages;
3980 cmd.args.imageBarrier.count = 1;
3981 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3982 cbD->pools.imageBarrier.append(barrier);
3986 VkImageLayout oldLayout, VkImageLayout newLayout,
3987 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
3988 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
3989 int startLayer,
int layerCount,
3990 int startLevel,
int levelCount)
3993 VkImageMemoryBarrier barrier = {};
3994 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3995 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3996 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
3997 barrier.subresourceRange.levelCount = uint32_t(levelCount);
3998 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
3999 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4000 barrier.oldLayout = oldLayout;
4001 barrier.newLayout = newLayout;
4002 barrier.srcAccessMask = srcAccess;
4003 barrier.dstAccessMask = dstAccess;
4004 barrier.image = image;
4008 cmd.args.imageBarrier.srcStageMask = srcStage;
4009 cmd.args.imageBarrier.dstStageMask = dstStage;
4010 cmd.args.imageBarrier.count = 1;
4011 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4012 cbD->pools.imageBarrier.append(barrier);
4017 VkDeviceSize size = 0;
4018 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4019 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4020 if (imageSizeBytes > 0)
4021 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4026 const QRhiTextureSubresourceUploadDescription &subresDesc,
4027 size_t *curOfs,
void *mp,
4028 BufferImageCopyList *copyInfos)
4030 qsizetype copySizeBytes = 0;
4031 qsizetype imageSizeBytes = 0;
4032 const void *src =
nullptr;
4033 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4034 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4036 VkBufferImageCopy copyInfo = {};
4037 copyInfo.bufferOffset = *curOfs;
4038 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4039 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4040 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4041 copyInfo.imageSubresource.layerCount = 1;
4042 copyInfo.imageExtent.depth = 1;
4044 copyInfo.imageOffset.z = uint32_t(layer);
4046 copyInfo.imageOffset.y = uint32_t(layer);
4048 const QByteArray rawData = subresDesc.data();
4049 const QPoint dp = subresDesc.destinationTopLeft();
4050 QImage image = subresDesc.image();
4051 if (!image.isNull()) {
4052 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4053 QSize size = image.size();
4054 src = image.constBits();
4057 int bpc = qMax(1, image.depth() / 8);
4059 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4060 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4061 const int sx = subresDesc.sourceTopLeft().x();
4062 const int sy = subresDesc.sourceTopLeft().y();
4063 if (!subresDesc.sourceSize().isEmpty())
4064 size = subresDesc.sourceSize();
4065 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4066 if (size.width() == image.width()) {
4069 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4070 copySizeBytes = size.height() * image.bytesPerLine();
4072 image = image.copy(sx, sy, size.width(), size.height());
4073 src = image.constBits();
4076 copySizeBytes = image.sizeInBytes();
4077 bpc = qMax(1, image.depth() / 8);
4078 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4081 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4083 copyInfo.imageOffset.x = dp.x();
4084 copyInfo.imageOffset.y = dp.y();
4085 copyInfo.imageExtent.width = uint32_t(size.width());
4086 copyInfo.imageExtent.height = uint32_t(size.height());
4087 copyInfos->append(copyInfo);
4088 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4089 copySizeBytes = imageSizeBytes = rawData.size();
4090 src = rawData.constData();
4091 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4092 const int subresw = size.width();
4093 const int subresh = size.height();
4094 if (!subresDesc.sourceSize().isEmpty())
4095 size = subresDesc.sourceSize();
4096 const int w = size.width();
4097 const int h = size.height();
4099 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4101 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4102 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4105 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4106 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4107 copyInfos->append(copyInfo);
4108 }
else if (!rawData.isEmpty()) {
4109 copySizeBytes = imageSizeBytes = rawData.size();
4110 src = rawData.constData();
4111 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4112 if (subresDesc.dataStride()) {
4113 quint32 bytesPerPixel = 0;
4114 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4116 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4118 if (!subresDesc.sourceSize().isEmpty())
4119 size = subresDesc.sourceSize();
4120 copyInfo.imageOffset.x = dp.x();
4121 copyInfo.imageOffset.y = dp.y();
4122 copyInfo.imageExtent.width = uint32_t(size.width());
4123 copyInfo.imageExtent.height = uint32_t(size.height());
4124 copyInfos->append(copyInfo);
4126 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4130 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4131 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4137 if (err == VK_ERROR_DEVICE_LOST)
4139 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4140 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4145#ifdef VK_EXT_device_fault
4146 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4149 VkDeviceFaultCountsEXT faultCounts{};
4150 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4151 faultCounts.pNext =
nullptr;
4153 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4154 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4155 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4158 faultCounts.vendorBinarySize = 0;
4160 QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
4161 addressInfos.resize(faultCounts.addressInfoCount);
4163 QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
4164 vendorInfos.resize(faultCounts.vendorInfoCount);
4166 VkDeviceFaultInfoEXT info{};
4167 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4168 info.pNext =
nullptr;
4169 info.pAddressInfos = addressInfos.isEmpty() ?
nullptr : addressInfos.data();
4170 info.pVendorInfos = vendorInfos.isEmpty() ?
nullptr : vendorInfos.data();
4171 info.pVendorBinaryData =
nullptr;
4173 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4174 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4175 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4179 const char *desc = info.description[0] ? info.description :
"n/a";
4180 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4181 faultCounts.addressInfoCount,
4182 faultCounts.vendorInfoCount,
4183 (
unsigned long long)faultCounts.vendorBinarySize,
4186 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4187 const auto &a = addressInfos[i];
4188 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4190 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4191 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4192 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4193 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4194 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4195 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4196 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4197 default:
return "UNKNOWN";
4200 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4202 addressTypeString(a.addressType),
4203 (
unsigned long long)a.reportedAddress,
4204 (
unsigned long long)a.addressPrecision);
4207 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4208 const auto &v = vendorInfos[i];
4209 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4211 (
unsigned long long)v.vendorFaultCode,
4212 (
unsigned long long)v.vendorFaultData,
4226 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4228 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4229 bufD->pendingDynamicUpdates[i].clear();
4230 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4234 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4235 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4237 if (!bufD->stagingBuffers[currentFrameSlot]) {
4238 VkBufferCreateInfo bufferInfo = {};
4239 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4242 bufferInfo.size = bufD->m_size;
4243 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4245 VmaAllocationCreateInfo allocInfo = {};
4246 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4248 VmaAllocation allocation;
4249 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4250 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4251 if (err == VK_SUCCESS) {
4252 bufD->stagingAllocations[currentFrameSlot] = allocation;
4253 setAllocationName(allocation, bufD->name());
4255 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4256 printExtraErrorInfo(err);
4261 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4262 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4263 u.offset, u
.data.size());
4264 if (err != VK_SUCCESS) {
4265 qWarning(
"Failed to copy memory to buffer: %d", err);
4269 trackedBufferBarrier(cbD, bufD, 0,
4270 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4272 VkBufferCopy copyInfo = {};
4273 copyInfo.srcOffset = u.offset;
4274 copyInfo.dstOffset = u.offset;
4275 copyInfo.size = u
.data.size();
4279 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4280 cmd.args.copyBuffer.dst = bufD->buffers[0];
4281 cmd.args.copyBuffer.desc = copyInfo;
4290 bufD->lastActiveFrameSlot = currentFrameSlot;
4292 if (bufD->m_type == QRhiBuffer::Immutable) {
4295 e.lastActiveFrameSlot = currentFrameSlot;
4296 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4297 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4298 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4299 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4300 releaseQueue.append(e);
4304 if (bufD->m_type == QRhiBuffer::Dynamic) {
4306 u.result->data.resizeForOverwrite(u.readSize);
4307 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4308 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4309 u.offset, u.result->data.data(), u.readSize);
4310 if (err != VK_SUCCESS) {
4311 qWarning(
"Failed to copy memory from buffer: %d", err);
4312 u.result->data.clear();
4314 if (u.result->completed)
4315 u.result->completed();
4324 readback.activeFrameSlot = currentFrameSlot;
4325 readback.result = u.result;
4326 readback.byteSize = u.readSize;
4328 VkBufferCreateInfo bufferInfo = {};
4329 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4330 bufferInfo.size = readback.byteSize;
4331 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4333 VmaAllocationCreateInfo allocInfo = {};
4334 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4336 VmaAllocation allocation;
4337 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4338 if (err == VK_SUCCESS) {
4340 setAllocationName(allocation, bufD->name());
4342 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4343 printExtraErrorInfo(err);
4347 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4349 VkBufferCopy copyInfo = {};
4350 copyInfo.srcOffset = u.offset;
4351 copyInfo.size = u.readSize;
4355 cmd.args.copyBuffer.src = bufD->buffers[0];
4356 cmd.args.copyBuffer.dst = readback.stagingBuf;
4357 cmd.args.copyBuffer.desc = copyInfo;
4359 bufD->lastActiveFrameSlot = currentFrameSlot;
4361 activeBufferReadbacks.append(readback);
4371 VkDeviceSize stagingSize = 0;
4372 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4373 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4374 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4375 stagingSize += subresUploadByteSize(subresDesc);
4379 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4380 VkBufferCreateInfo bufferInfo = {};
4381 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4382 bufferInfo.size = stagingSize;
4383 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4385 VmaAllocationCreateInfo allocInfo = {};
4386 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4388 VmaAllocation allocation;
4389 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4390 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4391 if (err != VK_SUCCESS) {
4392 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4393 printExtraErrorInfo(err);
4396 utexD->stagingAllocations[currentFrameSlot] = allocation;
4397 setAllocationName(allocation, utexD->name());
4399 BufferImageCopyList copyInfos;
4402 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4403 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4404 if (err != VK_SUCCESS) {
4405 qWarning(
"Failed to map image data: %d", err);
4409 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4410 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4411 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4414 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4415 prepareUploadSubres(utexD, layer, level,
4416 subresDesc, &curOfs, mp, ©Infos);
4420 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4421 vmaUnmapMemory(toVmaAllocator(allocator), a);
4423 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4424 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4428 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4429 cmd.args.copyBufferToImage.dst = utexD->image;
4430 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4431 cmd.args.copyBufferToImage.count = copyInfos.size();
4432 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4433 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4438 e.lastActiveFrameSlot = currentFrameSlot;
4439 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4440 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4441 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4442 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4443 releaseQueue.append(e);
4448 utexD->lastActiveFrameSlot = currentFrameSlot;
4452 qWarning(
"Texture copy with matching source and destination is not supported");
4457 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4458 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4460 VkImageCopy region = {};
4461 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4462 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4463 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4464 region.srcSubresource.layerCount = 1;
4466 region.srcOffset.x = u.desc.sourceTopLeft().x();
4467 region.srcOffset.y = u.desc.sourceTopLeft().y();
4469 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4471 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4472 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4473 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4474 region.dstSubresource.layerCount = 1;
4476 region.dstOffset.x = u.desc.destinationTopLeft().x();
4477 region.dstOffset.y = u.desc.destinationTopLeft().y();
4479 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4481 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4482 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4483 region.extent.width = uint32_t(copySize.width());
4484 region.extent.height = uint32_t(copySize.height());
4485 region.extent.depth = 1;
4487 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4488 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4489 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4490 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4494 cmd.args.copyImage.src = srcD->image;
4495 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4496 cmd.args.copyImage.dst = dstD->image;
4497 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4498 cmd.args.copyImage.desc = region;
4500 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4503 readback.activeFrameSlot = currentFrameSlot;
4504 readback.desc = u.rb;
4505 readback.result = u.result;
4511 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4512 qWarning(
"Multisample texture cannot be read back");
4515 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4516 if (u.rb.rect().isValid())
4517 readback.rect = u.rb.rect();
4519 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4520 readback.format = texD->m_format;
4521 texD->lastActiveFrameSlot = currentFrameSlot;
4526 qWarning(
"Swapchain does not support readback");
4529 if (u.rb.rect().isValid())
4530 readback.rect = u.rb.rect();
4532 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4533 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4534 if (readback.format == QRhiTexture::UnknownFormat)
4540 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4543 VkBufferCreateInfo bufferInfo = {};
4544 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4545 bufferInfo.size = readback.byteSize;
4546 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4548 VmaAllocationCreateInfo allocInfo = {};
4549 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4551 VmaAllocation allocation;
4552 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4553 if (err == VK_SUCCESS) {
4555 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4557 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4558 printExtraErrorInfo(err);
4563 VkBufferImageCopy copyDesc = {};
4564 copyDesc.bufferOffset = 0;
4565 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4566 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4567 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4568 copyDesc.imageSubresource.layerCount = 1;
4569 copyDesc.imageOffset.x = readback.rect.x();
4570 copyDesc.imageOffset.y = readback.rect.y();
4572 copyDesc.imageOffset.z = u.rb.layer();
4573 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4574 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4575 copyDesc.imageExtent.depth = 1;
4578 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4579 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4582 cmd.args.copyImageToBuffer.src = texD->image;
4583 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4584 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4585 cmd.args.copyImageToBuffer.desc = copyDesc;
4589 VkImage image = imageRes.image;
4592 qWarning(
"Attempted to read back undefined swapchain image content, "
4593 "results are undefined. (do a render pass first)");
4595 subresourceBarrier(cbD, image,
4596 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4597 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4598 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4606 cmd.args.copyImageToBuffer.src = image;
4607 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4608 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4609 cmd.args.copyImageToBuffer.desc = copyDesc;
4612 activeTextureReadbacks.append(readback);
4615 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4616 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4617 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4618 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4620 VkImageLayout origLayout = utexD->usageState.layout;
4621 VkAccessFlags origAccess = utexD->usageState.access;
4622 VkPipelineStageFlags origStage = utexD->usageState.stage;
4624 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4626 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4627 int w = utexD->m_pixelSize.width();
4628 int h = utexD->m_pixelSize.height();
4629 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4630 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4632 subresourceBarrier(cbD, utexD->image,
4633 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4634 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4635 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4639 subresourceBarrier(cbD, utexD->image,
4640 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4641 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4642 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4647 subresourceBarrier(cbD, utexD->image,
4648 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4649 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4650 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4654 VkImageBlit region = {};
4655 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4656 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4657 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4658 region.srcSubresource.layerCount = 1;
4660 region.srcOffsets[1].x = qMax(1, w);
4661 region.srcOffsets[1].y = qMax(1, h);
4662 region.srcOffsets[1].z = qMax(1, depth);
4664 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4665 region.dstSubresource.mipLevel = uint32_t(level);
4666 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4667 region.dstSubresource.layerCount = 1;
4669 region.dstOffsets[1].x = qMax(1, w >> 1);
4670 region.dstOffsets[1].y = qMax(1, h >> 1);
4671 region.dstOffsets[1].z = qMax(1, depth >> 1);
4675 cmd.args.blitImage.src = utexD->image;
4676 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4677 cmd.args.blitImage.dst = utexD->image;
4678 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4679 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4680 cmd.args.blitImage.desc = region;
4687 if (utexD->mipLevelCount > 1) {
4688 subresourceBarrier(cbD, utexD->image,
4689 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4690 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4691 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4693 0,
int(utexD->mipLevelCount) - 1);
4694 subresourceBarrier(cbD, utexD->image,
4695 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4696 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4697 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4699 int(utexD->mipLevelCount) - 1, 1);
4702 utexD->lastActiveFrameSlot = currentFrameSlot;
4711 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4714 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4716 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4720 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4721 if (err != VK_SUCCESS) {
4722 qWarning(
"Failed to map buffer: %d", err);
4725 quint32 changeBegin = UINT32_MAX;
4726 quint32 changeEnd = 0;
4727 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4728 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4729 if (u.offset < changeBegin)
4730 changeBegin = u.offset;
4731 if (u.offset + u.data.size() > changeEnd)
4732 changeEnd = u.offset + u.data.size();
4734 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4735 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4736 vmaUnmapMemory(toVmaAllocator(allocator), a);
4738 bufD->pendingDynamicUpdates[slot].clear();
4744 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4745 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4751 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4752 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4753 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4758 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4759 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4761 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4762 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4763 if (e.texture.extraImageViews[i])
4764 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4770 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4775 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4777 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4780 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4781 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4784 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4785 if (e.shaderResourceBindings.poolIndex >= 0) {
4786 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4787 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4794 qrhivk_releaseRenderBuffer(e, dev,
df);
4800 qrhivk_releaseSampler(e, dev,
df);
4803 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4805 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4806 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4808 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4809 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4810 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4813 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4816 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4818 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4819 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4825 releaseQueue.removeAt(i);
4832 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4834 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4836 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4837 readback.result->format = readback.format;
4838 readback.result->pixelSize = readback.rect.size();
4839 readback.result->data.resizeForOverwrite(readback.byteSize);
4840 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4841 toVmaAllocation(readback.stagingAlloc),
4842 0, readback.result->data.data(), readback.byteSize);
4843 if (err != VK_SUCCESS) {
4844 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4845 readback.result->data.clear();
4848 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4850 if (readback.result->completed)
4851 completedCallbacks.append(readback.result->completed);
4853 activeTextureReadbacks.remove(i);
4857 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4859 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4860 readback.result->data.resizeForOverwrite(readback.byteSize);
4861 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4862 toVmaAllocation(readback.stagingAlloc),
4863 0, readback.result->data.data(), readback.byteSize);
4864 if (err != VK_SUCCESS) {
4865 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4866 readback.result->data.clear();
4869 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4871 if (readback.result->completed)
4872 completedCallbacks.append(readback.result->completed);
4874 activeBufferReadbacks.remove(i);
4878 for (
auto f : completedCallbacks)
4885} qvk_sampleCounts[] = {
4887 { VK_SAMPLE_COUNT_1_BIT, 1 },
4888 { VK_SAMPLE_COUNT_2_BIT, 2 },
4889 { VK_SAMPLE_COUNT_4_BIT, 4 },
4890 { VK_SAMPLE_COUNT_8_BIT, 8 },
4891 { VK_SAMPLE_COUNT_16_BIT, 16 },
4892 { VK_SAMPLE_COUNT_32_BIT, 32 },
4893 { VK_SAMPLE_COUNT_64_BIT, 64 }
4898 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4899 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4900 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4901 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4904 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4905 if ((color & qvk_sampleCount.mask)
4906 && (depth & qvk_sampleCount.mask)
4907 && (stencil & qvk_sampleCount.mask))
4909 result.append(qvk_sampleCount.count);
4918 const int s = effectiveSampleCount(sampleCount);
4920 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4921 if (qvk_sampleCount.count == s)
4922 return qvk_sampleCount.mask;
4925 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4930 QList<QSize> result;
4931#ifdef VK_KHR_fragment_shading_rate
4932 sampleCount = qMax(1, sampleCount);
4933 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4934 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4935 if (qvk_sampleCount.count == sampleCount) {
4936 mask = qvk_sampleCount.mask;
4940 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4941 if (s.sampleCounts & mask)
4942 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4945 Q_UNUSED(sampleCount);
4946 result.append(QSize(1, 1));
4953 cbD->passResTrackers.emplace_back();
4958 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
4965 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
4969 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
4970 1, &cmd.args.copyBuffer.desc);
4973 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
4974 cmd.args.copyBufferToImage.dstLayout,
4975 uint32_t(cmd.args.copyBufferToImage.count),
4976 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
4979 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
4980 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
4981 1, &cmd.args.copyImage.desc);
4984 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
4985 cmd.args.copyImageToBuffer.dst,
4986 1, &cmd.args.copyImageToBuffer.desc);
4989 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
4990 0, 0,
nullptr, 0,
nullptr,
4991 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
4994 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
4996 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5000 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5001 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5002 1, &cmd.args.blitImage.desc,
5003 cmd.args.blitImage.filter);
5006 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5007 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5008 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5009 : VK_SUBPASS_CONTENTS_INLINE);
5012 VkMemoryBarrier barrier;
5013 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5014 barrier.pNext =
nullptr;
5015 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5016 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5017 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5023 df->vkCmdEndRenderPass(cbD->cb);
5026 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5030 const uint32_t *offsets =
nullptr;
5031 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5032 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5033 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5034 cmd.args.bindDescriptorSet.pipelineLayout,
5035 0, 1, &cmd.args.bindDescriptorSet.descSet,
5036 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5041 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5042 uint32_t(cmd.args.bindVertexBuffer.count),
5043 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5044 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5047 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5048 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5051 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5054 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5057 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5060 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5063 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5064 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5067 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5068 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5069 cmd.args.drawIndexed.firstInstance);
5072 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5073 cmd.args.drawIndirect.indirectBufferOffset,
5074 cmd.args.drawIndirect.drawCount,
5075 cmd.args.drawIndirect.stride);
5078 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5079 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5080 cmd.args.drawIndexedIndirect.drawCount,
5081 cmd.args.drawIndexedIndirect.stride);
5084#ifdef VK_EXT_debug_utils
5085 cmd.args.debugMarkerBegin.label.pLabelName =
5086 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5087 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5091#ifdef VK_EXT_debug_utils
5092 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5096#ifdef VK_EXT_debug_utils
5097 cmd.args.debugMarkerInsert.label.pLabelName =
5098 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5099 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5106 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5109 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5113#ifdef VK_KHR_fragment_shading_rate
5114 VkFragmentShadingRateCombinerOpKHR op[2] = {
5115 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5116 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5118 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5119 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5132 case QRhiPassResourceTracker::BufIndirectDraw:
5133 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5134 case QRhiPassResourceTracker::BufVertexInput:
5135 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5136 case QRhiPassResourceTracker::BufIndexRead:
5137 return VK_ACCESS_INDEX_READ_BIT;
5138 case QRhiPassResourceTracker::BufUniformRead:
5139 return VK_ACCESS_UNIFORM_READ_BIT;
5140 case QRhiPassResourceTracker::BufStorageLoad:
5141 return VK_ACCESS_SHADER_READ_BIT;
5142 case QRhiPassResourceTracker::BufStorageStore:
5143 return VK_ACCESS_SHADER_WRITE_BIT;
5144 case QRhiPassResourceTracker::BufStorageLoadStore:
5145 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5156 case QRhiPassResourceTracker::BufIndirectDrawStage:
5157 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5158 case QRhiPassResourceTracker::BufVertexInputStage:
5159 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5160 case QRhiPassResourceTracker::BufVertexStage:
5161 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5162 case QRhiPassResourceTracker::BufTCStage:
5163 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5164 case QRhiPassResourceTracker::BufTEStage:
5165 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5166 case QRhiPassResourceTracker::BufFragmentStage:
5167 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5168 case QRhiPassResourceTracker::BufComputeStage:
5169 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5170 case QRhiPassResourceTracker::BufGeometryStage:
5171 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5182 u.access = VkAccessFlags(usage
.access);
5183 u.stage = VkPipelineStageFlags(usage
.stage);
5190 case QRhiPassResourceTracker::TexSample:
5191 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5192 case QRhiPassResourceTracker::TexColorOutput:
5193 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5194 case QRhiPassResourceTracker::TexDepthOutput:
5195 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5196 case QRhiPassResourceTracker::TexStorageLoad:
5197 case QRhiPassResourceTracker::TexStorageStore:
5198 case QRhiPassResourceTracker::TexStorageLoadStore:
5199 return VK_IMAGE_LAYOUT_GENERAL;
5200 case QRhiPassResourceTracker::TexShadingRate:
5201#ifdef VK_KHR_fragment_shading_rate
5202 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5204 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5210 return VK_IMAGE_LAYOUT_GENERAL;
5216 case QRhiPassResourceTracker::TexSample:
5217 return VK_ACCESS_SHADER_READ_BIT;
5218 case QRhiPassResourceTracker::TexColorOutput:
5219 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5220 case QRhiPassResourceTracker::TexDepthOutput:
5221 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5222 case QRhiPassResourceTracker::TexStorageLoad:
5223 return VK_ACCESS_SHADER_READ_BIT;
5224 case QRhiPassResourceTracker::TexStorageStore:
5225 return VK_ACCESS_SHADER_WRITE_BIT;
5226 case QRhiPassResourceTracker::TexStorageLoadStore:
5227 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5240 case QRhiPassResourceTracker::TexVertexStage:
5241 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5242 case QRhiPassResourceTracker::TexTCStage:
5243 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5244 case QRhiPassResourceTracker::TexTEStage:
5245 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5246 case QRhiPassResourceTracker::TexFragmentStage:
5247 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5248 case QRhiPassResourceTracker::TexColorOutputStage:
5249 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5250 case QRhiPassResourceTracker::TexDepthOutputStage:
5251 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5252 case QRhiPassResourceTracker::TexComputeStage:
5253 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5254 case QRhiPassResourceTracker::TexGeometryStage:
5255 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5266 u.layout = VkImageLayout(usage
.layout);
5267 u.access = VkAccessFlags(usage
.access);
5268 u.stage = VkPipelineStageFlags(usage
.stage);
5279 const VkAccessFlags newAccess = toVkAccess(access);
5280 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5281 if (u.access == newAccess && u.stage == newStage) {
5282 if (!accessIsWrite(access))
5286 u.access = newAccess;
5296 const VkAccessFlags newAccess = toVkAccess(access);
5297 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5298 const VkImageLayout newLayout = toVkLayout(access);
5299 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5300 if (!accessIsWrite(access))
5304 u.layout = newLayout;
5305 u.access = newAccess;
5314 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5315 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5316 VkAccessFlags access = toVkAccess(trackedB.access);
5317 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5318 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5321 if (s.access == access && s.stage == stage) {
5322 if (!accessIsWrite(access))
5325 VkBufferMemoryBarrier bufMemBarrier = {};
5326 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5327 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5328 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5329 bufMemBarrier.srcAccessMask = s.access;
5330 bufMemBarrier.dstAccessMask = access;
5331 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5332 bufMemBarrier.size = VK_WHOLE_SIZE;
5333 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5339 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5340 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5341 VkImageLayout layout = toVkLayout(trackedT.access);
5342 VkAccessFlags access = toVkAccess(trackedT.access);
5343 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5344 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5345 if (s.access == access && s.stage == stage && s.layout == layout) {
5346 if (!accessIsWrite(access))
5349 VkImageMemoryBarrier barrier = {};
5350 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5351 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5352 barrier.subresourceRange.baseMipLevel = 0;
5353 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5354 barrier.subresourceRange.baseArrayLayer = 0;
5355 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5356 barrier.oldLayout = s.layout;
5357 barrier.newLayout = layout;
5358 barrier.srcAccessMask = s.access;
5359 barrier.dstAccessMask = access;
5360 barrier.image = texD->image;
5361 VkPipelineStageFlags srcStage = s.stage;
5364 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5365 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5374 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5375 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5376 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5378 qWarning(
"Physical device surface queries not available");
5382 return new QVkSwapChain(
this);
5385QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5387 return new QVkBuffer(
this, type, usage, size);
5392 return int(ubufAlign);
5414 static QMatrix4x4 m;
5415 if (m.isIdentity()) {
5417 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5418 0.0f, -1.0f, 0.0f, 0.0f,
5419 0.0f, 0.0f, 0.5f, 0.5f,
5420 0.0f, 0.0f, 0.0f, 1.0f);
5430 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5431 if (!physDevFeatures.textureCompressionBC)
5435 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5436 if (!physDevFeatures.textureCompressionETC2)
5440 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5441 if (!physDevFeatures.textureCompressionASTC_LDR)
5445 VkFormat vkformat = toVkTextureFormat(format, flags);
5446 VkFormatProperties props;
5447 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5448 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5454 case QRhi::MultisampleTexture:
5456 case QRhi::MultisampleRenderBuffer:
5458 case QRhi::DebugMarkers:
5459 return caps.debugUtils;
5460 case QRhi::Timestamps:
5461 return timestampValidBits != 0;
5462 case QRhi::Instancing:
5464 case QRhi::CustomInstanceStepRate:
5465 return caps.vertexAttribDivisor;
5466 case QRhi::PrimitiveRestart:
5468 case QRhi::NonDynamicUniformBuffers:
5470 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5472 case QRhi::NPOTTextureRepeat:
5474 case QRhi::RedOrAlpha8IsRed:
5476 case QRhi::ElementIndexUint:
5479 return caps.compute;
5480 case QRhi::WideLines:
5481 return caps.wideLines;
5482 case QRhi::VertexShaderPointSize:
5484 case QRhi::BaseVertex:
5486 case QRhi::BaseInstance:
5488 case QRhi::TriangleFanTopology:
5490 case QRhi::ReadBackNonUniformBuffer:
5492 case QRhi::ReadBackNonBaseMipLevel:
5494 case QRhi::TexelFetch:
5496 case QRhi::RenderToNonBaseMipLevel:
5498 case QRhi::IntAttributes:
5500 case QRhi::ScreenSpaceDerivatives:
5502 case QRhi::ReadBackAnyTextureFormat:
5504 case QRhi::PipelineCacheDataLoadSave:
5506 case QRhi::ImageDataStride:
5508 case QRhi::RenderBufferImport:
5510 case QRhi::ThreeDimensionalTextures:
5512 case QRhi::RenderTo3DTextureSlice:
5513 return caps.texture3DSliceAs2D;
5514 case QRhi::TextureArrays:
5516 case QRhi::Tessellation:
5517 return caps.tessellation;
5518 case QRhi::GeometryShader:
5519 return caps.geometryShader;
5520 case QRhi::TextureArrayRange:
5522 case QRhi::NonFillPolygonMode:
5523 return caps.nonFillPolygonMode;
5524 case QRhi::OneDimensionalTextures:
5526 case QRhi::OneDimensionalTextureMipmaps:
5528 case QRhi::HalfAttributes:
5530 case QRhi::RenderToOneDimensionalTexture:
5532 case QRhi::ThreeDimensionalTextureMipmaps:
5534 case QRhi::MultiView:
5535 return caps.multiView;
5536 case QRhi::TextureViewFormat:
5538 case QRhi::ResolveDepthStencil:
5539 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5540 case QRhi::VariableRateShading:
5541 return caps.renderPass2KHR && caps.perDrawShadingRate;
5542 case QRhi::VariableRateShadingMap:
5543 case QRhi::VariableRateShadingMapWithTexture:
5544 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5545 case QRhi::PerRenderTargetBlending:
5546 case QRhi::SampleVariables:
5548 case QRhi::InstanceIndexIncludesBaseInstance:
5550 case QRhi::DepthClamp:
5552 case QRhi::DrawIndirect:
5554 case QRhi::DrawIndirectMulti:
5555 return caps.drawIndirectMulti;
5557 Q_UNREACHABLE_RETURN(
false);
5564 case QRhi::TextureSizeMin:
5566 case QRhi::TextureSizeMax:
5567 return int(physDevProperties.limits.maxImageDimension2D);
5568 case QRhi::MaxColorAttachments:
5569 return int(physDevProperties.limits.maxColorAttachments);
5570 case QRhi::FramesInFlight:
5572 case QRhi::MaxAsyncReadbackFrames:
5574 case QRhi::MaxThreadGroupsPerDimension:
5575 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5576 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5577 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5578 case QRhi::MaxThreadsPerThreadGroup:
5579 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5580 case QRhi::MaxThreadGroupX:
5581 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5582 case QRhi::MaxThreadGroupY:
5583 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5584 case QRhi::MaxThreadGroupZ:
5585 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5586 case QRhi::TextureArraySizeMax:
5587 return int(physDevProperties.limits.maxImageArrayLayers);
5588 case QRhi::MaxUniformBufferRange:
5589 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5590 case QRhi::MaxVertexInputs:
5591 return physDevProperties.limits.maxVertexInputAttributes;
5592 case QRhi::MaxVertexOutputs:
5593 return physDevProperties.limits.maxVertexOutputComponents / 4;
5594 case QRhi::ShadingRateImageTileSize:
5595 return caps.imageBasedShadingRateTileSize;
5597 Q_UNREACHABLE_RETURN(0);
5603 return &nativeHandlesStruct;
5608 return driverInfoStruct;
5614 result.totalPipelineCreationTime = totalPipelineCreationTime();
5616 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5617 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5619 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5620 for (uint32_t i = 0; i < count; ++i) {
5621 const VmaStatistics &stats(budgets[i].statistics);
5622 result.blockCount += stats.blockCount;
5623 result.allocCount += stats.allocationCount;
5624 result.usedBytes += stats.allocationBytes;
5625 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5639 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5643 waitSemaphoresForQueueSubmit.clear();
5644 if (sp->waitSemaphoreCount)
5645 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5647 signalSemaphoresForQueueSubmit.clear();
5648 if (sp->signalSemaphoreCount)
5649 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5651 waitSemaphoresForPresent.clear();
5652 if (sp->presentWaitSemaphoreCount)
5653 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5683 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5686 size_t dataSize = 0;
5687 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5688 if (err != VK_SUCCESS) {
5689 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5690 return QByteArray();
5693 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5694 data.resize(dataOffset + dataSize);
5695 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5696 if (err != VK_SUCCESS) {
5697 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5698 return QByteArray();
5702 header.rhiId = pipelineCacheRhiId();
5703 header.arch = quint32(
sizeof(
void*));
5704 header.driverVersion = physDevProperties.driverVersion;
5705 header.vendorId = physDevProperties.vendorID;
5706 header.deviceId = physDevProperties.deviceID;
5707 header.dataSize = quint32(dataSize);
5708 header.uuidSize = VK_UUID_SIZE;
5709 header.reserved = 0;
5710 memcpy(data.data(), &header, headerSize);
5711 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5722 if (data.size() < qsizetype(headerSize)) {
5723 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5727 memcpy(&header, data.constData(), headerSize);
5729 const quint32 rhiId = pipelineCacheRhiId();
5730 if (header.rhiId != rhiId) {
5731 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5732 rhiId, header.rhiId);
5735 const quint32 arch = quint32(
sizeof(
void*));
5736 if (header.arch != arch) {
5737 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5741 if (header.driverVersion != physDevProperties.driverVersion) {
5742 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5743 physDevProperties.driverVersion, header.driverVersion);
5746 if (header.vendorId != physDevProperties.vendorID) {
5747 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5748 physDevProperties.vendorID, header.vendorId);
5751 if (header.deviceId != physDevProperties.deviceID) {
5752 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5753 physDevProperties.deviceID, header.deviceId);
5756 if (header.uuidSize != VK_UUID_SIZE) {
5757 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5758 quint32(VK_UUID_SIZE), header.uuidSize);
5762 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5763 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5766 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5767 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5771 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5772 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5773 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5777 if (pipelineCache) {
5778 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5779 pipelineCache = VK_NULL_HANDLE;
5782 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5783 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5784 int(header.dataSize));
5786 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5790QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5791 int sampleCount, QRhiRenderBuffer::Flags flags,
5792 QRhiTexture::Format backingFormatHint)
5794 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5798 const QSize &pixelSize,
int depth,
int arraySize,
5799 int sampleCount, QRhiTexture::Flags flags)
5801 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5805 QRhiSampler::Filter mipmapMode,
5806 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5808 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5813 return new QVkShadingRateMap(
this);
5817 QRhiTextureRenderTarget::Flags flags)
5824 return new QVkGraphicsPipeline(
this);
5829 return new QVkComputePipeline(
this);
5834 return new QVkShaderResourceBindings(
this);
5840 Q_ASSERT(psD->pipeline);
5844 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5846 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5850 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5851 cmd.args.bindPipeline.pipeline = psD->pipeline;
5854 cbD->currentGraphicsPipeline = ps;
5855 cbD->currentComputePipeline =
nullptr;
5856 cbD->currentPipelineGeneration = psD->generation;
5862 psD->lastActiveFrameSlot = currentFrameSlot;
5866 int dynamicOffsetCount,
5867 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5877 srb = gfxPsD->m_shaderResourceBindings;
5879 srb = compPsD->m_shaderResourceBindings;
5883 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5884 bool rewriteDescSet =
false;
5885 bool addWriteBarrier =
false;
5886 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5887 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5891 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5892 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5895 case QRhiShaderResourceBinding::UniformBuffer:
5898 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5899 sanityCheckResourceOwnership(bufD);
5901 if (bufD->m_type == QRhiBuffer::Dynamic)
5904 bufD->lastActiveFrameSlot = currentFrameSlot;
5905 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5907 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5913 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5914 rewriteDescSet =
true;
5915 bd.ubuf.id = bufD->m_id;
5916 bd.ubuf.generation = bufD->generation;
5920 case QRhiShaderResourceBinding::SampledTexture:
5921 case QRhiShaderResourceBinding::Texture:
5922 case QRhiShaderResourceBinding::Sampler:
5924 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5925 if (bd.stex.count != data->count) {
5926 bd.stex.count = data->count;
5927 rewriteDescSet =
true;
5929 for (
int elem = 0; elem < data->count; ++elem) {
5935 Q_ASSERT(texD || samplerD);
5936 sanityCheckResourceOwnership(texD);
5937 sanityCheckResourceOwnership(samplerD);
5939 texD->lastActiveFrameSlot = currentFrameSlot;
5945 samplerD->lastActiveFrameSlot = currentFrameSlot;
5946 const quint64 texId = texD ? texD->m_id : 0;
5947 const uint texGen = texD ? texD->generation : 0;
5948 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
5949 const uint samplerGen = samplerD ? samplerD->generation : 0;
5950 if (texGen != bd.stex.d[elem].texGeneration
5951 || texId != bd.stex.d[elem].texId
5952 || samplerGen != bd.stex.d[elem].samplerGeneration
5953 || samplerId != bd.stex.d[elem].samplerId)
5955 rewriteDescSet =
true;
5956 bd.stex.d[elem].texId = texId;
5957 bd.stex.d[elem].texGeneration = texGen;
5958 bd.stex.d[elem].samplerId = samplerId;
5959 bd.stex.d[elem].samplerGeneration = samplerGen;
5964 case QRhiShaderResourceBinding::ImageLoad:
5965 case QRhiShaderResourceBinding::ImageStore:
5966 case QRhiShaderResourceBinding::ImageLoadStore:
5969 sanityCheckResourceOwnership(texD);
5970 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
5971 texD->lastActiveFrameSlot = currentFrameSlot;
5973 if (b->type == QRhiShaderResourceBinding::ImageLoad)
5975 else if (b->type == QRhiShaderResourceBinding::ImageStore)
5980 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
5981 const auto prevAccess = passResTracker.textures().find(texD);
5982 if (prevAccess != passResTracker.textures().end()) {
5986 addWriteBarrier =
true;
5987 writeBarrierDstStageMask |= toVkPipelineStage(stage);
5988 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
5996 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
5997 rewriteDescSet =
true;
5998 bd.simage.id = texD->m_id;
5999 bd.simage.generation = texD->generation;
6003 case QRhiShaderResourceBinding::BufferLoad:
6004 case QRhiShaderResourceBinding::BufferStore:
6005 case QRhiShaderResourceBinding::BufferLoadStore:
6008 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6009 sanityCheckResourceOwnership(bufD);
6011 if (bufD->m_type == QRhiBuffer::Dynamic)
6014 bufD->lastActiveFrameSlot = currentFrameSlot;
6016 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6018 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6023 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6024 const auto prevAccess = passResTracker.buffers().find(bufD);
6025 if (prevAccess != passResTracker.buffers().end()) {
6029 addWriteBarrier =
true;
6030 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6031 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6034 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6038 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6039 rewriteDescSet =
true;
6040 bd.sbuf.id = bufD->m_id;
6041 bd.sbuf.generation = bufD->generation;
6051 if (addWriteBarrier) {
6053 VkMemoryBarrier barrier;
6054 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6055 barrier.pNext =
nullptr;
6056 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6057 barrier.srcAccessMask = barrier.dstAccessMask;
6058 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6065 cmd.args.memoryBarrier.dependencyFlags = 0;
6066 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6067 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6068 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6069 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6075 updateShaderResourceBindings(srb);
6079 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot || srbD->hasDynamicOffset;
6081 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6083 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6084 QVarLengthArray<uint32_t, 4> dynOfs;
6090 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
6091 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
6092 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
6093 uint32_t offset = 0;
6094 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6095 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6096 if (bindingOffsetPair.first == b->binding) {
6097 offset = bindingOffsetPair.second;
6101 dynOfs.append(offset);
6107 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6108 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6109 gfxPsD ? gfxPsD->layout : compPsD->layout,
6110 0, 1, &srbD->descSets[currentFrameSlot],
6111 uint32_t(dynOfs.size()),
6112 dynOfs.size() ? dynOfs.constData() :
nullptr);
6116 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6117 : VK_PIPELINE_BIND_POINT_COMPUTE;
6118 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6119 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6120 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6121 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6122 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6126 cbD->currentGraphicsSrb = srb;
6127 cbD->currentComputeSrb =
nullptr;
6129 cbD->currentGraphicsSrb =
nullptr;
6130 cbD->currentComputeSrb = srb;
6132 cbD->currentSrbGeneration = srbD->generation;
6133 cbD->currentDescSetSlot = currentFrameSlot;
6136 srbD->lastActiveFrameSlot = currentFrameSlot;
6140 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6141 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6147 bool needsBindVBuf =
false;
6148 for (
int i = 0; i < bindingCount; ++i) {
6149 const int inputSlot = startBinding + i;
6151 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6152 bufD->lastActiveFrameSlot = currentFrameSlot;
6153 if (bufD->m_type == QRhiBuffer::Dynamic)
6156 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6157 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6158 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6160 needsBindVBuf =
true;
6161 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6162 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6166 if (needsBindVBuf) {
6167 QVarLengthArray<VkBuffer, 4> bufs;
6168 QVarLengthArray<VkDeviceSize, 4> ofs;
6169 for (
int i = 0; i < bindingCount; ++i) {
6171 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6172 bufs.append(bufD->buffers[slot]);
6173 ofs.append(bindings[i].second);
6180 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6181 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6185 cmd.args.bindVertexBuffer.startBinding = startBinding;
6186 cmd.args.bindVertexBuffer.count = bufs.size();
6187 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6188 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6189 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6190 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6196 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6197 ibufD->lastActiveFrameSlot = currentFrameSlot;
6198 if (ibufD->m_type == QRhiBuffer::Dynamic)
6201 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6202 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6203 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6204 : VK_INDEX_TYPE_UINT32;
6206 if (cbD->currentIndexBuffer != vkindexbuf
6207 || cbD->currentIndexOffset != indexOffset
6208 || cbD->currentIndexFormat != type)
6210 cbD->currentIndexBuffer = vkindexbuf;
6211 cbD->currentIndexOffset = indexOffset;
6212 cbD->currentIndexFormat = type;
6215 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6219 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6220 cmd.args.bindIndexBuffer.ofs = indexOffset;
6221 cmd.args.bindIndexBuffer.type = type;
6235 const QSize outputSize = cbD->currentTarget->pixelSize();
6236 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6237 float x = 0, y = 0, w = 0, h = 0;
6239 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6242 w = outputSize.width();
6243 h = outputSize.height();
6246 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6250 VkRect2D *s = &cmd.args.setScissor.scissor;
6251 s->offset.x = int32_t(x);
6252 s->offset.y = int32_t(y);
6253 s->extent.width = uint32_t(w);
6254 s->extent.height = uint32_t(h);
6257 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6258 cbD->commands.unget();
6268 const QSize outputSize = cbD->currentTarget->pixelSize();
6272 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6276 VkViewport *vp = &cmd.args.setViewport.viewport;
6281 vp->minDepth = viewport.minDepth();
6282 vp->maxDepth = viewport.maxDepth();
6285 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6286 cbD->commands.unget();
6291 cbD->currentViewport = viewport;
6292 if (cbD->currentGraphicsPipeline
6293 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6303 Q_ASSERT(!cbD->currentGraphicsPipeline
6305 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6306 const QSize outputSize = cbD->currentTarget->pixelSize();
6310 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6314 VkRect2D *s = &cmd.args.setScissor.scissor;
6317 s->extent.width = uint32_t(w);
6318 s->extent.height = uint32_t(h);
6321 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6322 cbD->commands.unget();
6336 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6337 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6341 cmd.args.setBlendConstants.c[0] = c.redF();
6342 cmd.args.setBlendConstants.c[1] = c.greenF();
6343 cmd.args.setBlendConstants.c[2] = c.blueF();
6344 cmd.args.setBlendConstants.c[3] = c.alphaF();
6354 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6358 cmd.args.setStencilRef.ref = refValue;
6364#ifdef VK_KHR_fragment_shading_rate
6365 if (!vkCmdSetFragmentShadingRateKHR)
6368 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6369 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6370 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6372 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6373 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6374 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6376 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6377 if (cbD->passUsesSecondaryCb) {
6378 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6380 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6381 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6382 cmd.args.setShadingRate.w = size.width;
6383 cmd.args.setShadingRate.h = size.height;
6385 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6386 cbD->hasShadingRateSet =
true;
6389 Q_UNUSED(coarsePixelSize);
6394 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6400 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6404 cmd.args.draw.vertexCount = vertexCount;
6405 cmd.args.draw.instanceCount = instanceCount;
6406 cmd.args.draw.firstVertex = firstVertex;
6407 cmd.args.draw.firstInstance = firstInstance;
6412 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6418 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6419 firstIndex, vertexOffset, firstInstance);
6423 cmd.args.drawIndexed.indexCount = indexCount;
6424 cmd.args.drawIndexed.instanceCount = instanceCount;
6425 cmd.args.drawIndexed.firstIndex = firstIndex;
6426 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6427 cmd.args.drawIndexed.firstInstance = firstInstance;
6432 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6439 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6440 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6442 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6446 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6449 if (caps.drawIndirectMulti) {
6450 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6451 indirectBufVk, indirectBufferOffset,
6454 VkDeviceSize offset = indirectBufferOffset;
6455 for (quint32 i = 0; i < drawCount; ++i) {
6456 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6457 indirectBufVk, offset,
6463 if (caps.drawIndirectMulti) {
6466 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6467 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6468 cmd.args.drawIndirect.drawCount = drawCount;
6469 cmd.args.drawIndirect.stride = stride;
6471 VkDeviceSize offset = indirectBufferOffset;
6472 for (quint32 i = 0; i < drawCount; ++i) {
6475 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6476 cmd.args.drawIndirect.indirectBufferOffset = offset;
6477 cmd.args.drawIndirect.drawCount = 1;
6478 cmd.args.drawIndirect.stride = stride;
6486 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6493 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6494 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6496 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6500 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6503 if (caps.drawIndirectMulti) {
6504 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6505 indirectBufVk, indirectBufferOffset,
6508 VkDeviceSize offset = indirectBufferOffset;
6509 for (quint32 i = 0; i < drawCount; ++i) {
6510 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6511 indirectBufVk, offset,
6517 if (caps.drawIndirectMulti) {
6520 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6521 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
6522 cmd.args.drawIndexedIndirect.drawCount = drawCount;
6523 cmd.args.drawIndexedIndirect.stride = stride;
6525 VkDeviceSize offset = indirectBufferOffset;
6526 for (quint32 i = 0; i < drawCount; ++i) {
6529 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6530 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
6531 cmd.args.drawIndexedIndirect.drawCount = 1;
6532 cmd.args.drawIndexedIndirect.stride = stride;
6541#ifdef VK_EXT_debug_utils
6542 if (!debugMarkers || !caps.debugUtils)
6545 VkDebugUtilsLabelEXT label = {};
6546 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6548 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6549 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6550 label.pLabelName = name.constData();
6551 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6553 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6554 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6555 cmd.args.debugMarkerBegin.label = label;
6556 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6557 cbD->pools.debugMarkerData.append(name);
6567#ifdef VK_EXT_debug_utils
6568 if (!debugMarkers || !caps.debugUtils)
6571 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6572 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6573 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6575 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6576 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6585#ifdef VK_EXT_debug_utils
6586 if (!debugMarkers || !caps.debugUtils)
6589 VkDebugUtilsLabelEXT label = {};
6590 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6592 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6593 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6594 label.pLabelName = msg.constData();
6595 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6597 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6598 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6599 cmd.args.debugMarkerInsert.label = label;
6600 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6601 cbD->pools.debugMarkerData.append(msg);
6611 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6616 Q_ASSERT(cbD->currentTarget);
6619 switch (cbD->currentTarget->resourceType()) {
6620 case QRhiResource::SwapChainRenderTarget:
6623 case QRhiResource::TextureRenderTarget:
6655 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6656 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6660 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6661 cbD->activeSecondaryCbStack.removeLast();
6662 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6664 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6666 cbD->activeSecondaryCbStack.append(extCb);
6678 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6679 cbD->activeSecondaryCbStack.removeLast();
6680 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6681 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6695 if (!debugMarkers || name.isEmpty())
6698 QByteArray decoratedName = name;
6700 decoratedName +=
'/';
6701 decoratedName += QByteArray::number(slot);
6703 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6708#ifdef VK_EXT_debug_utils
6709 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6712 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6713 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6714 nameInfo.objectType = type;
6715 nameInfo.objectHandle = object;
6716 QByteArray decoratedName = name;
6718 decoratedName +=
'/';
6719 decoratedName += QByteArray::number(slot);
6721 nameInfo.pObjectName = decoratedName.constData();
6722 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6734 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6735 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6736 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6737 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6738 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6739 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6740 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6741 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6742 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
6743 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
6744 return VkBufferUsageFlagBits(u);
6750 case QRhiSampler::Nearest:
6751 return VK_FILTER_NEAREST;
6752 case QRhiSampler::Linear:
6753 return VK_FILTER_LINEAR;
6755 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6762 case QRhiSampler::None:
6763 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6764 case QRhiSampler::Nearest:
6765 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6766 case QRhiSampler::Linear:
6767 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6769 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6776 case QRhiSampler::Repeat:
6777 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6778 case QRhiSampler::ClampToEdge:
6779 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6780 case QRhiSampler::Mirror:
6781 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6783 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6790 case QRhiShaderStage::Vertex:
6791 return VK_SHADER_STAGE_VERTEX_BIT;
6792 case QRhiShaderStage::TessellationControl:
6793 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6794 case QRhiShaderStage::TessellationEvaluation:
6795 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6796 case QRhiShaderStage::Fragment:
6797 return VK_SHADER_STAGE_FRAGMENT_BIT;
6798 case QRhiShaderStage::Compute:
6799 return VK_SHADER_STAGE_COMPUTE_BIT;
6800 case QRhiShaderStage::Geometry:
6801 return VK_SHADER_STAGE_GEOMETRY_BIT;
6803 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6810 case QRhiVertexInputAttribute::Float4:
6811 return VK_FORMAT_R32G32B32A32_SFLOAT;
6812 case QRhiVertexInputAttribute::Float3:
6813 return VK_FORMAT_R32G32B32_SFLOAT;
6814 case QRhiVertexInputAttribute::Float2:
6815 return VK_FORMAT_R32G32_SFLOAT;
6816 case QRhiVertexInputAttribute::Float:
6817 return VK_FORMAT_R32_SFLOAT;
6818 case QRhiVertexInputAttribute::UNormByte4:
6819 return VK_FORMAT_R8G8B8A8_UNORM;
6820 case QRhiVertexInputAttribute::UNormByte2:
6821 return VK_FORMAT_R8G8_UNORM;
6822 case QRhiVertexInputAttribute::UNormByte:
6823 return VK_FORMAT_R8_UNORM;
6824 case QRhiVertexInputAttribute::UInt4:
6825 return VK_FORMAT_R32G32B32A32_UINT;
6826 case QRhiVertexInputAttribute::UInt3:
6827 return VK_FORMAT_R32G32B32_UINT;
6828 case QRhiVertexInputAttribute::UInt2:
6829 return VK_FORMAT_R32G32_UINT;
6830 case QRhiVertexInputAttribute::UInt:
6831 return VK_FORMAT_R32_UINT;
6832 case QRhiVertexInputAttribute::SInt4:
6833 return VK_FORMAT_R32G32B32A32_SINT;
6834 case QRhiVertexInputAttribute::SInt3:
6835 return VK_FORMAT_R32G32B32_SINT;
6836 case QRhiVertexInputAttribute::SInt2:
6837 return VK_FORMAT_R32G32_SINT;
6838 case QRhiVertexInputAttribute::SInt:
6839 return VK_FORMAT_R32_SINT;
6840 case QRhiVertexInputAttribute::Half4:
6841 return VK_FORMAT_R16G16B16A16_SFLOAT;
6842 case QRhiVertexInputAttribute::Half3:
6843 return VK_FORMAT_R16G16B16_SFLOAT;
6844 case QRhiVertexInputAttribute::Half2:
6845 return VK_FORMAT_R16G16_SFLOAT;
6846 case QRhiVertexInputAttribute::Half:
6847 return VK_FORMAT_R16_SFLOAT;
6848 case QRhiVertexInputAttribute::UShort4:
6849 return VK_FORMAT_R16G16B16A16_UINT;
6850 case QRhiVertexInputAttribute::UShort3:
6851 return VK_FORMAT_R16G16B16_UINT;
6852 case QRhiVertexInputAttribute::UShort2:
6853 return VK_FORMAT_R16G16_UINT;
6854 case QRhiVertexInputAttribute::UShort:
6855 return VK_FORMAT_R16_UINT;
6856 case QRhiVertexInputAttribute::SShort4:
6857 return VK_FORMAT_R16G16B16A16_SINT;
6858 case QRhiVertexInputAttribute::SShort3:
6859 return VK_FORMAT_R16G16B16_SINT;
6860 case QRhiVertexInputAttribute::SShort2:
6861 return VK_FORMAT_R16G16_SINT;
6862 case QRhiVertexInputAttribute::SShort:
6863 return VK_FORMAT_R16_SINT;
6865 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6872 case QRhiGraphicsPipeline::Triangles:
6873 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6874 case QRhiGraphicsPipeline::TriangleStrip:
6875 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6876 case QRhiGraphicsPipeline::TriangleFan:
6877 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6878 case QRhiGraphicsPipeline::Lines:
6879 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6880 case QRhiGraphicsPipeline::LineStrip:
6881 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6882 case QRhiGraphicsPipeline::Points:
6883 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6884 case QRhiGraphicsPipeline::Patches:
6885 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6887 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6894 case QRhiGraphicsPipeline::None:
6895 return VK_CULL_MODE_NONE;
6896 case QRhiGraphicsPipeline::Front:
6897 return VK_CULL_MODE_FRONT_BIT;
6898 case QRhiGraphicsPipeline::Back:
6899 return VK_CULL_MODE_BACK_BIT;
6901 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6908 case QRhiGraphicsPipeline::CCW:
6909 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6910 case QRhiGraphicsPipeline::CW:
6911 return VK_FRONT_FACE_CLOCKWISE;
6913 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6920 if (c.testFlag(QRhiGraphicsPipeline::R))
6921 f |= VK_COLOR_COMPONENT_R_BIT;
6922 if (c.testFlag(QRhiGraphicsPipeline::G))
6923 f |= VK_COLOR_COMPONENT_G_BIT;
6924 if (c.testFlag(QRhiGraphicsPipeline::B))
6925 f |= VK_COLOR_COMPONENT_B_BIT;
6926 if (c.testFlag(QRhiGraphicsPipeline::A))
6927 f |= VK_COLOR_COMPONENT_A_BIT;
6928 return VkColorComponentFlags(f);
6934 case QRhiGraphicsPipeline::Zero:
6935 return VK_BLEND_FACTOR_ZERO;
6936 case QRhiGraphicsPipeline::One:
6937 return VK_BLEND_FACTOR_ONE;
6938 case QRhiGraphicsPipeline::SrcColor:
6939 return VK_BLEND_FACTOR_SRC_COLOR;
6940 case QRhiGraphicsPipeline::OneMinusSrcColor:
6941 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6942 case QRhiGraphicsPipeline::DstColor:
6943 return VK_BLEND_FACTOR_DST_COLOR;
6944 case QRhiGraphicsPipeline::OneMinusDstColor:
6945 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6946 case QRhiGraphicsPipeline::SrcAlpha:
6947 return VK_BLEND_FACTOR_SRC_ALPHA;
6948 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6949 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6950 case QRhiGraphicsPipeline::DstAlpha:
6951 return VK_BLEND_FACTOR_DST_ALPHA;
6952 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6953 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
6954 case QRhiGraphicsPipeline::ConstantColor:
6955 return VK_BLEND_FACTOR_CONSTANT_COLOR;
6956 case QRhiGraphicsPipeline::OneMinusConstantColor:
6957 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
6958 case QRhiGraphicsPipeline::ConstantAlpha:
6959 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
6960 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6961 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
6962 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6963 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
6964 case QRhiGraphicsPipeline::Src1Color:
6965 return VK_BLEND_FACTOR_SRC1_COLOR;
6966 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6967 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
6968 case QRhiGraphicsPipeline::Src1Alpha:
6969 return VK_BLEND_FACTOR_SRC1_ALPHA;
6970 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6971 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
6973 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
6980 case QRhiGraphicsPipeline::Add:
6981 return VK_BLEND_OP_ADD;
6982 case QRhiGraphicsPipeline::Subtract:
6983 return VK_BLEND_OP_SUBTRACT;
6984 case QRhiGraphicsPipeline::ReverseSubtract:
6985 return VK_BLEND_OP_REVERSE_SUBTRACT;
6986 case QRhiGraphicsPipeline::Min:
6987 return VK_BLEND_OP_MIN;
6988 case QRhiGraphicsPipeline::Max:
6989 return VK_BLEND_OP_MAX;
6991 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
6998 case QRhiGraphicsPipeline::Never:
6999 return VK_COMPARE_OP_NEVER;
7000 case QRhiGraphicsPipeline::Less:
7001 return VK_COMPARE_OP_LESS;
7002 case QRhiGraphicsPipeline::Equal:
7003 return VK_COMPARE_OP_EQUAL;
7004 case QRhiGraphicsPipeline::LessOrEqual:
7005 return VK_COMPARE_OP_LESS_OR_EQUAL;
7006 case QRhiGraphicsPipeline::Greater:
7007 return VK_COMPARE_OP_GREATER;
7008 case QRhiGraphicsPipeline::NotEqual:
7009 return VK_COMPARE_OP_NOT_EQUAL;
7010 case QRhiGraphicsPipeline::GreaterOrEqual:
7011 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7012 case QRhiGraphicsPipeline::Always:
7013 return VK_COMPARE_OP_ALWAYS;
7015 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7022 case QRhiGraphicsPipeline::StencilZero:
7023 return VK_STENCIL_OP_ZERO;
7024 case QRhiGraphicsPipeline::Keep:
7025 return VK_STENCIL_OP_KEEP;
7026 case QRhiGraphicsPipeline::Replace:
7027 return VK_STENCIL_OP_REPLACE;
7028 case QRhiGraphicsPipeline::IncrementAndClamp:
7029 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7030 case QRhiGraphicsPipeline::DecrementAndClamp:
7031 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7032 case QRhiGraphicsPipeline::Invert:
7033 return VK_STENCIL_OP_INVERT;
7034 case QRhiGraphicsPipeline::IncrementAndWrap:
7035 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7036 case QRhiGraphicsPipeline::DecrementAndWrap:
7037 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7039 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7046 case QRhiGraphicsPipeline::Fill:
7047 return VK_POLYGON_MODE_FILL;
7048 case QRhiGraphicsPipeline::Line:
7049 return VK_POLYGON_MODE_LINE;
7051 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7057 dst->failOp = toVkStencilOp(src.failOp);
7058 dst->passOp = toVkStencilOp(src.passOp);
7059 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7060 dst->compareOp = toVkCompareOp(src.compareOp);
7066 case QRhiShaderResourceBinding::UniformBuffer:
7067 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7068 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7070 case QRhiShaderResourceBinding::SampledTexture:
7071 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7073 case QRhiShaderResourceBinding::Texture:
7074 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7076 case QRhiShaderResourceBinding::Sampler:
7077 return VK_DESCRIPTOR_TYPE_SAMPLER;
7079 case QRhiShaderResourceBinding::ImageLoad:
7080 case QRhiShaderResourceBinding::ImageStore:
7081 case QRhiShaderResourceBinding::ImageLoadStore:
7082 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7084 case QRhiShaderResourceBinding::BufferLoad:
7085 case QRhiShaderResourceBinding::BufferStore:
7086 case QRhiShaderResourceBinding::BufferLoadStore:
7087 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7090 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7097 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7098 s |= VK_SHADER_STAGE_VERTEX_BIT;
7099 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7100 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7101 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7102 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7103 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7104 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7105 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7106 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7107 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7108 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7109 return VkShaderStageFlags(s);
7115 case QRhiSampler::Never:
7116 return VK_COMPARE_OP_NEVER;
7117 case QRhiSampler::Less:
7118 return VK_COMPARE_OP_LESS;
7119 case QRhiSampler::Equal:
7120 return VK_COMPARE_OP_EQUAL;
7121 case QRhiSampler::LessOrEqual:
7122 return VK_COMPARE_OP_LESS_OR_EQUAL;
7123 case QRhiSampler::Greater:
7124 return VK_COMPARE_OP_GREATER;
7125 case QRhiSampler::NotEqual:
7126 return VK_COMPARE_OP_NOT_EQUAL;
7127 case QRhiSampler::GreaterOrEqual:
7128 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7129 case QRhiSampler::Always:
7130 return VK_COMPARE_OP_ALWAYS;
7132 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7140 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7160 e.buffer.buffers[i] = buffers[i];
7162 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7165 buffers[i] = VK_NULL_HANDLE;
7167 stagingBuffers[i] = VK_NULL_HANDLE;
7169 pendingDynamicUpdates[i].clear();
7177 rhiD->releaseQueue.append(e);
7178 rhiD->unregisterResource(
this);
7187 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7188 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7192 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7194 VkBufferCreateInfo bufferInfo = {};
7195 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7196 bufferInfo.size = nonZeroSize;
7197 bufferInfo.usage = toVkBufferUsage(m_usage);
7199 VmaAllocationCreateInfo allocInfo = {};
7201 if (m_type == Dynamic) {
7206 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7209 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7211 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7212 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7216 VkResult err = VK_SUCCESS;
7218 buffers[i] = VK_NULL_HANDLE;
7220 usageState[i].access = usageState[i].stage = 0;
7221 if (i == 0 || m_type == Dynamic) {
7222 VmaAllocation allocation;
7223 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7224 if (err != VK_SUCCESS)
7227 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7228 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7229 m_type == Dynamic ? i : -1);
7233 if (err != VK_SUCCESS) {
7234 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7235 rhiD->printExtraErrorInfo(err);
7241 rhiD->registerResource(
this);
7247 if (m_type == Dynamic) {
7253 b.objects[i] = &buffers[i];
7258 return { { &buffers[0] }, 1 };
7268 Q_ASSERT(m_type == Dynamic);
7270 Q_ASSERT(rhiD->inFrame);
7271 const int slot = rhiD->currentFrameSlot;
7273 VmaAllocation a = toVmaAllocation(allocations[slot]);
7274 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7275 if (err != VK_SUCCESS) {
7276 qWarning(
"Failed to map buffer: %d", err);
7279 return static_cast<
char *>(p);
7285 const int slot = rhiD->currentFrameSlot;
7286 VmaAllocation a = toVmaAllocation(allocations[slot]);
7287 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7288 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7292 int sampleCount, Flags flags,
7293 QRhiTexture::Format backingFormatHint)
7306 if (!memory && !backingTexture)
7313 e.renderBuffer.memory = memory;
7314 e.renderBuffer.image = image;
7315 e.renderBuffer.imageView = imageView;
7317 memory = VK_NULL_HANDLE;
7318 image = VK_NULL_HANDLE;
7319 imageView = VK_NULL_HANDLE;
7329 rhiD->releaseQueue.append(e);
7330 rhiD->unregisterResource(
this);
7336 if (memory || backingTexture)
7339 if (m_pixelSize.isEmpty())
7343 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7346 case QRhiRenderBuffer::Color:
7354 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7362 vkformat = backingTexture->vkformat;
7365 case QRhiRenderBuffer::DepthStencil:
7366 vkformat = rhiD->optimalDepthStencilFormat();
7367 if (!rhiD->createTransientImage(vkformat,
7369 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7370 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7379 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7388 rhiD->registerResource(
this);
7394 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7395 return m_backingFormatHint;
7397 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7401 int arraySize,
int sampleCount, Flags flags)
7405 stagingBuffers[i] = VK_NULL_HANDLE;
7408 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7409 perLevelImageViews[i] = VK_NULL_HANDLE;
7426 e.texture.image = owns ? image : VK_NULL_HANDLE;
7427 e.texture.imageView = imageView;
7431 e.texture.stagingBuffers[i] = stagingBuffers[i];
7434 stagingBuffers[i] = VK_NULL_HANDLE;
7438 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7439 e.texture.extraImageViews[i] = perLevelImageViews[i];
7440 perLevelImageViews[i] = VK_NULL_HANDLE;
7443 image = VK_NULL_HANDLE;
7444 imageView = VK_NULL_HANDLE;
7449 rhiD->releaseQueue.append(e);
7450 rhiD->unregisterResource(
this);
7460 vkformat = toVkTextureFormat(m_format, m_flags);
7461 if (m_writeViewFormat.format != UnknownFormat)
7462 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7464 viewFormat = vkformat;
7465 if (m_readViewFormat.format != UnknownFormat)
7466 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7468 viewFormatForSampling = vkformat;
7470 VkFormatProperties props;
7471 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7472 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7473 if (!canSampleOptimal) {
7474 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7478 const bool isCube = m_flags.testFlag(CubeMap);
7479 const bool isArray = m_flags.testFlag(TextureArray);
7480 const bool is3D = m_flags.testFlag(ThreeDimensional);
7481 const bool is1D = m_flags.testFlag(OneDimensional);
7482 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7484 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7485 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7487 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7488 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7489 if (mipLevelCount > maxLevels) {
7490 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7491 mipLevelCount = maxLevels;
7493 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7494 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7496 qWarning(
"Cubemap texture cannot be multisample");
7500 qWarning(
"3D texture cannot be multisample");
7504 qWarning(
"Multisample texture cannot have mipmaps");
7508 if (isCube && is3D) {
7509 qWarning(
"Texture cannot be both cube and 3D");
7512 if (isArray && is3D) {
7513 qWarning(
"Texture cannot be both array and 3D");
7516 if (isCube && is1D) {
7517 qWarning(
"Texture cannot be both cube and 1D");
7521 qWarning(
"Texture cannot be both 1D and 3D");
7524 if (m_depth > 1 && !is3D) {
7525 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7528 if (m_arraySize > 0 && !isArray) {
7529 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7532 if (m_arraySize < 1 && isArray) {
7533 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7537 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7538 usageState.access = 0;
7539 usageState.stage = 0;
7542 *adjustedSize = size;
7551 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7552 const bool isCube = m_flags.testFlag(CubeMap);
7553 const bool isArray = m_flags.testFlag(TextureArray);
7554 const bool is3D = m_flags.testFlag(ThreeDimensional);
7555 const bool is1D = m_flags.testFlag(OneDimensional);
7557 VkImageViewCreateInfo viewInfo = {};
7558 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7559 viewInfo.image = image;
7560 viewInfo.viewType = isCube
7561 ? VK_IMAGE_VIEW_TYPE_CUBE
7562 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7563 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7564 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7565 viewInfo.format = viewFormatForSampling;
7566 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7567 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7568 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7569 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7570 viewInfo.subresourceRange.aspectMask = aspectMask;
7573 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7574 viewInfo.subresourceRange.levelCount = mipLevelCount;
7575 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7576 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7577 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7579 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7582 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7583 if (err != VK_SUCCESS) {
7584 qWarning(
"Failed to create image view: %d", err);
7597 if (!prepareCreate(&size))
7601 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7602 const bool isDepth = isDepthTextureFormat(m_format);
7603 const bool isCube = m_flags.testFlag(CubeMap);
7604 const bool isArray = m_flags.testFlag(TextureArray);
7605 const bool is3D = m_flags.testFlag(ThreeDimensional);
7606 const bool is1D = m_flags.testFlag(OneDimensional);
7608 VkImageCreateInfo imageInfo = {};
7609 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7610 imageInfo.flags = 0;
7612 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7614 if (is3D && isRenderTarget) {
7620 if (!rhiD->caps.texture3DSliceAs2D)
7621 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7622#ifdef VK_VERSION_1_1
7623 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7625 imageInfo.flags |= 0x00000020;
7629 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7630 imageInfo.format = vkformat;
7631 imageInfo.extent.width = uint32_t(size.width());
7632 imageInfo.extent.height = uint32_t(size.height());
7633 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7634 imageInfo.mipLevels = mipLevelCount;
7635 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7636 imageInfo.samples = samples;
7637 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7638 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7640 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7641 if (isRenderTarget) {
7643 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7645 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7647 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7648 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7649 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7650 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7651 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7652 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7653#ifdef VK_KHR_fragment_shading_rate
7654 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7655 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7658 VmaAllocationCreateInfo allocInfo = {};
7659 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7661 VmaAllocation allocation;
7662 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7663 if (err != VK_SUCCESS) {
7664 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7665 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7666 int(imageInfo.format),
7667 imageInfo.mipLevels,
7668 imageInfo.arrayLayers,
7669 int(imageInfo.samples),
7671 rhiD->printExtraErrorInfo(err);
7675 rhiD->setAllocationName(allocation, m_objectName);
7680 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7683 rhiD->registerResource(
this);
7689 VkImage img = VkImage(src.object);
7693 if (!prepareCreate())
7701 usageState.layout = VkImageLayout(src.layout);
7705 rhiD->registerResource(
this);
7711 return {quint64(image), usageState.layout};
7716 usageState.layout = VkImageLayout(layout);
7721 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7722 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7723 return perLevelImageViews[level];
7725 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7726 const bool isCube = m_flags.testFlag(CubeMap);
7727 const bool isArray = m_flags.testFlag(TextureArray);
7728 const bool is3D = m_flags.testFlag(ThreeDimensional);
7729 const bool is1D = m_flags.testFlag(OneDimensional);
7731 VkImageViewCreateInfo viewInfo = {};
7732 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7733 viewInfo.image = image;
7734 viewInfo.viewType = isCube
7735 ? VK_IMAGE_VIEW_TYPE_CUBE
7736 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7737 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7738 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7739 viewInfo.format = viewFormat;
7740 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7741 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7742 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7743 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7744 viewInfo.subresourceRange.aspectMask = aspectMask;
7745 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7746 viewInfo.subresourceRange.levelCount = 1;
7747 viewInfo.subresourceRange.baseArrayLayer = 0;
7748 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7750 VkImageView v = VK_NULL_HANDLE;
7752 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7753 if (err != VK_SUCCESS) {
7754 qWarning(
"Failed to create image view: %d", err);
7755 return VK_NULL_HANDLE;
7758 perLevelImageViews[level] = v;
7763 AddressMode u, AddressMode v, AddressMode w)
7782 e.sampler.sampler = sampler;
7783 sampler = VK_NULL_HANDLE;
7787 rhiD->releaseQueue.append(e);
7788 rhiD->unregisterResource(
this);
7797 VkSamplerCreateInfo samplerInfo = {};
7798 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7799 samplerInfo.magFilter = toVkFilter(m_magFilter);
7800 samplerInfo.minFilter = toVkFilter(m_minFilter);
7801 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7802 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7803 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7804 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7805 samplerInfo.maxAnisotropy = 1.0f;
7806 samplerInfo.compareEnable = m_compareOp != Never;
7807 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7808 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7811 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7812 if (err != VK_SUCCESS) {
7813 qWarning(
"Failed to create sampler: %d", err);
7819 rhiD->registerResource(
this);
7826 serializedFormatData.reserve(64);
7840 rp = VK_NULL_HANDLE;
7848 e.renderPass.rp = rp;
7850 rp = VK_NULL_HANDLE;
7854 rhiD->releaseQueue.append(e);
7855 rhiD->unregisterResource(
this);
7861 return a.format == b.format
7862 && a.samples == b.samples
7863 && a.loadOp == b.loadOp
7864 && a.storeOp == b.storeOp
7865 && a.stencilLoadOp == b.stencilLoadOp
7866 && a.stencilStoreOp == b.stencilStoreOp
7867 && a.initialLayout == b.initialLayout
7868 && a.finalLayout == b.finalLayout;
7881 if (attDescs.size() != o->attDescs.size())
7883 if (colorRefs.size() != o->colorRefs.size())
7885 if (resolveRefs.size() != o->resolveRefs.size())
7891 if (multiViewCount != o->multiViewCount)
7896 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7897 const uint32_t attIdx = colorRefs[i].attachment;
7898 if (attIdx != o->colorRefs[i].attachment)
7900 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7905 const uint32_t attIdx = dsRef.attachment;
7906 if (attIdx != o->dsRef.attachment)
7908 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7912 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7913 const uint32_t attIdx = resolveRefs[i].attachment;
7914 if (attIdx != o->resolveRefs[i].attachment)
7916 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7921 const uint32_t attIdx = dsResolveRef.attachment;
7922 if (attIdx != o->dsResolveRef.attachment)
7924 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7929 const uint32_t attIdx = shadingRateRef.attachment;
7930 if (attIdx != o->shadingRateRef.attachment)
7932 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7943 serializedFormatData.clear();
7944 auto p =
std::back_inserter(serializedFormatData);
7946 *p++ = attDescs.size();
7947 *p++ = colorRefs.size();
7948 *p++ = resolveRefs.size();
7952 *p++ = multiViewCount;
7954 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
7955 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
7956 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
7957 *p++ = used ? a->format : 0;
7958 *p++ = used ? a->samples : 0;
7959 *p++ = used ? a->loadOp : 0;
7960 *p++ = used ? a->storeOp : 0;
7961 *p++ = used ? a->stencilLoadOp : 0;
7962 *p++ = used ? a->stencilStoreOp : 0;
7963 *p++ = used ? a->initialLayout : 0;
7964 *p++ = used ? a->finalLayout : 0;
7967 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7968 const uint32_t attIdx = colorRefs[i].attachment;
7970 serializeAttachmentData(attIdx);
7974 const uint32_t attIdx = dsRef.attachment;
7976 serializeAttachmentData(attIdx);
7979 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7980 const uint32_t attIdx = resolveRefs[i].attachment;
7982 serializeAttachmentData(attIdx);
7986 const uint32_t attIdx = dsResolveRef.attachment;
7988 serializeAttachmentData(attIdx);
7992 const uint32_t attIdx = shadingRateRef.attachment;
7994 serializeAttachmentData(attIdx);
8003 rpD->attDescs = attDescs;
8004 rpD->colorRefs = colorRefs;
8005 rpD->resolveRefs = resolveRefs;
8006 rpD->subpassDeps = subpassDeps;
8010 rpD->multiViewCount = multiViewCount;
8012 rpD->dsResolveRef = dsResolveRef;
8013 rpD->shadingRateRef = shadingRateRef;
8015 VkRenderPassCreateInfo rpInfo;
8016 VkSubpassDescription subpassDesc;
8017 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8021 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8026#ifdef VK_KHR_create_renderpass2
8027 if (rhiD->caps.renderPass2KHR) {
8029 VkRenderPassCreateInfo2KHR rpInfo2;
8030 RenderPass2SetupHelper rp2Helper(rhiD);
8031 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8035 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8036 if (err != VK_SUCCESS) {
8037 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8044 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8045 if (err != VK_SUCCESS) {
8046 qWarning(
"Failed to create renderpass: %d", err);
8053 rhiD->registerResource(rpD);
8059 return serializedFormatData;
8064 nativeHandlesStruct.renderPass = rp;
8065 return &nativeHandlesStruct;
8091 texture =
QRHI_RES(QVkTexture, src);
8123 return d.sampleCount;
8127 const QRhiTextureRenderTargetDescription &desc,
8132 rtv[att] = VK_NULL_HANDLE;
8133 resrtv[att] = VK_NULL_HANDLE;
8151 e.textureRenderTarget.fb = d.fb;
8152 d.fb = VK_NULL_HANDLE;
8155 e.textureRenderTarget.rtv[att] = rtv[att];
8156 e.textureRenderTarget.resrtv[att] = resrtv[att];
8157 rtv[att] = VK_NULL_HANDLE;
8158 resrtv[att] = VK_NULL_HANDLE;
8161 e.textureRenderTarget.dsv = dsv;
8162 dsv = VK_NULL_HANDLE;
8163 e.textureRenderTarget.resdsv = resdsv;
8164 resdsv = VK_NULL_HANDLE;
8166 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8167 shadingRateMapView = VK_NULL_HANDLE;
8171 rhiD->releaseQueue.append(e);
8172 rhiD->unregisterResource(
this);
8182 if (!rhiD->createOffscreenRenderPass(rp,
8183 m_desc.cbeginColorAttachments(),
8184 m_desc.cendColorAttachments(),
8185 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8186 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8187 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8188 m_desc.depthStencilBuffer(),
8189 m_desc.depthTexture(),
8190 m_desc.depthResolveTexture(),
8191 m_desc.shadingRateMap()))
8199 rhiD->registerResource(rp);
8208 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8209 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8210 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8213 QVarLengthArray<VkImageView, 8> views;
8214 d.multiViewCount = 0;
8216 d.colorAttCount = 0;
8218 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8219 d.colorAttCount += 1;
8222 Q_ASSERT(texD || rbD);
8224 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8225 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8226 const bool isMultiView = it->multiViewCount() >= 2;
8227 if (isMultiView && d.multiViewCount == 0)
8228 d.multiViewCount = it->multiViewCount();
8229 VkImageViewCreateInfo viewInfo = {};
8230 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8231 viewInfo.image = texD->image;
8232 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8233 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8234 : VK_IMAGE_VIEW_TYPE_2D);
8235 viewInfo.format = texD->viewFormat;
8236 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8237 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8238 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8239 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8240 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8241 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8242 viewInfo.subresourceRange.levelCount = 1;
8243 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8244 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8245 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8246 if (err != VK_SUCCESS) {
8247 qWarning(
"Failed to create render target image view: %d", err);
8250 views.append(rtv[attIndex]);
8251 if (attIndex == 0) {
8252 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8253 d.sampleCount = texD->samples;
8258 if (attIndex == 0) {
8259 d.pixelSize = rbD->pixelSize();
8260 d.sampleCount = rbD->samples;
8266 if (hasDepthStencil) {
8267 if (m_desc.depthTexture()) {
8270 VkImageViewCreateInfo viewInfo = {};
8271 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8272 viewInfo.image = depthTexD->image;
8273 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8274 viewInfo.format = depthTexD->viewFormat;
8275 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8276 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8277 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8278 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8279 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8280 viewInfo.subresourceRange.levelCount = 1;
8281 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8282 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8283 if (err != VK_SUCCESS) {
8284 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8288 if (d.colorAttCount == 0) {
8289 d.pixelSize = depthTexD->pixelSize();
8290 d.sampleCount = depthTexD->samples;
8294 views.append(depthRbD->imageView);
8295 if (d.colorAttCount == 0) {
8296 d.pixelSize = depthRbD->pixelSize();
8297 d.sampleCount = depthRbD->samples;
8305 d.resolveAttCount = 0;
8307 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8308 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8309 if (it->resolveTexture()) {
8311 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8312 d.resolveAttCount += 1;
8314 VkImageViewCreateInfo viewInfo = {};
8315 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8316 viewInfo.image = resTexD->image;
8317 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8318 : VK_IMAGE_VIEW_TYPE_2D;
8319 viewInfo.format = resTexD->viewFormat;
8320 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8321 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8322 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8323 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8324 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8325 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8326 viewInfo.subresourceRange.levelCount = 1;
8327 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8328 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8329 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8330 if (err != VK_SUCCESS) {
8331 qWarning(
"Failed to create render target resolve image view: %d", err);
8334 views.append(resrtv[attIndex]);
8338 if (m_desc.depthResolveTexture()) {
8340 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8342 VkImageViewCreateInfo viewInfo = {};
8343 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8344 viewInfo.image = resTexD->image;
8345 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8346 : VK_IMAGE_VIEW_TYPE_2D;
8347 viewInfo.format = resTexD->viewFormat;
8348 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8349 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8350 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8351 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8352 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8353 viewInfo.subresourceRange.baseMipLevel = 0;
8354 viewInfo.subresourceRange.levelCount = 1;
8355 viewInfo.subresourceRange.baseArrayLayer = 0;
8356 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8357 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8358 if (err != VK_SUCCESS) {
8359 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8362 views.append(resdsv);
8363 d.dsResolveAttCount = 1;
8365 d.dsResolveAttCount = 0;
8368 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8370 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8372 VkImageViewCreateInfo viewInfo = {};
8373 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8374 viewInfo.image = texD->image;
8375 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8376 : VK_IMAGE_VIEW_TYPE_2D;
8377 viewInfo.format = texD->viewFormat;
8378 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8379 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8380 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8381 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8382 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8383 viewInfo.subresourceRange.baseMipLevel = 0;
8384 viewInfo.subresourceRange.levelCount = 1;
8385 viewInfo.subresourceRange.baseArrayLayer = 0;
8386 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8387 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8388 if (err != VK_SUCCESS) {
8389 qWarning(
"Failed to create render target shading rate map view: %d", err);
8392 views.append(shadingRateMapView);
8393 d.shadingRateAttCount = 1;
8395 d.shadingRateAttCount = 0;
8398 if (!m_renderPassDesc)
8399 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8401 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8402 Q_ASSERT(d.rp && d.rp->rp);
8404 VkFramebufferCreateInfo fbInfo = {};
8405 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8406 fbInfo.renderPass = d.rp->rp;
8407 fbInfo.attachmentCount = uint32_t(views.count());
8408 fbInfo.pAttachments = views.constData();
8409 fbInfo.width = uint32_t(d.pixelSize.width());
8410 fbInfo.height = uint32_t(d.pixelSize.height());
8413 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8414 if (err != VK_SUCCESS) {
8415 qWarning(
"Failed to create framebuffer: %d", err);
8419 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8422 rhiD->registerResource(
this);
8428 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8441 return d.sampleCount;
8459 sortedBindings.clear();
8465 e.shaderResourceBindings.poolIndex =
poolIndex;
8466 e.shaderResourceBindings.layout = layout;
8469 layout = VK_NULL_HANDLE;
8470 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8471 descSets[i] = VK_NULL_HANDLE;
8475 rhiD->releaseQueue.append(e);
8476 rhiD->unregisterResource(
this);
8486 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8489 rhiD->updateLayoutDesc(
this);
8491 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8492 descSets[i] = VK_NULL_HANDLE;
8494 sortedBindings.clear();
8495 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8496 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8499 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8500 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8501 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8502 if (b->u.ubuf.hasDynamicOffset)
8503 hasDynamicOffset =
true;
8507 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
8508 vkbindings.reserve(sortedBindings.size());
8509 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8510 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8511 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
8512 vkbinding.binding = uint32_t(b->binding);
8513 vkbinding.descriptorType = toVkDescriptorType(b);
8514 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8515 vkbinding.descriptorCount = b->u.stex.count;
8517 vkbinding.descriptorCount = 1;
8518 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8521 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8522 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8523 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8524 layoutInfo.pBindings = vkbindings.constData();
8526 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8527 if (err != VK_SUCCESS) {
8528 qWarning(
"Failed to create descriptor set layout: %d", err);
8531 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
8533 VkDescriptorSetAllocateInfo allocInfo = {};
8534 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8537 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8538 layouts[i] = layout;
8539 allocInfo.pSetLayouts = layouts;
8540 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8544 boundResourceData[i].resize(sortedBindings.size());
8545 for (BoundResourceData &bd : boundResourceData[i])
8546 memset(&bd, 0,
sizeof(BoundResourceData));
8550 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
8554 rhiD->registerResource(
this);
8560 sortedBindings.clear();
8561 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8562 if (!flags.testFlag(BindingsAreSorted))
8563 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8575 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8576 for (BoundResourceData &bd : boundResourceData[i])
8577 memset(&bd, 0,
sizeof(BoundResourceData));
8595 if (!pipeline && !layout)
8602 e.pipelineState.pipeline = pipeline;
8603 e.pipelineState.layout = layout;
8605 pipeline = VK_NULL_HANDLE;
8606 layout = VK_NULL_HANDLE;
8610 rhiD->releaseQueue.append(e);
8611 rhiD->unregisterResource(
this);
8621 rhiD->pipelineCreationStart();
8622 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8625 if (!rhiD->ensurePipelineCache())
8628 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8629 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8630 pipelineLayoutInfo.setLayoutCount = 1;
8632 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8633 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8634 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8635 if (err != VK_SUCCESS) {
8636 qWarning(
"Failed to create pipeline layout: %d", err);
8640 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8641 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8643 QVarLengthArray<VkShaderModule, 4> shaders;
8644 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8645 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8646 const QShader bakedShader = shaderStage.shader();
8647 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8648 if (spirv.shader().isEmpty()) {
8649 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8652 VkShaderModule shader = rhiD->createShader(spirv.shader());
8654 shaders.append(shader);
8655 VkPipelineShaderStageCreateInfo shaderInfo = {};
8656 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8657 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8658 shaderInfo.module = shader;
8659 shaderInfo.pName = spirv.entryPoint().constData();
8660 shaderStageCreateInfos.append(shaderInfo);
8663 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8664 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8666 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8667#ifdef VK_EXT_vertex_attribute_divisor
8668 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8670 int bindingIndex = 0;
8671 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8672 it != itEnd; ++it, ++bindingIndex)
8674 VkVertexInputBindingDescription bindingInfo = {
8675 uint32_t(bindingIndex),
8677 it->classification() == QRhiVertexInputBinding::PerVertex
8678 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8680 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8681#ifdef VK_EXT_vertex_attribute_divisor
8682 if (rhiD->caps.vertexAttribDivisor) {
8683 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8687 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8688 "VK_EXT_vertex_attribute_divisor on the device and "
8689 "VK_KHR_get_physical_device_properties2 on the instance");
8692 vertexBindings.append(bindingInfo);
8694 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8695 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8698 VkVertexInputAttributeDescription attributeInfo = {
8699 uint32_t(it->location()),
8700 uint32_t(it->binding()),
8701 toVkAttributeFormat(it->format()),
8704 vertexAttributes.append(attributeInfo);
8706 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8707 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8708 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8709 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8710 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8711 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8712#ifdef VK_EXT_vertex_attribute_divisor
8713 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8714 if (!nonOneStepRates.isEmpty()) {
8715 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8716 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8717 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8718 vertexInputInfo.pNext = &divisorInfo;
8721 pipelineInfo.pVertexInputState = &vertexInputInfo;
8723 QVarLengthArray<VkDynamicState, 8> dynEnable;
8724 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8725 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8726 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8727 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8728 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8729 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8730#ifdef VK_KHR_fragment_shading_rate
8731 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8732 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8735 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8736 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8737 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8738 dynamicInfo.pDynamicStates = dynEnable.constData();
8739 pipelineInfo.pDynamicState = &dynamicInfo;
8741 VkPipelineViewportStateCreateInfo viewportInfo = {};
8742 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8743 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8744 pipelineInfo.pViewportState = &viewportInfo;
8746 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8747 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8748 inputAsmInfo.topology = toVkTopology(m_topology);
8749 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8750 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8752 VkPipelineTessellationStateCreateInfo tessInfo = {};
8753#ifdef VK_VERSION_1_1
8754 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8756 if (m_topology == Patches) {
8757 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8758 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8765#ifdef VK_VERSION_1_1
8766 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8767 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8768 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8769 tessInfo.pNext = &originInfo;
8771 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8774 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8777 pipelineInfo.pTessellationState = &tessInfo;
8780 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8781 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8782 if (m_depthClamp && rhiD->caps.depthClamp)
8783 rastInfo.depthClampEnable = m_depthClamp;
8784 rastInfo.cullMode = toVkCullMode(m_cullMode);
8785 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8786 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8787 rastInfo.depthBiasEnable =
true;
8788 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8789 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8791 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8792 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8793 pipelineInfo.pRasterizationState = &rastInfo;
8795 VkPipelineMultisampleStateCreateInfo msInfo = {};
8796 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8797 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8798 pipelineInfo.pMultisampleState = &msInfo;
8800 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8801 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8802 dsInfo.depthTestEnable = m_depthTest;
8803 dsInfo.depthWriteEnable = m_depthWrite;
8804 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8805 dsInfo.stencilTestEnable = m_stencilTest;
8806 if (m_stencilTest) {
8807 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8808 dsInfo.front.compareMask = m_stencilReadMask;
8809 dsInfo.front.writeMask = m_stencilWriteMask;
8810 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8811 dsInfo.back.compareMask = m_stencilReadMask;
8812 dsInfo.back.writeMask = m_stencilWriteMask;
8814 pipelineInfo.pDepthStencilState = &dsInfo;
8816 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8817 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8818 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8819 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8820 VkPipelineColorBlendAttachmentState blend = {};
8821 blend.blendEnable = b.enable;
8822 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8823 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8824 blend.colorBlendOp = toVkBlendOp(b.opColor);
8825 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8826 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8827 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8828 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8829 vktargetBlends.append(blend);
8831 if (vktargetBlends.isEmpty()) {
8832 VkPipelineColorBlendAttachmentState blend = {};
8833 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8834 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8835 vktargetBlends.append(blend);
8837 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8838 blendInfo.pAttachments = vktargetBlends.constData();
8839 pipelineInfo.pColorBlendState = &blendInfo;
8841 pipelineInfo.layout = layout;
8843 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8844 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8846 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8848 for (VkShaderModule shader : shaders)
8849 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8851 if (err != VK_SUCCESS) {
8852 qWarning(
"Failed to create graphics pipeline: %d", err);
8856 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8858 rhiD->pipelineCreationEnd();
8861 rhiD->registerResource(
this);
8877 if (!pipeline && !layout)
8884 e.pipelineState.pipeline = pipeline;
8885 e.pipelineState.layout = layout;
8887 pipeline = VK_NULL_HANDLE;
8888 layout = VK_NULL_HANDLE;
8892 rhiD->releaseQueue.append(e);
8893 rhiD->unregisterResource(
this);
8903 rhiD->pipelineCreationStart();
8904 if (!rhiD->ensurePipelineCache())
8907 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8908 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8909 pipelineLayoutInfo.setLayoutCount = 1;
8911 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8912 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8913 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8914 if (err != VK_SUCCESS) {
8915 qWarning(
"Failed to create pipeline layout: %d", err);
8919 VkComputePipelineCreateInfo pipelineInfo = {};
8920 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8921 pipelineInfo.layout = layout;
8923 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
8924 qWarning(
"Compute pipeline requires a compute shader stage");
8927 const QShader bakedShader = m_shaderStage.shader();
8928 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
8929 if (spirv.shader().isEmpty()) {
8930 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8933 if (bakedShader.stage() != QShader::ComputeStage) {
8934 qWarning() << bakedShader <<
"is not a compute shader";
8937 VkShaderModule shader = rhiD->createShader(spirv.shader());
8938 VkPipelineShaderStageCreateInfo shaderInfo = {};
8939 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8940 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8941 shaderInfo.module = shader;
8942 shaderInfo.pName = spirv.entryPoint().constData();
8943 pipelineInfo.stage = shaderInfo;
8945 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8946 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8947 if (err != VK_SUCCESS) {
8948 qWarning(
"Failed to create graphics pipeline: %d", err);
8952 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8954 rhiD->pipelineCreationEnd();
8957 rhiD->registerResource(
this);
8986 nativeHandlesStruct.commandBuffer = cb;
8988 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
8989 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
8991 nativeHandlesStruct.commandBuffer = cb;
8994 return &nativeHandlesStruct;
9012 if (sc == VK_NULL_HANDLE)
9017 rhiD->swapchains.remove(
this);
9023 frame.cmdBuf = VK_NULL_HANDLE;
9027 surface = lastConnectedSurface = VK_NULL_HANDLE;
9030 rhiD->unregisterResource(
this);
9045 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9055 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9057 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9058 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9059 if (bufferSize.width == uint32_t(-1)) {
9060 Q_ASSERT(bufferSize.height == uint32_t(-1));
9061 return m_window->size() * m_window->devicePixelRatio();
9063 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9069 case QRhiSwapChain::HDRExtendedSrgbLinear:
9070 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9071 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9072 case QRhiSwapChain::HDR10:
9073 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9074 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9075 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9076 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9077 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9090 qWarning(
"Attempted to call isFormatSupported() without a window set");
9095 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9098 uint32_t formatCount = 0;
9099 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9100 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9102 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9103 for (uint32_t i = 0; i < formatCount; ++i) {
9104 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9116 QRHI_RES_RHI(QRhiVulkan);
9118 if (m_window && rhiD->adapterLuidValid)
9119 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9133 if (!rhiD->createDefaultRenderPass(rp,
9134 m_depthStencil !=
nullptr,
9145 rhiD->registerResource(rp);
9152 case VK_FORMAT_R8_SRGB:
9153 case VK_FORMAT_R8G8_SRGB:
9154 case VK_FORMAT_R8G8B8_SRGB:
9155 case VK_FORMAT_B8G8R8_SRGB:
9156 case VK_FORMAT_R8G8B8A8_SRGB:
9157 case VK_FORMAT_B8G8R8A8_SRGB:
9158 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9173 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9175 qWarning(
"Failed to get surface for window");
9178 if (surface == surf)
9184 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9185 qWarning(
"Presenting not supported on this window");
9189 quint32 formatCount = 0;
9190 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9191 QList<VkSurfaceFormatKHR> formats(formatCount);
9192 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9196 colorFormat = formats.constFirst().format;
9197 colorSpace = formats.constFirst().colorSpace;
9200 const bool srgbRequested = m_flags.testFlag(sRGB);
9201 bool foundBestFormat =
false;
9202 if (m_format == SDR) {
9203 for (
int i = 0; i <
int(formatCount); ++i) {
9205 if (srgbRequested) {
9206 ok = defaultSrgbColorFormat == formats[i].format;
9208 ok = defaultColorFormat == formats[i].format;
9211 foundBestFormat =
true;
9212 colorFormat = formats[i].format;
9213 colorSpace = formats[i].colorSpace;
9220 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9221 for (
int i = 0; i <
int(formatCount); ++i) {
9223 if (m_format != SDR) {
9224 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9225 }
else if (srgbRequested) {
9226 ok = isSrgbFormat(formats[i].format);
9229 colorFormat = formats[i].format;
9230 colorSpace = formats[i].colorSpace;
9237 if (m_format != SDR) {
9238 VkSurfaceFormatKHR format{};
9239 format.format = colorFormat;
9240 format.colorSpace = colorSpace;
9241 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9242 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9246 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9247 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9252#if QT_CONFIG(wayland)
9257 const bool hasPassThrough =
9258 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9259 return fmt.format == colorFormat
9260 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9262 if (hasPassThrough) {
9263 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9267 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9269 quint32 presModeCount = 0;
9270 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9271 supportedPresentationModes.resize(presModeCount);
9272 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9273 supportedPresentationModes.data());
9281 const bool needsRegistration = !window || window != m_window;
9288 if (window && window != m_window)
9292 m_currentPixelSize = surfacePixelSize();
9293 pixelSize = m_currentPixelSize;
9296 qWarning(
"Failed to create new swapchain");
9300 if (needsRegistration || !rhiD->swapchains.contains(
this))
9301 rhiD->swapchains.insert(
this);
9303 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9304 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9305 m_depthStencil->sampleCount(), m_sampleCount);
9307 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9308 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9309 m_depthStencil->setPixelSize(pixelSize);
9310 if (!m_depthStencil->create())
9311 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9312 pixelSize.width(), pixelSize.height());
9314 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9315 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9316 pixelSize.width(), pixelSize.height());
9320 if (!m_renderPassDesc)
9321 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9323 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9324 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9325 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9327 rtWrapper.d.pixelSize = pixelSize;
9328 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9329 rtWrapper.d.sampleCount = samples;
9330 rtWrapper.d.colorAttCount = 1;
9331 if (m_depthStencil) {
9332 rtWrapper.d.dsAttCount = 1;
9333 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9335 rtWrapper.d.dsAttCount = 0;
9338 rtWrapper.d.dsResolveAttCount = 0;
9339 if (samples > VK_SAMPLE_COUNT_1_BIT)
9340 rtWrapper.d.resolveAttCount = 1;
9342 rtWrapper.d.resolveAttCount = 0;
9344 if (shadingRateMapView)
9345 rtWrapper.d.shadingRateAttCount = 1;
9347 rtWrapper.d.shadingRateAttCount = 0;
9352 QVarLengthArray<VkImageView, 4> views;
9353 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9355 views.append(
ds->imageView);
9356 if (samples > VK_SAMPLE_COUNT_1_BIT)
9357 views.append(image.imageView);
9358 if (shadingRateMapView)
9359 views.append(shadingRateMapView);
9361 VkFramebufferCreateInfo fbInfo = {};
9362 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9363 fbInfo.renderPass = rtWrapper.d.rp->rp;
9364 fbInfo.attachmentCount = uint32_t(views.count());
9365 fbInfo.pAttachments = views.constData();
9366 fbInfo.width = uint32_t(pixelSize.width());
9367 fbInfo.height = uint32_t(pixelSize.height());
9370 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9371 if (err != VK_SUCCESS) {
9372 qWarning(
"Failed to create framebuffer: %d", err);
9378 rtWrapperRight.setRenderPassDescriptor(
9380 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9381 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9383 rtWrapperRight.d.pixelSize = pixelSize;
9384 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9385 rtWrapperRight.d.sampleCount = samples;
9386 rtWrapperRight.d.colorAttCount = 1;
9387 if (m_depthStencil) {
9388 rtWrapperRight.d.dsAttCount = 1;
9389 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9391 rtWrapperRight.d.dsAttCount = 0;
9394 rtWrapperRight.d.dsResolveAttCount = 0;
9395 if (samples > VK_SAMPLE_COUNT_1_BIT)
9396 rtWrapperRight.d.resolveAttCount = 1;
9398 rtWrapperRight.d.resolveAttCount = 0;
9403 QVarLengthArray<VkImageView, 4> views;
9404 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9406 views.append(
ds->imageView);
9407 if (samples > VK_SAMPLE_COUNT_1_BIT)
9408 views.append(image.imageView);
9409 if (shadingRateMapView)
9410 views.append(shadingRateMapView);
9412 VkFramebufferCreateInfo fbInfo = {};
9413 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9414 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9415 fbInfo.attachmentCount = uint32_t(views.count());
9416 fbInfo.pAttachments = views.constData();
9417 fbInfo.width = uint32_t(pixelSize.width());
9418 fbInfo.height = uint32_t(pixelSize.height());
9421 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9422 if (err != VK_SUCCESS) {
9423 qWarning(
"Failed to create framebuffer: %d", err);
9431 if (needsRegistration)
9432 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)