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 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
708 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
710 if (caps.apiVersion >= QVersionNumber(1, 3))
711 physDevFeatures12.pNext = &physDevFeatures13;
713 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
714 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
715 featuresQueried =
true;
722 if (!featuresQueried) {
730 if (caps.apiVersion == QVersionNumber(1, 1)) {
731 multiviewFeaturesIfApi11 = {};
732 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
733 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
734 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
735 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
736 featuresQueried =
true;
741 if (!featuresQueried) {
744 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
745 featuresQueried =
true;
753 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
754 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
755 queryQueueFamilyProps();
756 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
757 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
758 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
759 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
760 if (!gfxQueueFamilyIdxOpt.has_value()
761 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
762 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
764 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
765 gfxQueueFamilyIdxOpt = i;
766 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
767 computelessGfxQueueCandidateIdxOpt = i;
770 if (gfxQueueFamilyIdxOpt.has_value()) {
771 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
773 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
774 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
776 qWarning(
"No graphics (or no graphics+present) queue family found");
781 VkDeviceQueueCreateInfo queueInfo = {};
782 const float prio[] = { 0 };
783 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
784 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
785 queueInfo.queueCount = 1;
786 queueInfo.pQueuePriorities = prio;
788 QList<
const char *> devLayers;
789 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
790 devLayers.append(
"VK_LAYER_KHRONOS_validation");
792 QList<
const char *> requestedDevExts;
793 requestedDevExts.append(
"VK_KHR_swapchain");
795 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
797 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
798 if (hasPhysDevProp2) {
799 requestedDevExts.append(
"VK_KHR_portability_subset");
801 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
802 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
807#ifdef VK_EXT_vertex_attribute_divisor
808 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
809 if (hasPhysDevProp2) {
810 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
811 caps.vertexAttribDivisor =
true;
816#ifdef VK_KHR_create_renderpass2
817 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
818 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
819 caps.renderPass2KHR =
true;
823#ifdef VK_KHR_depth_stencil_resolve
824 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
825 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
826 caps.depthStencilResolveKHR =
true;
830#ifdef VK_KHR_fragment_shading_rate
831 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
832 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
835#ifdef VK_EXT_device_fault
836 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
837 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
838 caps.deviceFault =
true;
842 for (
const QByteArray &ext : requestedDeviceExtensions) {
843 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
844 if (devExts.contains(ext)) {
845 requestedDevExts.append(ext.constData());
847 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
853 QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
854 for (
const QByteArray &ext : envExtList) {
855 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
856 if (devExts.contains(ext)) {
857 requestedDevExts.append(ext.constData());
859 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
865 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
866 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
867 for (
const char *ext : requestedDevExts)
868 qCDebug(QRHI_LOG_INFO,
" %s", ext);
871 VkDeviceCreateInfo devInfo = {};
872 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
873 devInfo.queueCreateInfoCount = 1;
874 devInfo.pQueueCreateInfos = &queueInfo;
875 devInfo.enabledLayerCount = uint32_t(devLayers.size());
876 devInfo.ppEnabledLayerNames = devLayers.constData();
877 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
878 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
894 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
897 physDevFeatures13.robustImageAccess = VK_FALSE;
901 if (caps.apiVersion >= QVersionNumber(1, 1)) {
908 devInfo.pNext = &physDevFeaturesChainable;
912 physDevFeatures.robustBufferAccess = VK_FALSE;
913 devInfo.pEnabledFeatures = &physDevFeatures;
916 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
917 if (err != VK_SUCCESS) {
918 qWarning(
"Failed to create device: %d", err);
922 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
927 caps.deviceFault =
true;
928 caps.vertexAttribDivisor =
true;
929 caps.renderPass2KHR =
true;
930 caps.depthStencilResolveKHR =
true;
933 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
934 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
935 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
936 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
937 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
938 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
940 df = inst->deviceFunctions(dev);
942 VkCommandPoolCreateInfo poolInfo = {};
943 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
944 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
946 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
947 if (err != VK_SUCCESS) {
948 qWarning(
"Failed to create command pool: %d", err);
953 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
954 gfxQueueFamilyIdx, gfxQueueIdx);
956 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
958 if (queueFamilyProps.isEmpty())
959 queryQueueFamilyProps();
961 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
962 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
964 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
967 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
969 caps.depthClamp = physDevFeatures.depthClamp;
971 caps.wideLines = physDevFeatures.wideLines;
973 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
975 caps.tessellation = physDevFeatures.tessellationShader;
976 caps.geometryShader = physDevFeatures.geometryShader;
978 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
981 if (caps.apiVersion >= QVersionNumber(1, 2))
982 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
986 if (caps.apiVersion == QVersionNumber(1, 1))
987 caps.multiView = multiviewFeaturesIfApi11.multiview;
990#ifdef VK_KHR_fragment_shading_rate
991 fragmentShadingRates.clear();
992 if (caps.apiVersion >= QVersionNumber(1, 1)) {
993 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
994 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
995 if (caps.imageBasedShadingRate) {
996 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
997 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
998 VkPhysicalDeviceProperties2 props2 = {};
999 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1000 props2.pNext = &shadingRateProps;
1001 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1002 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1005 if (caps.perDrawShadingRate) {
1006 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1007 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1008 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1009 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1011 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1012 fragmentShadingRates.resize(count);
1013 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1015 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1017 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1019 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1020 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1029#ifdef VK_KHR_create_renderpass2
1030 if (caps.renderPass2KHR) {
1031 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1032 if (!vkCreateRenderPass2KHR)
1033 caps.renderPass2KHR =
false;
1039 adapterLuidValid =
false;
1041#ifdef VK_VERSION_1_2
1042 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1043 VkPhysicalDeviceVulkan11Properties v11props = {};
1044 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1045 VkPhysicalDeviceProperties2 props2 = {};
1046 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1047 props2.pNext = &v11props;
1048 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1049 if (v11props.deviceLUIDValid) {
1050 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1051 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1052 adapterLuidValid =
true;
1053 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1054 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1055 adapterLuid.LowPart, adapterLuid.HighPart);
1062 VmaVulkanFunctions funcs = {};
1063 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1064 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1066 VmaAllocatorCreateInfo allocatorInfo = {};
1069 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1070 allocatorInfo.physicalDevice = physDev;
1071 allocatorInfo.device = dev;
1072 allocatorInfo.pVulkanFunctions = &funcs;
1073 allocatorInfo.instance = inst->vkInstance();
1081#ifdef VK_VERSION_1_4
1082 if (caps.apiVersion >= QVersionNumber(1, 4))
1083 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1086#ifdef VK_VERSION_1_3
1087 if (caps.apiVersion >= QVersionNumber(1, 3))
1088 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1091#ifdef VK_VERSION_1_2
1092 if (caps.apiVersion >= QVersionNumber(1, 2))
1093 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1096#ifdef VK_VERSION_1_1
1097 if (caps.apiVersion >= QVersionNumber(1, 1))
1098 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1101#ifdef VK_VERSION_1_0
1102 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1105 VmaAllocator vmaallocator;
1106 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1107 if (err != VK_SUCCESS) {
1108 qWarning(
"Failed to create allocator: %d", err);
1114 inst->installDebugOutputFilter(qvk_debug_filter);
1116 VkDescriptorPool pool;
1117 VkResult err = createDescriptorPool(&pool);
1118 if (err == VK_SUCCESS)
1119 descriptorPools.append(pool);
1121 qWarning(
"Failed to create initial descriptor pool: %d", err);
1123 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1124 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1125 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1127 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1128 if (err != VK_SUCCESS) {
1129 qWarning(
"Failed to create timestamp query pool: %d", err);
1132 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1133 timestampQueryPoolMap.fill(
false);
1135#ifdef VK_EXT_debug_utils
1136 if (caps.debugUtils) {
1137 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1138 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1139 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1140 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1144#ifdef VK_EXT_device_fault
1145 if (caps.deviceFault) {
1146 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1152 nativeHandlesStruct.physDev = physDev;
1153 nativeHandlesStruct.dev = dev;
1154 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1155 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1156 nativeHandlesStruct.gfxQueue = gfxQueue;
1157 nativeHandlesStruct.vmemAllocator = allocator;
1158 nativeHandlesStruct.inst = inst;
1169 df->vkDeviceWaitIdle(dev);
1176 dxgiHdrInfo =
nullptr;
1180 df->vkDestroyFence(dev, ofr.cmdFence,
nullptr);
1181 ofr.cmdFence = VK_NULL_HANDLE;
1184 if (pipelineCache) {
1185 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1186 pipelineCache = VK_NULL_HANDLE;
1189 for (
const DescriptorPoolData &pool : descriptorPools)
1190 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1192 descriptorPools.clear();
1194 if (timestampQueryPool) {
1195 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1196 timestampQueryPool = VK_NULL_HANDLE;
1200 vmaDestroyAllocator(toVmaAllocator(allocator));
1206 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1207 cmdPool[i] = VK_NULL_HANDLE;
1209 freeSecondaryCbs[i].clear();
1210 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1213 if (!importedDevice && dev) {
1214 df->vkDestroyDevice(dev,
nullptr);
1215 inst->resetDeviceFunctions(dev);
1216 dev = VK_NULL_HANDLE;
1226QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1228 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1229 if (nativeHandles) {
1230 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1231 requestedPhysDev = h->physDev;
1234 QRhi::AdapterList list;
1235 QVulkanFunctions *f = inst->functions();
1236 uint32_t physDevCount = 0;
1237 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1241 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1242 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1243 if (err != VK_SUCCESS || !physDevCount)
1246 VkPhysicalDeviceProperties physDevProperties = {};
1247 for (uint32_t i = 0; i < physDevCount; ++i) {
1248 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1251 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1252 QVulkanAdapter *a =
new QVulkanAdapter;
1253 a->physDev = physDevs[i];
1254 fillDriverInfo(&a->adapterInfo, physDevProperties);
1268 VkDescriptorPoolSize descPoolSizes[] = {
1269 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1270 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1271 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1272 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1273 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1275 VkDescriptorPoolCreateInfo descPoolInfo = {};
1276 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1280 descPoolInfo.flags = 0;
1282 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1283 descPoolInfo.pPoolSizes = descPoolSizes;
1284 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1289 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1290 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1291 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1292 if (r == VK_SUCCESS)
1293 descriptorPools[poolIndex].refCount += 1;
1297 int lastPoolIdx = descriptorPools.size() - 1;
1298 for (
int i = lastPoolIdx; i >= 0; --i) {
1299 if (descriptorPools[i].refCount == 0) {
1300 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1301 descriptorPools[i].allocedDescSets = 0;
1303 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1304 VkResult err = tryAllocate(i);
1305 if (err == VK_SUCCESS) {
1306 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1307 *resultPoolIndex = i;
1313 VkDescriptorPool newPool;
1314 VkResult poolErr = createDescriptorPool(&newPool);
1315 if (poolErr == VK_SUCCESS) {
1316 descriptorPools.append(newPool);
1317 lastPoolIdx = descriptorPools.size() - 1;
1318 VkResult err = tryAllocate(lastPoolIdx);
1319 if (err != VK_SUCCESS) {
1320 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1323 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1324 *resultPoolIndex = lastPoolIdx;
1327 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1334 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1336 case QRhiTexture::RGBA8:
1337 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1338 case QRhiTexture::BGRA8:
1339 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1340 case QRhiTexture::R8:
1341 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1342 case QRhiTexture::RG8:
1343 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1344 case QRhiTexture::R16:
1345 return VK_FORMAT_R16_UNORM;
1346 case QRhiTexture::RG16:
1347 return VK_FORMAT_R16G16_UNORM;
1348 case QRhiTexture::RED_OR_ALPHA8:
1349 return VK_FORMAT_R8_UNORM;
1351 case QRhiTexture::RGBA16F:
1352 return VK_FORMAT_R16G16B16A16_SFLOAT;
1353 case QRhiTexture::RGBA32F:
1354 return VK_FORMAT_R32G32B32A32_SFLOAT;
1355 case QRhiTexture::R16F:
1356 return VK_FORMAT_R16_SFLOAT;
1357 case QRhiTexture::R32F:
1358 return VK_FORMAT_R32_SFLOAT;
1360 case QRhiTexture::RGB10A2:
1362 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1364 case QRhiTexture::R8SI:
1365 return VK_FORMAT_R8_SINT;
1366 case QRhiTexture::R32SI:
1367 return VK_FORMAT_R32_SINT;
1368 case QRhiTexture::RG32SI:
1369 return VK_FORMAT_R32G32_SINT;
1370 case QRhiTexture::RGBA32SI:
1371 return VK_FORMAT_R32G32B32A32_SINT;
1373 case QRhiTexture::R8UI:
1374 return VK_FORMAT_R8_UINT;
1375 case QRhiTexture::R32UI:
1376 return VK_FORMAT_R32_UINT;
1377 case QRhiTexture::RG32UI:
1378 return VK_FORMAT_R32G32_UINT;
1379 case QRhiTexture::RGBA32UI:
1380 return VK_FORMAT_R32G32B32A32_UINT;
1382 case QRhiTexture::D16:
1383 return VK_FORMAT_D16_UNORM;
1384 case QRhiTexture::D24:
1385 return VK_FORMAT_X8_D24_UNORM_PACK32;
1386 case QRhiTexture::D24S8:
1387 return VK_FORMAT_D24_UNORM_S8_UINT;
1388 case QRhiTexture::D32F:
1389 return VK_FORMAT_D32_SFLOAT;
1390 case QRhiTexture::D32FS8:
1391 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1393 case QRhiTexture::BC1:
1394 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1395 case QRhiTexture::BC2:
1396 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1397 case QRhiTexture::BC3:
1398 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1399 case QRhiTexture::BC4:
1400 return VK_FORMAT_BC4_UNORM_BLOCK;
1401 case QRhiTexture::BC5:
1402 return VK_FORMAT_BC5_UNORM_BLOCK;
1403 case QRhiTexture::BC6H:
1404 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1405 case QRhiTexture::BC7:
1406 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1408 case QRhiTexture::ETC2_RGB8:
1409 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1410 case QRhiTexture::ETC2_RGB8A1:
1411 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1412 case QRhiTexture::ETC2_RGBA8:
1413 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1415 case QRhiTexture::ASTC_4x4:
1416 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1417 case QRhiTexture::ASTC_5x4:
1418 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1419 case QRhiTexture::ASTC_5x5:
1420 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1421 case QRhiTexture::ASTC_6x5:
1422 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1423 case QRhiTexture::ASTC_6x6:
1424 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1425 case QRhiTexture::ASTC_8x5:
1426 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1427 case QRhiTexture::ASTC_8x6:
1428 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1429 case QRhiTexture::ASTC_8x8:
1430 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1431 case QRhiTexture::ASTC_10x5:
1432 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1433 case QRhiTexture::ASTC_10x6:
1434 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1435 case QRhiTexture::ASTC_10x8:
1436 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1437 case QRhiTexture::ASTC_10x10:
1438 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1439 case QRhiTexture::ASTC_12x10:
1440 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1441 case QRhiTexture::ASTC_12x12:
1442 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1445 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1452 case VK_FORMAT_R8G8B8A8_UNORM:
1453 return QRhiTexture::RGBA8;
1454 case VK_FORMAT_R8G8B8A8_SRGB:
1456 (*flags) |= QRhiTexture::sRGB;
1457 return QRhiTexture::RGBA8;
1458 case VK_FORMAT_B8G8R8A8_UNORM:
1459 return QRhiTexture::BGRA8;
1460 case VK_FORMAT_B8G8R8A8_SRGB:
1462 (*flags) |= QRhiTexture::sRGB;
1463 return QRhiTexture::BGRA8;
1464 case VK_FORMAT_R16G16B16A16_SFLOAT:
1465 return QRhiTexture::RGBA16F;
1466 case VK_FORMAT_R32G32B32A32_SFLOAT:
1467 return QRhiTexture::RGBA32F;
1468 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1469 return QRhiTexture::RGB10A2;
1471 qWarning(
"VkFormat %d cannot be read back", format);
1474 return QRhiTexture::UnknownFormat;
1480 case QRhiTexture::Format::D16:
1481 case QRhiTexture::Format::D24:
1482 case QRhiTexture::Format::D24S8:
1483 case QRhiTexture::Format::D32F:
1484 case QRhiTexture::Format::D32FS8:
1495 case QRhiTexture::Format::D24S8:
1496 case QRhiTexture::Format::D32FS8:
1506 if (isDepthTextureFormat(format)) {
1507 if (isStencilTextureFormat(format))
1508 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1510 return VK_IMAGE_ASPECT_DEPTH_BIT;
1512 return VK_IMAGE_ASPECT_COLOR_BIT;
1523 VkPhysicalDeviceMemoryProperties physDevMemProps;
1524 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1526 VkMemoryRequirements memReq;
1527 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1528 uint32_t memTypeIndex = uint32_t(-1);
1530 if (memReq.memoryTypeBits) {
1532 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1533 bool foundDevLocal =
false;
1534 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1535 if (memReq.memoryTypeBits & (1 << i)) {
1536 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1537 if (!foundDevLocal) {
1538 foundDevLocal =
true;
1541 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1550 return memTypeIndex;
1554 const QSize &pixelSize,
1555 VkImageUsageFlags usage,
1556 VkImageAspectFlags aspectMask,
1557 VkSampleCountFlagBits samples,
1558 VkDeviceMemory *mem,
1563 VkMemoryRequirements memReq;
1566 for (
int i = 0; i < count; ++i) {
1567 VkImageCreateInfo imgInfo = {};
1568 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1569 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1570 imgInfo.format = format;
1571 imgInfo.extent.width = uint32_t(pixelSize.width());
1572 imgInfo.extent.height = uint32_t(pixelSize.height());
1573 imgInfo.extent.depth = 1;
1574 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1575 imgInfo.samples = samples;
1576 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1577 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1578 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1580 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1581 if (err != VK_SUCCESS) {
1582 qWarning(
"Failed to create image: %d", err);
1589 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1592 VkMemoryAllocateInfo memInfo = {};
1593 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1594 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1596 uint32_t startIndex = 0;
1598 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1599 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1600 qWarning(
"No suitable memory type found");
1603 startIndex = memInfo.memoryTypeIndex + 1;
1604 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1605 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1606 qWarning(
"Failed to allocate image memory: %d", err);
1609 }
while (err != VK_SUCCESS);
1611 VkDeviceSize ofs = 0;
1612 for (
int i = 0; i < count; ++i) {
1613 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1614 if (err != VK_SUCCESS) {
1615 qWarning(
"Failed to bind image memory: %d", err);
1618 ofs += aligned(memReq.size, memReq.alignment);
1620 VkImageViewCreateInfo imgViewInfo = {};
1621 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1622 imgViewInfo.image = images[i];
1623 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1624 imgViewInfo.format = format;
1625 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1626 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1627 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1628 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1629 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1630 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1632 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1633 if (err != VK_SUCCESS) {
1634 qWarning(
"Failed to create image view: %d", err);
1644 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1645 return optimalDsFormat;
1647 const VkFormat dsFormatCandidates[] = {
1648 VK_FORMAT_D24_UNORM_S8_UINT,
1649 VK_FORMAT_D32_SFLOAT_S8_UINT,
1650 VK_FORMAT_D16_UNORM_S8_UINT
1652 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1653 int dsFormatIdx = 0;
1654 while (dsFormatIdx < dsFormatCandidateCount) {
1655 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1656 VkFormatProperties fmtProp;
1657 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1658 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1662 if (dsFormatIdx == dsFormatCandidateCount)
1663 qWarning(
"Failed to find an optimal depth-stencil format");
1665 return optimalDsFormat;
1670 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1672 if (multiViewCount < 2)
1674 if (!multiViewCap) {
1675 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1678#ifdef VK_VERSION_1_1
1679 uint32_t allViewsMask = 0;
1680 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1681 allViewsMask |= (1 << i);
1682 multiViewMask = allViewsMask;
1683 multiViewCorrelationMask = allViewsMask;
1684 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1685 multiViewInfo.subpassCount = 1;
1686 multiViewInfo.pViewMasks = &multiViewMask;
1687 multiViewInfo.correlationMaskCount = 1;
1688 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1689 rpInfo->pNext = &multiViewInfo;
1694#ifdef VK_VERSION_1_1
1701#ifdef VK_KHR_create_renderpass2
1705struct RenderPass2SetupHelper
1707 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1709 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1713 if (multiViewCount >= 2) {
1714 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1715 viewMask |= (1 << i);
1718 attDescs2.resize(rpInfo->attachmentCount);
1719 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1720 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1721 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1723 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1724 att2.flags = att.flags;
1725 att2.format = att.format;
1726 att2.samples = att.samples;
1727 att2.loadOp = att.loadOp;
1728 att2.storeOp = att.storeOp;
1729 att2.stencilLoadOp = att.stencilLoadOp;
1730 att2.stencilStoreOp = att.stencilStoreOp;
1731 att2.initialLayout = att.initialLayout;
1732 att2.finalLayout = att.finalLayout;
1737 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1738 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1739 subpass2.flags = subpassDesc.flags;
1740 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1741 if (multiViewCount >= 2)
1742 subpass2.viewMask = viewMask;
1745 qsizetype startIndex = attRefs2.count();
1746 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1747 attRefs2.append({});
1748 VkAttachmentReference2KHR &attref2(attRefs2.last());
1749 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1750 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1751 attref2.attachment = attref.attachment;
1752 attref2.layout = attref.layout;
1753 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1755 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1756 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1759 if (subpassDesc.pResolveAttachments) {
1760 startIndex = attRefs2.count();
1761 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1762 attRefs2.append({});
1763 VkAttachmentReference2KHR &attref2(attRefs2.last());
1764 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1765 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1766 attref2.attachment = attref.attachment;
1767 attref2.layout = attref.layout;
1768 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1770 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1774 if (subpassDesc.pDepthStencilAttachment) {
1775 startIndex = attRefs2.count();
1776 attRefs2.append({});
1777 VkAttachmentReference2KHR &attref2(attRefs2.last());
1778 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1779 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1780 attref2.attachment = attref.attachment;
1781 attref2.layout = attref.layout;
1782 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1783 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1787#ifdef VK_KHR_depth_stencil_resolve
1789 if (rpD->hasDepthStencilResolve) {
1790 startIndex = attRefs2.count();
1791 attRefs2.append({});
1792 VkAttachmentReference2KHR &attref2(attRefs2.last());
1793 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1794 attref2.attachment = rpD->dsResolveRef.attachment;
1795 attref2.layout = rpD->dsResolveRef.layout;
1796 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1797 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1798 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1799 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1800 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1801 addToChain(&subpass2, &dsResolveDesc);
1805#ifdef VK_KHR_fragment_shading_rate
1806 shadingRateAttInfo = {};
1807 if (rpD->hasShadingRateMap) {
1808 startIndex = attRefs2.count();
1809 attRefs2.append({});
1810 VkAttachmentReference2KHR &attref2(attRefs2.last());
1811 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1812 attref2.attachment = rpD->shadingRateRef.attachment;
1813 attref2.layout = rpD->shadingRateRef.layout;
1814 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1815 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1816 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1817 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1818 addToChain(&subpass2, &shadingRateAttInfo);
1824 subpassDeps2.clear();
1825 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1826 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1827 subpassDeps2.append({});
1828 VkSubpassDependency2 &dep2(subpassDeps2.last());
1829 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1830 dep2.srcSubpass = dep.srcSubpass;
1831 dep2.dstSubpass = dep.dstSubpass;
1832 dep2.srcStageMask = dep.srcStageMask;
1833 dep2.dstStageMask = dep.dstStageMask;
1834 dep2.srcAccessMask = dep.srcAccessMask;
1835 dep2.dstAccessMask = dep.dstAccessMask;
1836 dep2.dependencyFlags = dep.dependencyFlags;
1839 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1840 rpInfo2->pNext =
nullptr;
1841 rpInfo2->flags = rpInfo->flags;
1842 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1843 rpInfo2->pAttachments = attDescs2.constData();
1844 rpInfo2->subpassCount = 1;
1845 rpInfo2->pSubpasses = &subpass2;
1846 rpInfo2->dependencyCount = subpassDeps2.count();
1847 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1848 if (multiViewCount >= 2) {
1849 rpInfo2->correlatedViewMaskCount = 1;
1850 rpInfo2->pCorrelatedViewMasks = &viewMask;
1856 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1857 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1858 VkSubpassDescription2KHR subpass2;
1859 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1860#ifdef VK_KHR_depth_stencil_resolve
1861 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1863#ifdef VK_KHR_fragment_shading_rate
1864 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1871 VkSubpassDescription *subpassDesc,
1874 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1875 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1876 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1877 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1878 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1879 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1881 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1882 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1883 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1884 rpInfo->pAttachments = rpD->attDescs.constData();
1885 rpInfo->subpassCount = 1;
1886 rpInfo->pSubpasses = subpassDesc;
1887 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1888 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1892 bool hasDepthStencil,
1893 VkSampleCountFlagBits samples,
1894 VkFormat colorFormat,
1895 QRhiShadingRateMap *shadingRateMap)
1899 VkAttachmentDescription attDesc = {};
1900 attDesc.format = colorFormat;
1901 attDesc.samples = samples;
1902 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1903 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1904 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1905 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1906 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1907 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1908 rpD->attDescs.append(attDesc);
1910 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1915 rpD->multiViewCount = 0;
1917 if (hasDepthStencil) {
1921 attDesc.format = optimalDepthStencilFormat();
1922 attDesc.samples = samples;
1923 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1924 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1925 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1926 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1927 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1928 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1929 rpD->attDescs.append(attDesc);
1931 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1936 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1938 attDesc.format = colorFormat;
1939 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1940 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1941 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1942 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1943 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1944 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1945 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1946 rpD->attDescs.append(attDesc);
1948 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1951 rpD->dsResolveRef = {};
1953 rpD->shadingRateRef = {};
1954#ifdef VK_KHR_fragment_shading_rate
1955 if (shadingRateMap) {
1957 attDesc.format = VK_FORMAT_R8_UINT;
1958 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1959 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1960 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1961 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1962 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1963 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1964 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1965 rpD->attDescs.append(attDesc);
1967 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
1972 VkSubpassDependency subpassDep = {};
1973 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1974 subpassDep.dstSubpass = 0;
1975 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1976 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1977 subpassDep.srcAccessMask = 0;
1978 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1979 rpD->subpassDeps.append(subpassDep);
1980 if (hasDepthStencil) {
1981 memset(&subpassDep, 0,
sizeof(subpassDep));
1982 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1983 subpassDep.dstSubpass = 0;
1984 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1985 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1986 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1987 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1988 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1989 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
1990 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1991 rpD->subpassDeps.append(subpassDep);
1994 VkRenderPassCreateInfo rpInfo;
1995 VkSubpassDescription subpassDesc;
1996 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
1998#ifdef VK_KHR_create_renderpass2
1999 if (caps.renderPass2KHR) {
2001 VkRenderPassCreateInfo2KHR rpInfo2;
2002 RenderPass2SetupHelper rp2Helper(
this);
2003 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2005 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2006 if (err != VK_SUCCESS) {
2007 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2014 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2015 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2016 if (err != VK_SUCCESS) {
2017 qWarning(
"Failed to create renderpass: %d", err);
2026 const QRhiColorAttachment *colorAttachmentsBegin,
2027 const QRhiColorAttachment *colorAttachmentsEnd,
2031 QRhiRenderBuffer *depthStencilBuffer,
2032 QRhiTexture *depthTexture,
2033 QRhiTexture *depthResolveTexture,
2034 QRhiShadingRateMap *shadingRateMap)
2038 int multiViewCount = 0;
2039 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2042 Q_ASSERT(texD || rbD);
2043 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2044 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2046 VkAttachmentDescription attDesc = {};
2047 attDesc.format = vkformat;
2048 attDesc.samples = samples;
2049 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2050 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2051 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2052 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2054 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2055 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2056 rpD->attDescs.append(attDesc);
2058 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2059 rpD->colorRefs.append(ref);
2061 if (it->multiViewCount() >= 2) {
2062 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2063 qWarning(
"Inconsistent multiViewCount in color attachment set");
2065 multiViewCount = it->multiViewCount();
2066 }
else if (multiViewCount > 0) {
2067 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2070 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2071 rpD->multiViewCount = uint32_t(multiViewCount);
2075 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2076 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2077 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2078 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2079 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2080 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2081 VkAttachmentDescription attDesc = {};
2082 attDesc.format = dsFormat;
2083 attDesc.samples = samples;
2084 attDesc.loadOp = loadOp;
2085 attDesc.storeOp = storeOp;
2086 attDesc.stencilLoadOp = loadOp;
2087 attDesc.stencilStoreOp = storeOp;
2088 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2089 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2090 rpD->attDescs.append(attDesc);
2091 if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
2092 multiViewCount = depthTexture->arraySize();
2093 rpD->multiViewCount = multiViewCount;
2095 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2100 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2101 if (it->resolveTexture()) {
2103 const VkFormat dstFormat = rtexD->vkformat;
2104 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2105 qWarning(
"Resolving into a multisample texture is not supported");
2109 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2110 if (srcFormat != dstFormat) {
2114 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2115 int(srcFormat),
int(dstFormat));
2118 VkAttachmentDescription attDesc = {};
2119 attDesc.format = rtexD->viewFormat;
2120 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2121 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2122 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2123 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2124 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2125 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2126 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2127 rpD->attDescs.append(attDesc);
2129 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2130 rpD->resolveRefs.append(ref);
2132 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2133 rpD->resolveRefs.append(ref);
2136 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2141 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2142 qWarning(
"Resolving into a multisample depth texture is not supported");
2145 if (texD->vkformat != rtexD->vkformat) {
2146 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2147 int(texD->vkformat),
int(rtexD->vkformat));
2150 VkAttachmentDescription attDesc = {};
2151 attDesc.format = rtexD->viewFormat;
2152 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2153 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2154 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2155 attDesc.stencilLoadOp = attDesc.loadOp;
2156 attDesc.stencilStoreOp = attDesc.storeOp;
2157 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2158 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2159 rpD->attDescs.append(attDesc);
2160 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2162 rpD->dsResolveRef = {};
2166 rpD->shadingRateRef = {};
2167#ifdef VK_KHR_fragment_shading_rate
2168 if (shadingRateMap) {
2169 VkAttachmentDescription attDesc = {};
2170 attDesc.format = VK_FORMAT_R8_UINT;
2171 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2172 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2173 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2174 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2175 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2176 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2177 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2178 rpD->attDescs.append(attDesc);
2179 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2184 VkSubpassDependency selfDependency;
2185 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
2186 selfDependency.srcSubpass = 0;
2187 selfDependency.dstSubpass = 0;
2188 selfDependency.srcStageMask = stageMask;
2189 selfDependency.dstStageMask = stageMask;
2190 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2191 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2192#ifdef VK_VERSION_1_1
2193 selfDependency.dependencyFlags = rpD->multiViewCount >= 2 ? VK_DEPENDENCY_VIEW_LOCAL_BIT : 0;
2195 selfDependency.dependencyFlags = 0;
2197 rpD->subpassDeps.append(selfDependency);
2204 VkRenderPassCreateInfo rpInfo;
2205 VkSubpassDescription subpassDesc;
2206 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2209 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2212#ifdef VK_KHR_create_renderpass2
2213 if (caps.renderPass2KHR) {
2215 VkRenderPassCreateInfo2KHR rpInfo2;
2216 RenderPass2SetupHelper rp2Helper(
this);
2217 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2220 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2221 if (err != VK_SUCCESS) {
2222 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2229 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2230 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2233 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2234 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2235 if (err != VK_SUCCESS) {
2236 qWarning(
"Failed to create renderpass: %d", err);
2247 if (swapChainD->pixelSize.isEmpty()) {
2248 qWarning(
"Surface size is 0, cannot create swapchain");
2252 df->vkDeviceWaitIdle(dev);
2254 if (!vkCreateSwapchainKHR) {
2255 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2256 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2257 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2258 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2259 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2260 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2261 qWarning(
"Swapchain functions not available");
2266 VkSurfaceCapabilitiesKHR surfaceCaps;
2267 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2268 quint32 reqBufferCount;
2269 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2270 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2272 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2274 VkSurfaceTransformFlagBitsKHR preTransform =
2275 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2276 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2277 : surfaceCaps.currentTransform;
2303 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2304 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2305 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2306 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2308 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2309 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2310 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2311 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2312 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2313 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2314 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2315 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2316 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2317 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2320 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2321 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2322 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2323 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2325 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2326 && surfaceCaps.maxImageArrayLayers > 1;
2329 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2330 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2334 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2335 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2336 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2337 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2345 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2347 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2348 reuseExisting ?
"recycled" :
"new",
2349 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2351 VkSwapchainCreateInfoKHR swapChainInfo = {};
2352 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2353 swapChainInfo.surface = swapChainD->surface;
2354 swapChainInfo.minImageCount = reqBufferCount;
2355 swapChainInfo.imageFormat = swapChainD->colorFormat;
2356 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2357 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2358 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2359 swapChainInfo.imageUsage = usage;
2360 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2361 swapChainInfo.preTransform = preTransform;
2362 swapChainInfo.compositeAlpha = compositeAlpha;
2363 swapChainInfo.presentMode = presentMode;
2364 swapChainInfo.clipped =
true;
2365 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2367 VkSwapchainKHR newSwapChain;
2368 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2369 if (err != VK_SUCCESS) {
2370 qWarning(
"Failed to create swapchain: %d", err);
2377 swapChainD->sc = newSwapChain;
2378 swapChainD->lastConnectedSurface = swapChainD->surface;
2380 quint32 actualSwapChainBufferCount = 0;
2381 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2382 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2383 qWarning(
"Failed to get swapchain images: %d", err);
2387 if (actualSwapChainBufferCount != reqBufferCount)
2388 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2391 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2392 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2393 if (err != VK_SUCCESS) {
2394 qWarning(
"Failed to get swapchain images: %d", err);
2398 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2399 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2400 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2401 if (!createTransientImage(swapChainD->colorFormat,
2402 swapChainD->pixelSize,
2403 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2404 VK_IMAGE_ASPECT_COLOR_BIT,
2405 swapChainD->samples,
2406 &swapChainD->msaaImageMem,
2409 swapChainD->bufferCount))
2411 qWarning(
"Failed to create transient image for MSAA color buffer");
2416 VkFenceCreateInfo fenceInfo = {};
2417 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2418 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2421 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2425 image.image = swapChainImages[i];
2426 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2427 image.msaaImage = msaaImages[i];
2428 image.msaaImageView = msaaViews[i];
2431 VkImageViewCreateInfo imgViewInfo = {};
2432 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2433 imgViewInfo.image = swapChainImages[i];
2434 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2435 imgViewInfo.format = swapChainD->colorFormat;
2436 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2437 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2438 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2439 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2440 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2441 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2442 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2443 if (err != VK_SUCCESS) {
2444 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2450 VkSemaphoreCreateInfo semInfo = {};
2451 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2452 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2457 image.image = swapChainImages[i];
2458 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2459 image.msaaImage = msaaImages[i];
2460 image.msaaImageView = msaaViews[i];
2463 VkImageViewCreateInfo imgViewInfo = {};
2464 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2465 imgViewInfo.image = swapChainImages[i];
2466 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2467 imgViewInfo.format = swapChainD->colorFormat;
2468 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2469 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2470 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2471 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2472 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2473 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2474 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2475 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2476 if (err != VK_SUCCESS) {
2477 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2481 VkSemaphoreCreateInfo semInfo = {};
2482 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2483 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2489 swapChainD->currentImageIndex = 0;
2491 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2493 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2494 VkImageViewCreateInfo viewInfo = {};
2495 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2496 viewInfo.image = texD->image;
2497 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2498 viewInfo.format = texD->viewFormat;
2499 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2500 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2501 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2502 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2503 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2504 viewInfo.subresourceRange.baseMipLevel = 0;
2505 viewInfo.subresourceRange.levelCount = 1;
2506 viewInfo.subresourceRange.baseArrayLayer = 0;
2507 viewInfo.subresourceRange.layerCount = 1;
2508 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2509 if (err != VK_SUCCESS) {
2510 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2515 VkSemaphoreCreateInfo semInfo = {};
2516 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2524 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2526 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2527 if (err != VK_SUCCESS) {
2528 qWarning(
"Failed to create command buffer fence: %d", err);
2534 swapChainD->currentFrameSlot = 0;
2543 if (swapChainD->sc == VK_NULL_HANDLE)
2547 df->vkDeviceWaitIdle(dev);
2551 if (frame.cmdFence) {
2553 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2554 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2555 frame.cmdFence = VK_NULL_HANDLE;
2558 if (frame.imageSem) {
2559 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2560 frame.imageSem = VK_NULL_HANDLE;
2567 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2568 image.fb = VK_NULL_HANDLE;
2570 if (image.imageView) {
2571 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2572 image.imageView = VK_NULL_HANDLE;
2574 if (image.msaaImageView) {
2575 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2576 image.msaaImageView = VK_NULL_HANDLE;
2578 if (image.msaaImage) {
2579 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2580 image.msaaImage = VK_NULL_HANDLE;
2582 if (image.drawSem) {
2583 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2584 image.drawSem = VK_NULL_HANDLE;
2588 if (swapChainD->msaaImageMem) {
2589 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2590 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2593 if (swapChainD->shadingRateMapView) {
2594 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2595 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2598 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2599 swapChainD->sc = VK_NULL_HANDLE;
2606 VkCommandPoolResetFlags flags = 0;
2611 if (releaseCachedResourcesCalledBeforeFrameStart)
2612 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2615 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2621 for (quint64 i = 0; i < timestampValidBits; i += 8)
2622 mask |= 0xFFULL << i;
2623 const quint64 ts0 = timestamp[0] & mask;
2624 const quint64 ts1 = timestamp[1] & mask;
2625 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2626 if (!qFuzzyIsNull(nsecsPerTick)) {
2627 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2628 const double elapsedSec = elapsedMs / 1000.0;
2639 const int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2642 inst->handle()->beginFrame(swapChainD->window);
2652 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2653 if (waitResult != QRhi::FrameOpSuccess)
2658 uint32_t imageIndex = 0;
2659 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2660 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2662 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2663 swapChainD->currentImageIndex = imageIndex;
2666 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2667 return QRhi::FrameOpSwapChainOutOfDate;
2669 if (err == VK_ERROR_DEVICE_LOST) {
2670 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2671 printExtraErrorInfo(err);
2673 return QRhi::FrameOpDeviceLost;
2675 qWarning(
"Failed to acquire next swapchain image: %d", err);
2676 return QRhi::FrameOpError;
2680 currentFrameSlot =
int(swapChainD->currentFrameSlot);
2683 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2689 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2690 if (cbres != QRhi::FrameOpSuccess)
2693 swapChainD->cbWrapper.cb = frame.cmdBuf;
2696 swapChainD->rtWrapper.d.fb = image.fb;
2700 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2701 swapChainD->rtWrapperRight.d.fb = image.fb;
2708 quint64 timestamp[2] = { 0, 0 };
2709 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2710 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2711 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2712 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2714 if (err == VK_SUCCESS) {
2716 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2718 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2720 qWarning(
"Failed to query timestamp: %d", err);
2725 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2726 int timestampQueryIdx = -1;
2727 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2728 if (!timestampQueryPoolMap.testBit(i)) {
2729 timestampQueryPoolMap.setBit(i);
2730 timestampQueryIdx = i * 2;
2734 if (timestampQueryIdx >= 0) {
2735 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2737 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2738 timestampQueryPool, uint32_t(timestampQueryIdx));
2743 return QRhi::FrameOpSuccess;
2751 auto cleanup = qScopeGuard([
this, swapChainD] {
2752 inst->handle()->endFrame(swapChainD->window);
2757 int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2762 VkImageMemoryBarrier presTrans = {};
2763 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2764 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2765 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2766 presTrans.image = image.image;
2767 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2768 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2772 presTrans.srcAccessMask = 0;
2773 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2774 df->vkCmdPipelineBarrier(frame.cmdBuf,
2775 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2776 0, 0,
nullptr, 0,
nullptr,
2780 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2781 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2782 df->vkCmdPipelineBarrier(frame.cmdBuf,
2783 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2784 0, 0,
nullptr, 0,
nullptr,
2792 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2798 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2799 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2801 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2802 needsPresent ? &image.drawSem :
nullptr);
2803 if (submitres != QRhi::FrameOpSuccess)
2811 VkPresentInfoKHR presInfo = {};
2812 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2813 presInfo.swapchainCount = 1;
2814 presInfo.pSwapchains = &swapChainD->sc;
2815 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2816 waitSemaphoresForPresent.append(image.drawSem);
2817 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2818 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2822 inst->presentAboutToBeQueued(swapChainD->window);
2824 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2825 waitSemaphoresForPresent.clear();
2826 if (err != VK_SUCCESS) {
2827 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2828 return QRhi::FrameOpSwapChainOutOfDate;
2829 }
else if (err != VK_SUBOPTIMAL_KHR) {
2830 if (err == VK_ERROR_DEVICE_LOST) {
2831 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2832 printExtraErrorInfo(err);
2834 return QRhi::FrameOpDeviceLost;
2836 qWarning(
"Failed to present: %d", err);
2837 return QRhi::FrameOpError;
2843 inst->presentQueued(swapChainD->window);
2853 return QRhi::FrameOpSuccess;
2872 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2882 VkCommandBufferAllocateInfo cmdBufInfo = {};
2883 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2884 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2885 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2886 cmdBufInfo.commandBufferCount = 1;
2888 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2889 if (err != VK_SUCCESS) {
2890 if (err == VK_ERROR_DEVICE_LOST) {
2891 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2892 printExtraErrorInfo(err);
2894 return QRhi::FrameOpDeviceLost;
2896 qWarning(
"Failed to allocate frame command buffer: %d", err);
2897 return QRhi::FrameOpError;
2901 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2902 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2904 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2905 if (err != VK_SUCCESS) {
2906 if (err == VK_ERROR_DEVICE_LOST) {
2907 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2908 printExtraErrorInfo(err);
2910 return QRhi::FrameOpDeviceLost;
2912 qWarning(
"Failed to begin frame command buffer: %d", err);
2913 return QRhi::FrameOpError;
2916 return QRhi::FrameOpSuccess;
2920 VkSemaphore *waitSem, VkSemaphore *signalSem)
2922 VkResult err =
df->vkEndCommandBuffer(cb);
2923 if (err != VK_SUCCESS) {
2924 if (err == VK_ERROR_DEVICE_LOST) {
2925 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2926 printExtraErrorInfo(err);
2928 return QRhi::FrameOpDeviceLost;
2930 qWarning(
"Failed to end frame command buffer: %d", err);
2931 return QRhi::FrameOpError;
2934 VkSubmitInfo submitInfo = {};
2935 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2936 submitInfo.commandBufferCount = 1;
2937 submitInfo.pCommandBuffers = &cb;
2940 waitSemaphoresForQueueSubmit.append(*waitSem);
2942 signalSemaphoresForQueueSubmit.append(*signalSem);
2944 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2945 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2946 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2947 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2948 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2950 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
2951 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
2952 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
2955 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
2957 waitSemaphoresForQueueSubmit.clear();
2958 signalSemaphoresForQueueSubmit.clear();
2960 if (err != VK_SUCCESS) {
2961 if (err == VK_ERROR_DEVICE_LOST) {
2962 qWarning(
"Device loss detected in vkQueueSubmit()");
2963 printExtraErrorInfo(err);
2965 return QRhi::FrameOpDeviceLost;
2967 qWarning(
"Failed to submit to graphics queue: %d", err);
2968 return QRhi::FrameOpError;
2971 return QRhi::FrameOpSuccess;
2976 for (QVkSwapChain *sc : std::as_const(swapchains)) {
2977 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
2978 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
2979 if (frame.cmdFenceWaitable) {
2980 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2982 if (err != VK_SUCCESS) {
2983 if (err == VK_ERROR_DEVICE_LOST) {
2984 qWarning(
"Device loss detected in vkWaitForFences()");
2985 printExtraErrorInfo(err);
2987 return QRhi::FrameOpDeviceLost;
2989 qWarning(
"Failed to wait for fence: %d", err);
2990 return QRhi::FrameOpError;
2993 df->vkResetFences(dev, 1, &frame.cmdFence);
2994 frame.cmdFenceWaitable =
false;
2998 return QRhi::FrameOpSuccess;
3012 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3014 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3015 if (waitResult != QRhi::FrameOpSuccess)
3021 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3022 if (cbres != QRhi::FrameOpSuccess)
3028 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3029 int timestampQueryIdx = -1;
3030 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3031 if (!timestampQueryPoolMap.testBit(i)) {
3032 timestampQueryPoolMap.setBit(i);
3033 timestampQueryIdx = i * 2;
3037 if (timestampQueryIdx >= 0) {
3038 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3040 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3041 timestampQueryPool, uint32_t(timestampQueryIdx));
3042 ofr.timestampQueryIndex = timestampQueryIdx;
3047 return QRhi::FrameOpSuccess;
3053 Q_ASSERT(ofr.active);
3060 if (ofr.timestampQueryIndex >= 0) {
3061 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3062 timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
3065 if (!ofr.cmdFence) {
3066 VkFenceCreateInfo fenceInfo = {};
3067 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3068 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence);
3069 if (err != VK_SUCCESS) {
3070 qWarning(
"Failed to create command buffer fence: %d", err);
3071 return QRhi::FrameOpError;
3075 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence,
nullptr,
nullptr);
3076 if (submitres != QRhi::FrameOpSuccess)
3080 df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
3081 df->vkResetFences(dev, 1, &ofr.cmdFence);
3088 if (ofr.timestampQueryIndex >= 0) {
3089 quint64 timestamp[2] = { 0, 0 };
3090 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
3091 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3092 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3093 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
3094 ofr.timestampQueryIndex = -1;
3095 if (err == VK_SUCCESS) {
3097 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3101 qWarning(
"Failed to query timestamp: %d", err);
3105 return QRhi::FrameOpSuccess;
3127 swapChainD->cbWrapper.resetCommands();
3128 cb = swapChainD->cbWrapper.cb;
3130 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3131 if (submitres != QRhi::FrameOpSuccess)
3135 df->vkQueueWaitIdle(gfxQueue);
3142 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3145 startPrimaryCommandBuffer(&frame.cmdBuf);
3146 swapChainD->cbWrapper.cb = frame.cmdBuf;
3153 return QRhi::FrameOpSuccess;
3160 u
.access =
int(bufUsage.access);
3161 u
.stage =
int(bufUsage.stage);
3169 u
.access =
int(texUsage.access);
3170 u
.stage =
int(texUsage.stage);
3176 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3179 rtD->lastActiveFrameSlot = currentFrameSlot;
3180 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3182 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3190 texD->lastActiveFrameSlot = currentFrameSlot;
3195 rbD->lastActiveFrameSlot = currentFrameSlot;
3201 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3204 if (rtD->m_desc.depthStencilBuffer()) {
3206 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3213 rbD->lastActiveFrameSlot = currentFrameSlot;
3215 if (rtD->m_desc.depthTexture()) {
3220 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3222 if (rtD->m_desc.depthResolveTexture()) {
3227 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3229 if (rtD->m_desc.shadingRateMap()) {
3234 texD->lastActiveFrameSlot = currentFrameSlot;
3248 VkCommandBuffer secondaryCb;
3250 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3251 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3252 freeSecondaryCbs[currentFrameSlot].removeLast();
3254 VkCommandBufferAllocateInfo cmdBufInfo = {};
3255 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3256 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3257 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3258 cmdBufInfo.commandBufferCount = 1;
3260 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3261 if (err != VK_SUCCESS) {
3262 qWarning(
"Failed to create secondary command buffer: %d", err);
3263 return VK_NULL_HANDLE;
3267 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3268 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3269 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3270 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3271 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3272 cmdBufInheritInfo.subpass = 0;
3274 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3275 cmdBufInheritInfo.framebuffer = rtD->fb;
3277 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3279 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3280 if (err != VK_SUCCESS) {
3281 qWarning(
"Failed to begin secondary command buffer: %d", err);
3282 return VK_NULL_HANDLE;
3290 VkResult err =
df->vkEndCommandBuffer(cb);
3291 if (err != VK_SUCCESS)
3292 qWarning(
"Failed to end secondary command buffer: %d", err);
3296 cmd.args.executeSecondary.cb = cb;
3300 e.lastActiveFrameSlot = currentFrameSlot;
3301 e.secondaryCommandBuffer.cb = cb;
3302 releaseQueue.append(e);
3306 QRhiRenderTarget *rt,
3307 const QColor &colorClearValue,
3308 const QRhiDepthStencilClearValue &depthStencilClearValue,
3309 QRhiResourceUpdateBatch *resourceUpdates,
3310 QRhiCommandBuffer::BeginPassFlags flags)
3315 if (resourceUpdates)
3325 switch (rt->resourceType()) {
3326 case QRhiResource::SwapChainRenderTarget:
3328 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3338 texD->lastActiveFrameSlot = currentFrameSlot;
3341 case QRhiResource::TextureRenderTarget:
3355 cbD->currentTarget = rt;
3360 VkRenderPassBeginInfo rpBeginInfo = {};
3361 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3362 rpBeginInfo.renderPass = rtD
->rp->rp;
3363 rpBeginInfo.framebuffer = rtD->fb;
3364 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3365 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3367 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3368 [](
const VkAttachmentDescription &attDesc) {
3369 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3370 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3373 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3374 if (rpHasAnyClearOp) {
3377 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3378 colorClearValue.alphaF() } };
3383 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3388 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3389 colorClearValue.alphaF() } };
3394 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3399 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3403 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3404 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3408 cmd.args.beginRenderPass.desc = rpBeginInfo;
3409 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3411 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3414 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3419 rateCmd.args.setShadingRate.w = 1;
3420 rateCmd.args.setShadingRate.h = 1;
3432 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3433 cbD->activeSecondaryCbStack.removeLast();
3434 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3441 cbD->currentTarget =
nullptr;
3443 if (resourceUpdates)
3448 QRhiResourceUpdateBatch *resourceUpdates,
3449 QRhiCommandBuffer::BeginPassFlags flags)
3454 if (resourceUpdates)
3462 cbD->computePassState.reset();
3465 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3476 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3477 cbD->activeSecondaryCbStack.removeLast();
3478 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3483 if (resourceUpdates)
3490 Q_ASSERT(psD->pipeline);
3494 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3496 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3500 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3501 cmd.args.bindPipeline.pipeline = psD->pipeline;
3504 cbD->currentGraphicsPipeline =
nullptr;
3505 cbD->currentComputePipeline = ps;
3506 cbD->currentPipelineGeneration = psD->generation;
3509 psD->lastActiveFrameSlot = currentFrameSlot;
3514 QRhiShaderResourceBinding::Type bindingType,
3515 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3517 VkAccessFlags access = 0;
3518 if (bindingType == loadTypeVal) {
3519 access = VK_ACCESS_SHADER_READ_BIT;
3521 access = VK_ACCESS_SHADER_WRITE_BIT;
3522 if (bindingType == loadStoreTypeVal)
3523 access |= VK_ACCESS_SHADER_READ_BIT;
3525 auto it = writtenResources->find(resource);
3526 if (it != writtenResources->end())
3527 it->first |= access;
3528 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3529 writtenResources->insert(resource, { access,
true });
3539 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3540 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3541 if (cbD->currentComputeSrb) {
3545 for (
auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
3546 accessAndIsNewFlag = { 0,
false };
3549 const int bindingCount = srbD->m_bindings.size();
3550 for (
int i = 0; i < bindingCount; ++i) {
3551 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings.at(i));
3553 case QRhiShaderResourceBinding::ImageLoad:
3554 case QRhiShaderResourceBinding::ImageStore:
3555 case QRhiShaderResourceBinding::ImageLoadStore:
3556 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3559 QRhiShaderResourceBinding::ImageLoad,
3560 QRhiShaderResourceBinding::ImageStore,
3561 QRhiShaderResourceBinding::ImageLoadStore);
3563 case QRhiShaderResourceBinding::BufferLoad:
3564 case QRhiShaderResourceBinding::BufferStore:
3565 case QRhiShaderResourceBinding::BufferLoadStore:
3566 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3569 QRhiShaderResourceBinding::BufferLoad,
3570 QRhiShaderResourceBinding::BufferStore,
3571 QRhiShaderResourceBinding::BufferLoadStore);
3578 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3579 const int accessInThisDispatch = it->first;
3580 const bool isNewInThisDispatch = it->second;
3581 if (accessInThisDispatch && !isNewInThisDispatch) {
3582 if (it.key()->resourceType() == QRhiResource::Texture) {
3584 VkImageMemoryBarrier barrier = {};
3585 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3586 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3588 barrier.subresourceRange.baseMipLevel = 0;
3589 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3590 barrier.subresourceRange.baseArrayLayer = 0;
3591 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3592 barrier.oldLayout = texD->usageState.layout;
3593 barrier.newLayout = texD->usageState.layout;
3594 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3595 barrier.dstAccessMask = accessInThisDispatch;
3596 barrier.image = texD->image;
3597 imageBarriers.append(barrier);
3600 VkBufferMemoryBarrier barrier = {};
3601 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3602 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3603 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3604 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3605 barrier.dstAccessMask = accessInThisDispatch;
3606 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3607 barrier.size = VK_WHOLE_SIZE;
3608 bufferBarriers.append(barrier);
3614 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3615 it = cbD->computePassState.writtenResources.erase(it);
3622 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3623 if (!imageBarriers.isEmpty()) {
3624 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3627 imageBarriers.size(), imageBarriers.constData());
3629 if (!bufferBarriers.isEmpty()) {
3630 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3632 bufferBarriers.size(), bufferBarriers.constData(),
3635 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3637 if (!imageBarriers.isEmpty()) {
3640 cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3641 cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3642 cmd.args.imageBarrier.count = imageBarriers.size();
3643 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3644 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3646 if (!bufferBarriers.isEmpty()) {
3649 cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3650 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3651 cmd.args.bufferBarrier.count = bufferBarriers.size();
3652 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3653 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3657 cmd.args.dispatch.x = x;
3658 cmd.args.dispatch.y = y;
3659 cmd.args.dispatch.z = z;
3665 VkShaderModuleCreateInfo shaderInfo = {};
3666 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3667 shaderInfo.codeSize = size_t(spirv.size());
3668 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3669 VkShaderModule shaderModule;
3670 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3671 if (err != VK_SUCCESS) {
3672 qWarning(
"Failed to create shader module: %d", err);
3673 return VK_NULL_HANDLE;
3675 return shaderModule;
3683 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3684 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3685 pipelineCacheInfo.initialDataSize = initialDataSize;
3686 pipelineCacheInfo.pInitialData = initialData;
3687 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3688 if (err != VK_SUCCESS) {
3689 qWarning(
"Failed to create pipeline cache: %d", err);
3699 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3700 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3701 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3702 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3703 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3705 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3706 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3709 VkWriteDescriptorSet writeInfo = {};
3710 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3711 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3712 writeInfo.dstBinding = uint32_t(b->binding);
3713 writeInfo.descriptorCount = 1;
3715 int bufferInfoIndex = -1;
3716 int imageInfoIndex = -1;
3719 case QRhiShaderResourceBinding::UniformBuffer:
3721 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3722 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3723 QRhiBuffer *buf = b->u.ubuf.buf;
3725 bd.ubuf.id = bufD->m_id;
3726 bd.ubuf.generation = bufD->generation;
3727 VkDescriptorBufferInfo bufInfo;
3728 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3729 bufInfo.offset = b->u.ubuf.offset;
3730 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3732 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3733 bufferInfoIndex = bufferInfos.size();
3734 bufferInfos.append(bufInfo);
3737 case QRhiShaderResourceBinding::SampledTexture:
3739 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3740 writeInfo.descriptorCount = data->count;
3741 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3742 ArrayOfImageDesc imageInfo(data->count);
3743 for (
int elem = 0; elem < data->count; ++elem) {
3746 bd.stex.d[elem].texId = texD->m_id;
3747 bd.stex.d[elem].texGeneration = texD->generation;
3748 bd.stex.d[elem].samplerId = samplerD->m_id;
3749 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3750 imageInfo[elem].sampler = samplerD->sampler;
3751 imageInfo[elem].imageView = texD->imageView;
3752 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3754 bd.stex.count = data->count;
3755 imageInfoIndex = imageInfos.size();
3756 imageInfos.append(imageInfo);
3759 case QRhiShaderResourceBinding::Texture:
3761 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3762 writeInfo.descriptorCount = data->count;
3763 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3764 ArrayOfImageDesc imageInfo(data->count);
3765 for (
int elem = 0; elem < data->count; ++elem) {
3767 bd.stex.d[elem].texId = texD->m_id;
3768 bd.stex.d[elem].texGeneration = texD->generation;
3769 bd.stex.d[elem].samplerId = 0;
3770 bd.stex.d[elem].samplerGeneration = 0;
3771 imageInfo[elem].sampler = VK_NULL_HANDLE;
3772 imageInfo[elem].imageView = texD->imageView;
3773 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3775 bd.stex.count = data->count;
3776 imageInfoIndex = imageInfos.size();
3777 imageInfos.append(imageInfo);
3780 case QRhiShaderResourceBinding::Sampler:
3783 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3784 bd.stex.d[0].texId = 0;
3785 bd.stex.d[0].texGeneration = 0;
3786 bd.stex.d[0].samplerId = samplerD->m_id;
3787 bd.stex.d[0].samplerGeneration = samplerD->generation;
3788 ArrayOfImageDesc imageInfo(1);
3789 imageInfo[0].sampler = samplerD->sampler;
3790 imageInfo[0].imageView = VK_NULL_HANDLE;
3791 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3792 imageInfoIndex = imageInfos.size();
3793 imageInfos.append(imageInfo);
3796 case QRhiShaderResourceBinding::ImageLoad:
3797 case QRhiShaderResourceBinding::ImageStore:
3798 case QRhiShaderResourceBinding::ImageLoadStore:
3801 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3803 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3804 bd.simage.id = texD->m_id;
3805 bd.simage.generation = texD->generation;
3806 ArrayOfImageDesc imageInfo(1);
3807 imageInfo[0].sampler = VK_NULL_HANDLE;
3808 imageInfo[0].imageView = view;
3809 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3810 imageInfoIndex = imageInfos.size();
3811 imageInfos.append(imageInfo);
3815 case QRhiShaderResourceBinding::BufferLoad:
3816 case QRhiShaderResourceBinding::BufferStore:
3817 case QRhiShaderResourceBinding::BufferLoadStore:
3820 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3821 bd.sbuf.id = bufD->m_id;
3822 bd.sbuf.generation = bufD->generation;
3823 VkDescriptorBufferInfo bufInfo;
3824 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3825 bufInfo.offset = b->u.sbuf.offset;
3826 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3827 bufferInfoIndex = bufferInfos.size();
3828 bufferInfos.append(bufInfo);
3835 writeInfos.append(writeInfo);
3836 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3839 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3840 const int bufferInfoIndex = infoIndices[i].first;
3841 const int imageInfoIndex = infoIndices[i].second;
3842 if (bufferInfoIndex >= 0)
3843 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3844 else if (imageInfoIndex >= 0)
3845 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3848 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3853 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3854 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3855 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3856 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3857 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3858 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3862 VkAccessFlags access, VkPipelineStageFlags stage)
3865 Q_ASSERT(access && stage);
3873 if (s.access == access && s.stage == stage) {
3876 if (!accessIsWrite(access))
3880 VkBufferMemoryBarrier bufMemBarrier = {};
3881 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3882 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3883 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3884 bufMemBarrier.srcAccessMask = s.access;
3885 bufMemBarrier.dstAccessMask = access;
3886 bufMemBarrier.buffer = bufD->buffers[slot];
3887 bufMemBarrier.size = VK_WHOLE_SIZE;
3891 cmd.args.bufferBarrier.srcStageMask = s.stage;
3892 cmd.args.bufferBarrier.dstStageMask = stage;
3893 cmd.args.bufferBarrier.count = 1;
3894 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3895 cbD->pools.bufferBarrier.append(bufMemBarrier);
3902 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3905 Q_ASSERT(layout && access && stage);
3907 if (s.access == access && s.stage == stage && s.layout == layout) {
3908 if (!accessIsWrite(access))
3912 VkImageMemoryBarrier barrier = {};
3913 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3914 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3915 barrier.subresourceRange.baseMipLevel = 0;
3916 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3917 barrier.subresourceRange.baseArrayLayer = 0;
3918 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3919 barrier.oldLayout = s.layout;
3920 barrier.newLayout = layout;
3921 barrier.srcAccessMask = s.access;
3922 barrier.dstAccessMask = access;
3923 barrier.image = texD->image;
3925 VkPipelineStageFlags srcStage = s.stage;
3928 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3932 cmd.args.imageBarrier.srcStageMask = srcStage;
3933 cmd.args.imageBarrier.dstStageMask = stage;
3934 cmd.args.imageBarrier.count = 1;
3935 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3936 cbD->pools.imageBarrier.append(barrier);
3947 VkImageMemoryBarrier barrier = {};
3948 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3949 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
3950 barrier.subresourceRange.baseMipLevel = 0;
3951 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3952 barrier.subresourceRange.baseArrayLayer = 0;
3953 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3954 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3955 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
3956 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3957 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
3958 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3959 barrier.image = rbD->image;
3961 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
3962 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
3966 cmd.args.imageBarrier.srcStageMask = stages;
3967 cmd.args.imageBarrier.dstStageMask = stages;
3968 cmd.args.imageBarrier.count = 1;
3969 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3970 cbD->pools.imageBarrier.append(barrier);
3974 VkImageLayout oldLayout, VkImageLayout newLayout,
3975 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
3976 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
3977 int startLayer,
int layerCount,
3978 int startLevel,
int levelCount)
3981 VkImageMemoryBarrier barrier = {};
3982 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3983 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3984 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
3985 barrier.subresourceRange.levelCount = uint32_t(levelCount);
3986 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
3987 barrier.subresourceRange.layerCount = uint32_t(layerCount);
3988 barrier.oldLayout = oldLayout;
3989 barrier.newLayout = newLayout;
3990 barrier.srcAccessMask = srcAccess;
3991 barrier.dstAccessMask = dstAccess;
3992 barrier.image = image;
3996 cmd.args.imageBarrier.srcStageMask = srcStage;
3997 cmd.args.imageBarrier.dstStageMask = dstStage;
3998 cmd.args.imageBarrier.count = 1;
3999 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4000 cbD->pools.imageBarrier.append(barrier);
4005 VkDeviceSize size = 0;
4006 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4007 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4008 if (imageSizeBytes > 0)
4009 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4014 const QRhiTextureSubresourceUploadDescription &subresDesc,
4015 size_t *curOfs,
void *mp,
4016 BufferImageCopyList *copyInfos)
4018 qsizetype copySizeBytes = 0;
4019 qsizetype imageSizeBytes = 0;
4020 const void *src =
nullptr;
4021 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4022 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4024 VkBufferImageCopy copyInfo = {};
4025 copyInfo.bufferOffset = *curOfs;
4026 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4027 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4028 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4029 copyInfo.imageSubresource.layerCount = 1;
4030 copyInfo.imageExtent.depth = 1;
4032 copyInfo.imageOffset.z = uint32_t(layer);
4034 copyInfo.imageOffset.y = uint32_t(layer);
4036 const QByteArray rawData = subresDesc.data();
4037 const QPoint dp = subresDesc.destinationTopLeft();
4038 QImage image = subresDesc.image();
4039 if (!image.isNull()) {
4040 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4041 QSize size = image.size();
4042 src = image.constBits();
4045 int bpc = qMax(1, image.depth() / 8);
4047 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4048 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4049 const int sx = subresDesc.sourceTopLeft().x();
4050 const int sy = subresDesc.sourceTopLeft().y();
4051 if (!subresDesc.sourceSize().isEmpty())
4052 size = subresDesc.sourceSize();
4053 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4054 if (size.width() == image.width()) {
4057 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4058 copySizeBytes = size.height() * image.bytesPerLine();
4060 image = image.copy(sx, sy, size.width(), size.height());
4061 src = image.constBits();
4064 copySizeBytes = image.sizeInBytes();
4065 bpc = qMax(1, image.depth() / 8);
4066 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4069 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4071 copyInfo.imageOffset.x = dp.x();
4072 copyInfo.imageOffset.y = dp.y();
4073 copyInfo.imageExtent.width = uint32_t(size.width());
4074 copyInfo.imageExtent.height = uint32_t(size.height());
4075 copyInfos->append(copyInfo);
4076 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4077 copySizeBytes = imageSizeBytes = rawData.size();
4078 src = rawData.constData();
4079 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4080 const int subresw = size.width();
4081 const int subresh = size.height();
4082 if (!subresDesc.sourceSize().isEmpty())
4083 size = subresDesc.sourceSize();
4084 const int w = size.width();
4085 const int h = size.height();
4087 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4089 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4090 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4093 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4094 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4095 copyInfos->append(copyInfo);
4096 }
else if (!rawData.isEmpty()) {
4097 copySizeBytes = imageSizeBytes = rawData.size();
4098 src = rawData.constData();
4099 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4100 if (subresDesc.dataStride()) {
4101 quint32 bytesPerPixel = 0;
4102 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4104 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4106 if (!subresDesc.sourceSize().isEmpty())
4107 size = subresDesc.sourceSize();
4108 copyInfo.imageOffset.x = dp.x();
4109 copyInfo.imageOffset.y = dp.y();
4110 copyInfo.imageExtent.width = uint32_t(size.width());
4111 copyInfo.imageExtent.height = uint32_t(size.height());
4112 copyInfos->append(copyInfo);
4114 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4118 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4119 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4125 if (err == VK_ERROR_DEVICE_LOST)
4127 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4128 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4133#ifdef VK_EXT_device_fault
4134 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4137 VkDeviceFaultCountsEXT faultCounts{};
4138 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4139 faultCounts.pNext =
nullptr;
4141 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4142 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4143 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4146 faultCounts.vendorBinarySize = 0;
4148 QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
4149 addressInfos.resize(faultCounts.addressInfoCount);
4151 QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
4152 vendorInfos.resize(faultCounts.vendorInfoCount);
4154 VkDeviceFaultInfoEXT info{};
4155 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4156 info.pNext =
nullptr;
4157 info.pAddressInfos = addressInfos.isEmpty() ?
nullptr : addressInfos.data();
4158 info.pVendorInfos = vendorInfos.isEmpty() ?
nullptr : vendorInfos.data();
4159 info.pVendorBinaryData =
nullptr;
4161 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4162 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4163 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4167 const char *desc = info.description[0] ? info.description :
"n/a";
4168 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4169 faultCounts.addressInfoCount,
4170 faultCounts.vendorInfoCount,
4171 (
unsigned long long)faultCounts.vendorBinarySize,
4174 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4175 const auto &a = addressInfos[i];
4176 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4178 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4179 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4180 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4181 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4182 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4183 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4184 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4185 default:
return "UNKNOWN";
4188 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4190 addressTypeString(a.addressType),
4191 (
unsigned long long)a.reportedAddress,
4192 (
unsigned long long)a.addressPrecision);
4195 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4196 const auto &v = vendorInfos[i];
4197 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4199 (
unsigned long long)v.vendorFaultCode,
4200 (
unsigned long long)v.vendorFaultData,
4214 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4216 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4217 bufD->pendingDynamicUpdates[i].clear();
4218 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4222 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4223 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4225 if (!bufD->stagingBuffers[currentFrameSlot]) {
4226 VkBufferCreateInfo bufferInfo = {};
4227 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4230 bufferInfo.size = bufD->m_size;
4231 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4233 VmaAllocationCreateInfo allocInfo = {};
4234 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4236 VmaAllocation allocation;
4237 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4238 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4239 if (err == VK_SUCCESS) {
4240 bufD->stagingAllocations[currentFrameSlot] = allocation;
4241 setAllocationName(allocation, bufD->name());
4243 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4244 printExtraErrorInfo(err);
4249 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4250 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4251 u.offset, u
.data.size());
4252 if (err != VK_SUCCESS) {
4253 qWarning(
"Failed to copy memory to buffer: %d", err);
4257 trackedBufferBarrier(cbD, bufD, 0,
4258 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4260 VkBufferCopy copyInfo = {};
4261 copyInfo.srcOffset = u.offset;
4262 copyInfo.dstOffset = u.offset;
4263 copyInfo.size = u
.data.size();
4267 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4268 cmd.args.copyBuffer.dst = bufD->buffers[0];
4269 cmd.args.copyBuffer.desc = copyInfo;
4278 bufD->lastActiveFrameSlot = currentFrameSlot;
4280 if (bufD->m_type == QRhiBuffer::Immutable) {
4283 e.lastActiveFrameSlot = currentFrameSlot;
4284 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4285 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4286 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4287 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4288 releaseQueue.append(e);
4292 if (bufD->m_type == QRhiBuffer::Dynamic) {
4294 u.result->data.resizeForOverwrite(u.readSize);
4295 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4296 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4297 u.offset, u.result->data.data(), u.readSize);
4298 if (err != VK_SUCCESS) {
4299 qWarning(
"Failed to copy memory from buffer: %d", err);
4300 u.result->data.clear();
4302 if (u.result->completed)
4303 u.result->completed();
4312 readback.activeFrameSlot = currentFrameSlot;
4313 readback.result = u.result;
4314 readback.byteSize = u.readSize;
4316 VkBufferCreateInfo bufferInfo = {};
4317 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4318 bufferInfo.size = readback.byteSize;
4319 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4321 VmaAllocationCreateInfo allocInfo = {};
4322 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4324 VmaAllocation allocation;
4325 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4326 if (err == VK_SUCCESS) {
4328 setAllocationName(allocation, bufD->name());
4330 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4331 printExtraErrorInfo(err);
4335 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4337 VkBufferCopy copyInfo = {};
4338 copyInfo.srcOffset = u.offset;
4339 copyInfo.size = u.readSize;
4343 cmd.args.copyBuffer.src = bufD->buffers[0];
4344 cmd.args.copyBuffer.dst = readback.stagingBuf;
4345 cmd.args.copyBuffer.desc = copyInfo;
4347 bufD->lastActiveFrameSlot = currentFrameSlot;
4349 activeBufferReadbacks.append(readback);
4359 VkDeviceSize stagingSize = 0;
4360 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4361 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4362 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4363 stagingSize += subresUploadByteSize(subresDesc);
4367 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4368 VkBufferCreateInfo bufferInfo = {};
4369 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4370 bufferInfo.size = stagingSize;
4371 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4373 VmaAllocationCreateInfo allocInfo = {};
4374 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4376 VmaAllocation allocation;
4377 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4378 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4379 if (err != VK_SUCCESS) {
4380 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4381 printExtraErrorInfo(err);
4384 utexD->stagingAllocations[currentFrameSlot] = allocation;
4385 setAllocationName(allocation, utexD->name());
4387 BufferImageCopyList copyInfos;
4390 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4391 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4392 if (err != VK_SUCCESS) {
4393 qWarning(
"Failed to map image data: %d", err);
4397 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4398 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4399 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4402 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4403 prepareUploadSubres(utexD, layer, level,
4404 subresDesc, &curOfs, mp, ©Infos);
4408 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4409 vmaUnmapMemory(toVmaAllocator(allocator), a);
4411 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4412 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4416 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4417 cmd.args.copyBufferToImage.dst = utexD->image;
4418 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4419 cmd.args.copyBufferToImage.count = copyInfos.size();
4420 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4421 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4426 e.lastActiveFrameSlot = currentFrameSlot;
4427 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4428 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4429 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4430 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4431 releaseQueue.append(e);
4436 utexD->lastActiveFrameSlot = currentFrameSlot;
4440 qWarning(
"Texture copy with matching source and destination is not supported");
4445 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4446 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4448 VkImageCopy region = {};
4449 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4450 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4451 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4452 region.srcSubresource.layerCount = 1;
4454 region.srcOffset.x = u.desc.sourceTopLeft().x();
4455 region.srcOffset.y = u.desc.sourceTopLeft().y();
4457 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4459 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4460 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4461 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4462 region.dstSubresource.layerCount = 1;
4464 region.dstOffset.x = u.desc.destinationTopLeft().x();
4465 region.dstOffset.y = u.desc.destinationTopLeft().y();
4467 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4469 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4470 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4471 region.extent.width = uint32_t(copySize.width());
4472 region.extent.height = uint32_t(copySize.height());
4473 region.extent.depth = 1;
4475 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4476 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4477 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4478 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4482 cmd.args.copyImage.src = srcD->image;
4483 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4484 cmd.args.copyImage.dst = dstD->image;
4485 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4486 cmd.args.copyImage.desc = region;
4488 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4491 readback.activeFrameSlot = currentFrameSlot;
4492 readback.desc = u.rb;
4493 readback.result = u.result;
4499 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4500 qWarning(
"Multisample texture cannot be read back");
4503 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4504 if (u.rb.rect().isValid())
4505 readback.rect = u.rb.rect();
4507 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4508 readback.format = texD->m_format;
4509 texD->lastActiveFrameSlot = currentFrameSlot;
4514 qWarning(
"Swapchain does not support readback");
4517 if (u.rb.rect().isValid())
4518 readback.rect = u.rb.rect();
4520 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4521 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4522 if (readback.format == QRhiTexture::UnknownFormat)
4528 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4531 VkBufferCreateInfo bufferInfo = {};
4532 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4533 bufferInfo.size = readback.byteSize;
4534 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4536 VmaAllocationCreateInfo allocInfo = {};
4537 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4539 VmaAllocation allocation;
4540 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4541 if (err == VK_SUCCESS) {
4543 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4545 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4546 printExtraErrorInfo(err);
4551 VkBufferImageCopy copyDesc = {};
4552 copyDesc.bufferOffset = 0;
4553 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4554 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4555 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4556 copyDesc.imageSubresource.layerCount = 1;
4557 copyDesc.imageOffset.x = readback.rect.x();
4558 copyDesc.imageOffset.y = readback.rect.y();
4560 copyDesc.imageOffset.z = u.rb.layer();
4561 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4562 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4563 copyDesc.imageExtent.depth = 1;
4566 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4567 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4570 cmd.args.copyImageToBuffer.src = texD->image;
4571 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4572 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4573 cmd.args.copyImageToBuffer.desc = copyDesc;
4577 VkImage image = imageRes.image;
4580 qWarning(
"Attempted to read back undefined swapchain image content, "
4581 "results are undefined. (do a render pass first)");
4583 subresourceBarrier(cbD, image,
4584 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4585 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4586 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4594 cmd.args.copyImageToBuffer.src = image;
4595 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4596 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4597 cmd.args.copyImageToBuffer.desc = copyDesc;
4600 activeTextureReadbacks.append(readback);
4603 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4604 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4605 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4606 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4608 VkImageLayout origLayout = utexD->usageState.layout;
4609 VkAccessFlags origAccess = utexD->usageState.access;
4610 VkPipelineStageFlags origStage = utexD->usageState.stage;
4612 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4614 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4615 int w = utexD->m_pixelSize.width();
4616 int h = utexD->m_pixelSize.height();
4617 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4618 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4620 subresourceBarrier(cbD, utexD->image,
4621 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4622 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4623 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4627 subresourceBarrier(cbD, utexD->image,
4628 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4629 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4630 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4635 subresourceBarrier(cbD, utexD->image,
4636 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4637 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4638 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4642 VkImageBlit region = {};
4643 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4644 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4645 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4646 region.srcSubresource.layerCount = 1;
4648 region.srcOffsets[1].x = qMax(1, w);
4649 region.srcOffsets[1].y = qMax(1, h);
4650 region.srcOffsets[1].z = qMax(1, depth);
4652 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4653 region.dstSubresource.mipLevel = uint32_t(level);
4654 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4655 region.dstSubresource.layerCount = 1;
4657 region.dstOffsets[1].x = qMax(1, w >> 1);
4658 region.dstOffsets[1].y = qMax(1, h >> 1);
4659 region.dstOffsets[1].z = qMax(1, depth >> 1);
4663 cmd.args.blitImage.src = utexD->image;
4664 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4665 cmd.args.blitImage.dst = utexD->image;
4666 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4667 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4668 cmd.args.blitImage.desc = region;
4675 if (utexD->mipLevelCount > 1) {
4676 subresourceBarrier(cbD, utexD->image,
4677 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4678 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4679 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4681 0,
int(utexD->mipLevelCount) - 1);
4682 subresourceBarrier(cbD, utexD->image,
4683 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4684 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4685 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4687 int(utexD->mipLevelCount) - 1, 1);
4690 utexD->lastActiveFrameSlot = currentFrameSlot;
4699 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4702 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4704 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4708 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4709 if (err != VK_SUCCESS) {
4710 qWarning(
"Failed to map buffer: %d", err);
4713 quint32 changeBegin = UINT32_MAX;
4714 quint32 changeEnd = 0;
4715 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4716 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4717 if (u.offset < changeBegin)
4718 changeBegin = u.offset;
4719 if (u.offset + u.data.size() > changeEnd)
4720 changeEnd = u.offset + u.data.size();
4722 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4723 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4724 vmaUnmapMemory(toVmaAllocator(allocator), a);
4726 bufD->pendingDynamicUpdates[slot].clear();
4732 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4733 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4739 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4740 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4741 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4746 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4747 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4749 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4750 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4751 if (e.texture.extraImageViews[i])
4752 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4758 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4763 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4765 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4768 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4769 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4772 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4773 if (e.shaderResourceBindings.poolIndex >= 0) {
4774 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4775 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4782 qrhivk_releaseRenderBuffer(e, dev,
df);
4788 qrhivk_releaseSampler(e, dev,
df);
4791 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4793 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4794 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4796 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4797 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4798 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4801 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4804 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4806 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4807 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4813 releaseQueue.removeAt(i);
4820 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4822 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4824 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4825 readback.result->format = readback.format;
4826 readback.result->pixelSize = readback.rect.size();
4827 readback.result->data.resizeForOverwrite(readback.byteSize);
4828 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4829 toVmaAllocation(readback.stagingAlloc),
4830 0, readback.result->data.data(), readback.byteSize);
4831 if (err != VK_SUCCESS) {
4832 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4833 readback.result->data.clear();
4836 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4838 if (readback.result->completed)
4839 completedCallbacks.append(readback.result->completed);
4841 activeTextureReadbacks.remove(i);
4845 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4847 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4848 readback.result->data.resizeForOverwrite(readback.byteSize);
4849 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4850 toVmaAllocation(readback.stagingAlloc),
4851 0, readback.result->data.data(), readback.byteSize);
4852 if (err != VK_SUCCESS) {
4853 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4854 readback.result->data.clear();
4857 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4859 if (readback.result->completed)
4860 completedCallbacks.append(readback.result->completed);
4862 activeBufferReadbacks.remove(i);
4866 for (
auto f : completedCallbacks)
4873} qvk_sampleCounts[] = {
4875 { VK_SAMPLE_COUNT_1_BIT, 1 },
4876 { VK_SAMPLE_COUNT_2_BIT, 2 },
4877 { VK_SAMPLE_COUNT_4_BIT, 4 },
4878 { VK_SAMPLE_COUNT_8_BIT, 8 },
4879 { VK_SAMPLE_COUNT_16_BIT, 16 },
4880 { VK_SAMPLE_COUNT_32_BIT, 32 },
4881 { VK_SAMPLE_COUNT_64_BIT, 64 }
4886 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4887 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4888 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4889 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4892 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4893 if ((color & qvk_sampleCount.mask)
4894 && (depth & qvk_sampleCount.mask)
4895 && (stencil & qvk_sampleCount.mask))
4897 result.append(qvk_sampleCount.count);
4906 const int s = effectiveSampleCount(sampleCount);
4908 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4909 if (qvk_sampleCount.count == s)
4910 return qvk_sampleCount.mask;
4913 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4918 QList<QSize> result;
4919#ifdef VK_KHR_fragment_shading_rate
4920 sampleCount = qMax(1, sampleCount);
4921 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4922 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4923 if (qvk_sampleCount.count == sampleCount) {
4924 mask = qvk_sampleCount.mask;
4928 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4929 if (s.sampleCounts & mask)
4930 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4933 Q_UNUSED(sampleCount);
4934 result.append(QSize(1, 1));
4941 cbD->passResTrackers.emplace_back();
4946 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
4953 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
4957 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
4958 1, &cmd.args.copyBuffer.desc);
4961 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
4962 cmd.args.copyBufferToImage.dstLayout,
4963 uint32_t(cmd.args.copyBufferToImage.count),
4964 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
4967 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
4968 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
4969 1, &cmd.args.copyImage.desc);
4972 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
4973 cmd.args.copyImageToBuffer.dst,
4974 1, &cmd.args.copyImageToBuffer.desc);
4977 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
4978 0, 0,
nullptr, 0,
nullptr,
4979 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
4982 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
4984 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
4988 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
4989 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
4990 1, &cmd.args.blitImage.desc,
4991 cmd.args.blitImage.filter);
4994 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
4995 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
4996 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
4997 : VK_SUBPASS_CONTENTS_INLINE);
5000 VkMemoryBarrier barrier;
5001 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5002 barrier.pNext =
nullptr;
5003 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5004 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5005 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5011 df->vkCmdEndRenderPass(cbD->cb);
5014 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5018 const uint32_t *offsets =
nullptr;
5019 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5020 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5021 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5022 cmd.args.bindDescriptorSet.pipelineLayout,
5023 0, 1, &cmd.args.bindDescriptorSet.descSet,
5024 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5029 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5030 uint32_t(cmd.args.bindVertexBuffer.count),
5031 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5032 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5035 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5036 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5039 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5042 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5045 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5048 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5051 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5052 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5055 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5056 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5057 cmd.args.drawIndexed.firstInstance);
5060#ifdef VK_EXT_debug_utils
5061 cmd.args.debugMarkerBegin.label.pLabelName =
5062 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5063 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5067#ifdef VK_EXT_debug_utils
5068 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5072#ifdef VK_EXT_debug_utils
5073 cmd.args.debugMarkerInsert.label.pLabelName =
5074 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5075 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5082 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5085 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5089#ifdef VK_KHR_fragment_shading_rate
5090 VkFragmentShadingRateCombinerOpKHR op[2] = {
5091 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5092 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5094 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5095 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5108 case QRhiPassResourceTracker::BufVertexInput:
5109 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5110 case QRhiPassResourceTracker::BufIndexRead:
5111 return VK_ACCESS_INDEX_READ_BIT;
5112 case QRhiPassResourceTracker::BufUniformRead:
5113 return VK_ACCESS_UNIFORM_READ_BIT;
5114 case QRhiPassResourceTracker::BufStorageLoad:
5115 return VK_ACCESS_SHADER_READ_BIT;
5116 case QRhiPassResourceTracker::BufStorageStore:
5117 return VK_ACCESS_SHADER_WRITE_BIT;
5118 case QRhiPassResourceTracker::BufStorageLoadStore:
5119 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5130 case QRhiPassResourceTracker::BufVertexInputStage:
5131 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5132 case QRhiPassResourceTracker::BufVertexStage:
5133 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5134 case QRhiPassResourceTracker::BufTCStage:
5135 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5136 case QRhiPassResourceTracker::BufTEStage:
5137 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5138 case QRhiPassResourceTracker::BufFragmentStage:
5139 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5140 case QRhiPassResourceTracker::BufComputeStage:
5141 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5142 case QRhiPassResourceTracker::BufGeometryStage:
5143 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5154 u.access = VkAccessFlags(usage
.access);
5155 u.stage = VkPipelineStageFlags(usage
.stage);
5162 case QRhiPassResourceTracker::TexSample:
5163 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5164 case QRhiPassResourceTracker::TexColorOutput:
5165 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5166 case QRhiPassResourceTracker::TexDepthOutput:
5167 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5168 case QRhiPassResourceTracker::TexStorageLoad:
5169 case QRhiPassResourceTracker::TexStorageStore:
5170 case QRhiPassResourceTracker::TexStorageLoadStore:
5171 return VK_IMAGE_LAYOUT_GENERAL;
5172 case QRhiPassResourceTracker::TexShadingRate:
5173#ifdef VK_KHR_fragment_shading_rate
5174 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5176 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5182 return VK_IMAGE_LAYOUT_GENERAL;
5188 case QRhiPassResourceTracker::TexSample:
5189 return VK_ACCESS_SHADER_READ_BIT;
5190 case QRhiPassResourceTracker::TexColorOutput:
5191 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5192 case QRhiPassResourceTracker::TexDepthOutput:
5193 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5194 case QRhiPassResourceTracker::TexStorageLoad:
5195 return VK_ACCESS_SHADER_READ_BIT;
5196 case QRhiPassResourceTracker::TexStorageStore:
5197 return VK_ACCESS_SHADER_WRITE_BIT;
5198 case QRhiPassResourceTracker::TexStorageLoadStore:
5199 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5212 case QRhiPassResourceTracker::TexVertexStage:
5213 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5214 case QRhiPassResourceTracker::TexTCStage:
5215 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5216 case QRhiPassResourceTracker::TexTEStage:
5217 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5218 case QRhiPassResourceTracker::TexFragmentStage:
5219 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5220 case QRhiPassResourceTracker::TexColorOutputStage:
5221 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5222 case QRhiPassResourceTracker::TexDepthOutputStage:
5223 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5224 case QRhiPassResourceTracker::TexComputeStage:
5225 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5226 case QRhiPassResourceTracker::TexGeometryStage:
5227 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5238 u.layout = VkImageLayout(usage
.layout);
5239 u.access = VkAccessFlags(usage
.access);
5240 u.stage = VkPipelineStageFlags(usage
.stage);
5251 const VkAccessFlags newAccess = toVkAccess(access);
5252 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5253 if (u.access == newAccess && u.stage == newStage) {
5254 if (!accessIsWrite(access))
5258 u.access = newAccess;
5268 const VkAccessFlags newAccess = toVkAccess(access);
5269 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5270 const VkImageLayout newLayout = toVkLayout(access);
5271 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5272 if (!accessIsWrite(access))
5276 u.layout = newLayout;
5277 u.access = newAccess;
5286 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5287 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5288 VkAccessFlags access = toVkAccess(trackedB.access);
5289 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5290 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5293 if (s.access == access && s.stage == stage) {
5294 if (!accessIsWrite(access))
5297 VkBufferMemoryBarrier bufMemBarrier = {};
5298 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5299 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5300 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5301 bufMemBarrier.srcAccessMask = s.access;
5302 bufMemBarrier.dstAccessMask = access;
5303 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5304 bufMemBarrier.size = VK_WHOLE_SIZE;
5305 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5311 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5312 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5313 VkImageLayout layout = toVkLayout(trackedT.access);
5314 VkAccessFlags access = toVkAccess(trackedT.access);
5315 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5316 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5317 if (s.access == access && s.stage == stage && s.layout == layout) {
5318 if (!accessIsWrite(access))
5321 VkImageMemoryBarrier barrier = {};
5322 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5323 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5324 barrier.subresourceRange.baseMipLevel = 0;
5325 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5326 barrier.subresourceRange.baseArrayLayer = 0;
5327 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5328 barrier.oldLayout = s.layout;
5329 barrier.newLayout = layout;
5330 barrier.srcAccessMask = s.access;
5331 barrier.dstAccessMask = access;
5332 barrier.image = texD->image;
5333 VkPipelineStageFlags srcStage = s.stage;
5336 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5337 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5346 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5347 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5348 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5350 qWarning(
"Physical device surface queries not available");
5354 return new QVkSwapChain(
this);
5357QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5359 return new QVkBuffer(
this, type, usage, size);
5364 return int(ubufAlign);
5386 static QMatrix4x4 m;
5387 if (m.isIdentity()) {
5389 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5390 0.0f, -1.0f, 0.0f, 0.0f,
5391 0.0f, 0.0f, 0.5f, 0.5f,
5392 0.0f, 0.0f, 0.0f, 1.0f);
5402 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5403 if (!physDevFeatures.textureCompressionBC)
5407 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5408 if (!physDevFeatures.textureCompressionETC2)
5412 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5413 if (!physDevFeatures.textureCompressionASTC_LDR)
5417 VkFormat vkformat = toVkTextureFormat(format, flags);
5418 VkFormatProperties props;
5419 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5420 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5426 case QRhi::MultisampleTexture:
5428 case QRhi::MultisampleRenderBuffer:
5430 case QRhi::DebugMarkers:
5431 return caps.debugUtils;
5432 case QRhi::Timestamps:
5433 return timestampValidBits != 0;
5434 case QRhi::Instancing:
5436 case QRhi::CustomInstanceStepRate:
5437 return caps.vertexAttribDivisor;
5438 case QRhi::PrimitiveRestart:
5440 case QRhi::NonDynamicUniformBuffers:
5442 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5444 case QRhi::NPOTTextureRepeat:
5446 case QRhi::RedOrAlpha8IsRed:
5448 case QRhi::ElementIndexUint:
5451 return caps.compute;
5452 case QRhi::WideLines:
5453 return caps.wideLines;
5454 case QRhi::VertexShaderPointSize:
5456 case QRhi::BaseVertex:
5458 case QRhi::BaseInstance:
5460 case QRhi::TriangleFanTopology:
5462 case QRhi::ReadBackNonUniformBuffer:
5464 case QRhi::ReadBackNonBaseMipLevel:
5466 case QRhi::TexelFetch:
5468 case QRhi::RenderToNonBaseMipLevel:
5470 case QRhi::IntAttributes:
5472 case QRhi::ScreenSpaceDerivatives:
5474 case QRhi::ReadBackAnyTextureFormat:
5476 case QRhi::PipelineCacheDataLoadSave:
5478 case QRhi::ImageDataStride:
5480 case QRhi::RenderBufferImport:
5482 case QRhi::ThreeDimensionalTextures:
5484 case QRhi::RenderTo3DTextureSlice:
5485 return caps.texture3DSliceAs2D;
5486 case QRhi::TextureArrays:
5488 case QRhi::Tessellation:
5489 return caps.tessellation;
5490 case QRhi::GeometryShader:
5491 return caps.geometryShader;
5492 case QRhi::TextureArrayRange:
5494 case QRhi::NonFillPolygonMode:
5495 return caps.nonFillPolygonMode;
5496 case QRhi::OneDimensionalTextures:
5498 case QRhi::OneDimensionalTextureMipmaps:
5500 case QRhi::HalfAttributes:
5502 case QRhi::RenderToOneDimensionalTexture:
5504 case QRhi::ThreeDimensionalTextureMipmaps:
5506 case QRhi::MultiView:
5507 return caps.multiView;
5508 case QRhi::TextureViewFormat:
5510 case QRhi::ResolveDepthStencil:
5511 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5512 case QRhi::VariableRateShading:
5513 return caps.renderPass2KHR && caps.perDrawShadingRate;
5514 case QRhi::VariableRateShadingMap:
5515 case QRhi::VariableRateShadingMapWithTexture:
5516 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5517 case QRhi::PerRenderTargetBlending:
5518 case QRhi::SampleVariables:
5520 case QRhi::InstanceIndexIncludesBaseInstance:
5522 case QRhi::DepthClamp:
5525 Q_UNREACHABLE_RETURN(
false);
5532 case QRhi::TextureSizeMin:
5534 case QRhi::TextureSizeMax:
5535 return int(physDevProperties.limits.maxImageDimension2D);
5536 case QRhi::MaxColorAttachments:
5537 return int(physDevProperties.limits.maxColorAttachments);
5538 case QRhi::FramesInFlight:
5540 case QRhi::MaxAsyncReadbackFrames:
5542 case QRhi::MaxThreadGroupsPerDimension:
5543 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5544 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5545 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5546 case QRhi::MaxThreadsPerThreadGroup:
5547 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5548 case QRhi::MaxThreadGroupX:
5549 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5550 case QRhi::MaxThreadGroupY:
5551 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5552 case QRhi::MaxThreadGroupZ:
5553 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5554 case QRhi::TextureArraySizeMax:
5555 return int(physDevProperties.limits.maxImageArrayLayers);
5556 case QRhi::MaxUniformBufferRange:
5557 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5558 case QRhi::MaxVertexInputs:
5559 return physDevProperties.limits.maxVertexInputAttributes;
5560 case QRhi::MaxVertexOutputs:
5561 return physDevProperties.limits.maxVertexOutputComponents / 4;
5562 case QRhi::ShadingRateImageTileSize:
5563 return caps.imageBasedShadingRateTileSize;
5565 Q_UNREACHABLE_RETURN(0);
5571 return &nativeHandlesStruct;
5576 return driverInfoStruct;
5582 result.totalPipelineCreationTime = totalPipelineCreationTime();
5584 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5585 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5587 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5588 for (uint32_t i = 0; i < count; ++i) {
5589 const VmaStatistics &stats(budgets[i].statistics);
5590 result.blockCount += stats.blockCount;
5591 result.allocCount += stats.allocationCount;
5592 result.usedBytes += stats.allocationBytes;
5593 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5607 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5611 waitSemaphoresForQueueSubmit.clear();
5612 if (sp->waitSemaphoreCount)
5613 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5615 signalSemaphoresForQueueSubmit.clear();
5616 if (sp->signalSemaphoreCount)
5617 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5619 waitSemaphoresForPresent.clear();
5620 if (sp->presentWaitSemaphoreCount)
5621 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5651 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5654 size_t dataSize = 0;
5655 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5656 if (err != VK_SUCCESS) {
5657 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5658 return QByteArray();
5661 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5662 data.resize(dataOffset + dataSize);
5663 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5664 if (err != VK_SUCCESS) {
5665 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5666 return QByteArray();
5670 header.rhiId = pipelineCacheRhiId();
5671 header.arch = quint32(
sizeof(
void*));
5672 header.driverVersion = physDevProperties.driverVersion;
5673 header.vendorId = physDevProperties.vendorID;
5674 header.deviceId = physDevProperties.deviceID;
5675 header.dataSize = quint32(dataSize);
5676 header.uuidSize = VK_UUID_SIZE;
5677 header.reserved = 0;
5678 memcpy(data.data(), &header, headerSize);
5679 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5690 if (data.size() < qsizetype(headerSize)) {
5691 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5695 memcpy(&header, data.constData(), headerSize);
5697 const quint32 rhiId = pipelineCacheRhiId();
5698 if (header.rhiId != rhiId) {
5699 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5700 rhiId, header.rhiId);
5703 const quint32 arch = quint32(
sizeof(
void*));
5704 if (header.arch != arch) {
5705 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5709 if (header.driverVersion != physDevProperties.driverVersion) {
5710 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5711 physDevProperties.driverVersion, header.driverVersion);
5714 if (header.vendorId != physDevProperties.vendorID) {
5715 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5716 physDevProperties.vendorID, header.vendorId);
5719 if (header.deviceId != physDevProperties.deviceID) {
5720 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5721 physDevProperties.deviceID, header.deviceId);
5724 if (header.uuidSize != VK_UUID_SIZE) {
5725 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5726 quint32(VK_UUID_SIZE), header.uuidSize);
5730 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5731 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5734 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5735 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5739 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5740 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5741 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5745 if (pipelineCache) {
5746 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5747 pipelineCache = VK_NULL_HANDLE;
5750 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5751 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5752 int(header.dataSize));
5754 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5758QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5759 int sampleCount, QRhiRenderBuffer::Flags flags,
5760 QRhiTexture::Format backingFormatHint)
5762 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5766 const QSize &pixelSize,
int depth,
int arraySize,
5767 int sampleCount, QRhiTexture::Flags flags)
5769 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5773 QRhiSampler::Filter mipmapMode,
5774 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5776 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5781 return new QVkShadingRateMap(
this);
5785 QRhiTextureRenderTarget::Flags flags)
5792 return new QVkGraphicsPipeline(
this);
5797 return new QVkComputePipeline(
this);
5802 return new QVkShaderResourceBindings(
this);
5808 Q_ASSERT(psD->pipeline);
5812 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5814 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5818 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5819 cmd.args.bindPipeline.pipeline = psD->pipeline;
5822 cbD->currentGraphicsPipeline = ps;
5823 cbD->currentComputePipeline =
nullptr;
5824 cbD->currentPipelineGeneration = psD->generation;
5827 psD->lastActiveFrameSlot = currentFrameSlot;
5831 int dynamicOffsetCount,
5832 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5842 srb = gfxPsD->m_shaderResourceBindings;
5844 srb = compPsD->m_shaderResourceBindings;
5848 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5849 bool rewriteDescSet =
false;
5850 bool addWriteBarrier =
false;
5851 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5852 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5856 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5857 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5860 case QRhiShaderResourceBinding::UniformBuffer:
5863 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5865 if (bufD->m_type == QRhiBuffer::Dynamic)
5868 bufD->lastActiveFrameSlot = currentFrameSlot;
5869 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5871 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5877 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5878 rewriteDescSet =
true;
5879 bd.ubuf.id = bufD->m_id;
5880 bd.ubuf.generation = bufD->generation;
5884 case QRhiShaderResourceBinding::SampledTexture:
5885 case QRhiShaderResourceBinding::Texture:
5886 case QRhiShaderResourceBinding::Sampler:
5888 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5889 if (bd.stex.count != data->count) {
5890 bd.stex.count = data->count;
5891 rewriteDescSet =
true;
5893 for (
int elem = 0; elem < data->count; ++elem) {
5899 Q_ASSERT(texD || samplerD);
5901 texD->lastActiveFrameSlot = currentFrameSlot;
5907 samplerD->lastActiveFrameSlot = currentFrameSlot;
5908 const quint64 texId = texD ? texD->m_id : 0;
5909 const uint texGen = texD ? texD->generation : 0;
5910 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
5911 const uint samplerGen = samplerD ? samplerD->generation : 0;
5912 if (texGen != bd.stex.d[elem].texGeneration
5913 || texId != bd.stex.d[elem].texId
5914 || samplerGen != bd.stex.d[elem].samplerGeneration
5915 || samplerId != bd.stex.d[elem].samplerId)
5917 rewriteDescSet =
true;
5918 bd.stex.d[elem].texId = texId;
5919 bd.stex.d[elem].texGeneration = texGen;
5920 bd.stex.d[elem].samplerId = samplerId;
5921 bd.stex.d[elem].samplerGeneration = samplerGen;
5926 case QRhiShaderResourceBinding::ImageLoad:
5927 case QRhiShaderResourceBinding::ImageStore:
5928 case QRhiShaderResourceBinding::ImageLoadStore:
5931 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
5932 texD->lastActiveFrameSlot = currentFrameSlot;
5934 if (b->type == QRhiShaderResourceBinding::ImageLoad)
5936 else if (b->type == QRhiShaderResourceBinding::ImageStore)
5941 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
5942 const auto prevAccess = passResTracker.textures().find(texD);
5943 if (prevAccess != passResTracker.textures().end()) {
5947 addWriteBarrier =
true;
5948 writeBarrierDstStageMask |= toVkPipelineStage(stage);
5949 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
5957 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
5958 rewriteDescSet =
true;
5959 bd.simage.id = texD->m_id;
5960 bd.simage.generation = texD->generation;
5964 case QRhiShaderResourceBinding::BufferLoad:
5965 case QRhiShaderResourceBinding::BufferStore:
5966 case QRhiShaderResourceBinding::BufferLoadStore:
5969 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
5971 if (bufD->m_type == QRhiBuffer::Dynamic)
5974 bufD->lastActiveFrameSlot = currentFrameSlot;
5976 if (b->type == QRhiShaderResourceBinding::BufferLoad)
5978 else if (b->type == QRhiShaderResourceBinding::BufferStore)
5983 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
5984 const auto prevAccess = passResTracker.buffers().find(bufD);
5985 if (prevAccess != passResTracker.buffers().end()) {
5989 addWriteBarrier =
true;
5990 writeBarrierDstStageMask |= toVkPipelineStage(stage);
5991 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
5994 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5998 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
5999 rewriteDescSet =
true;
6000 bd.sbuf.id = bufD->m_id;
6001 bd.sbuf.generation = bufD->generation;
6011 if (addWriteBarrier) {
6013 VkMemoryBarrier barrier;
6014 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6015 barrier.pNext =
nullptr;
6016 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6017 barrier.srcAccessMask = barrier.dstAccessMask;
6018 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6025 cmd.args.memoryBarrier.dependencyFlags = 0;
6026 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6027 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6028 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6029 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6035 updateShaderResourceBindings(srb);
6039 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot || srbD->hasDynamicOffset;
6041 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6043 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6044 QVarLengthArray<uint32_t, 4> dynOfs;
6050 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
6051 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
6052 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
6053 uint32_t offset = 0;
6054 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6055 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6056 if (bindingOffsetPair.first == b->binding) {
6057 offset = bindingOffsetPair.second;
6061 dynOfs.append(offset);
6067 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6068 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6069 gfxPsD ? gfxPsD->layout : compPsD->layout,
6070 0, 1, &srbD->descSets[currentFrameSlot],
6071 uint32_t(dynOfs.size()),
6072 dynOfs.size() ? dynOfs.constData() :
nullptr);
6076 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6077 : VK_PIPELINE_BIND_POINT_COMPUTE;
6078 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6079 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6080 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6081 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6082 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6086 cbD->currentGraphicsSrb = srb;
6087 cbD->currentComputeSrb =
nullptr;
6089 cbD->currentGraphicsSrb =
nullptr;
6090 cbD->currentComputeSrb = srb;
6092 cbD->currentSrbGeneration = srbD->generation;
6093 cbD->currentDescSetSlot = currentFrameSlot;
6096 srbD->lastActiveFrameSlot = currentFrameSlot;
6100 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6101 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6107 bool needsBindVBuf =
false;
6108 for (
int i = 0; i < bindingCount; ++i) {
6109 const int inputSlot = startBinding + i;
6111 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6112 bufD->lastActiveFrameSlot = currentFrameSlot;
6113 if (bufD->m_type == QRhiBuffer::Dynamic)
6116 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6117 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6118 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6120 needsBindVBuf =
true;
6121 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6122 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6126 if (needsBindVBuf) {
6127 QVarLengthArray<VkBuffer, 4> bufs;
6128 QVarLengthArray<VkDeviceSize, 4> ofs;
6129 for (
int i = 0; i < bindingCount; ++i) {
6131 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6132 bufs.append(bufD->buffers[slot]);
6133 ofs.append(bindings[i].second);
6140 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6141 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6145 cmd.args.bindVertexBuffer.startBinding = startBinding;
6146 cmd.args.bindVertexBuffer.count = bufs.size();
6147 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6148 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6149 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6150 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6156 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6157 ibufD->lastActiveFrameSlot = currentFrameSlot;
6158 if (ibufD->m_type == QRhiBuffer::Dynamic)
6161 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6162 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6163 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6164 : VK_INDEX_TYPE_UINT32;
6166 if (cbD->currentIndexBuffer != vkindexbuf
6167 || cbD->currentIndexOffset != indexOffset
6168 || cbD->currentIndexFormat != type)
6170 cbD->currentIndexBuffer = vkindexbuf;
6171 cbD->currentIndexOffset = indexOffset;
6172 cbD->currentIndexFormat = type;
6175 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6179 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6180 cmd.args.bindIndexBuffer.ofs = indexOffset;
6181 cmd.args.bindIndexBuffer.type = type;
6195 const QSize outputSize = cbD->currentTarget->pixelSize();
6199 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6203 VkViewport *vp = &cmd.args.setViewport.viewport;
6208 vp->minDepth = viewport.minDepth();
6209 vp->maxDepth = viewport.maxDepth();
6212 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6213 cbD->commands.unget();
6218 if (cbD->currentGraphicsPipeline
6222 VkRect2D *s = &cmd.args.setScissor.scissor;
6223 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
6224 s->offset.x = int32_t(x);
6225 s->offset.y = int32_t(y);
6226 s->extent.width = uint32_t(w);
6227 s->extent.height = uint32_t(h);
6229 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6230 cbD->commands.unget();
6241 Q_ASSERT(!cbD->currentGraphicsPipeline
6243 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6244 const QSize outputSize = cbD->currentTarget->pixelSize();
6248 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6252 VkRect2D *s = &cmd.args.setScissor.scissor;
6255 s->extent.width = uint32_t(w);
6256 s->extent.height = uint32_t(h);
6259 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6260 cbD->commands.unget();
6272 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6273 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6277 cmd.args.setBlendConstants.c[0] = c.redF();
6278 cmd.args.setBlendConstants.c[1] = c.greenF();
6279 cmd.args.setBlendConstants.c[2] = c.blueF();
6280 cmd.args.setBlendConstants.c[3] = c.alphaF();
6290 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6294 cmd.args.setStencilRef.ref = refValue;
6300#ifdef VK_KHR_fragment_shading_rate
6301 if (!vkCmdSetFragmentShadingRateKHR)
6304 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6305 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6306 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6308 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6309 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6310 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6312 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6313 if (cbD->passUsesSecondaryCb) {
6314 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6316 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6317 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6318 cmd.args.setShadingRate.w = size.width;
6319 cmd.args.setShadingRate.h = size.height;
6321 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6322 cbD->hasShadingRateSet =
true;
6325 Q_UNUSED(coarsePixelSize);
6330 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6336 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6340 cmd.args.draw.vertexCount = vertexCount;
6341 cmd.args.draw.instanceCount = instanceCount;
6342 cmd.args.draw.firstVertex = firstVertex;
6343 cmd.args.draw.firstInstance = firstInstance;
6348 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6354 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6355 firstIndex, vertexOffset, firstInstance);
6359 cmd.args.drawIndexed.indexCount = indexCount;
6360 cmd.args.drawIndexed.instanceCount = instanceCount;
6361 cmd.args.drawIndexed.firstIndex = firstIndex;
6362 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6363 cmd.args.drawIndexed.firstInstance = firstInstance;
6369#ifdef VK_EXT_debug_utils
6370 if (!debugMarkers || !caps.debugUtils)
6373 VkDebugUtilsLabelEXT label = {};
6374 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6376 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6377 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6378 label.pLabelName = name.constData();
6379 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6381 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6382 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6383 cmd.args.debugMarkerBegin.label = label;
6384 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6385 cbD->pools.debugMarkerData.append(name);
6395#ifdef VK_EXT_debug_utils
6396 if (!debugMarkers || !caps.debugUtils)
6399 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6400 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6401 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6403 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6404 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6413#ifdef VK_EXT_debug_utils
6414 if (!debugMarkers || !caps.debugUtils)
6417 VkDebugUtilsLabelEXT label = {};
6418 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6420 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6421 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6422 label.pLabelName = msg.constData();
6423 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6425 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6426 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6427 cmd.args.debugMarkerInsert.label = label;
6428 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6429 cbD->pools.debugMarkerData.append(msg);
6439 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6444 Q_ASSERT(cbD->currentTarget);
6447 switch (cbD->currentTarget->resourceType()) {
6448 case QRhiResource::SwapChainRenderTarget:
6451 case QRhiResource::TextureRenderTarget:
6483 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6484 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6488 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6489 cbD->activeSecondaryCbStack.removeLast();
6490 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6492 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6494 cbD->activeSecondaryCbStack.append(extCb);
6506 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6507 cbD->activeSecondaryCbStack.removeLast();
6508 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6509 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6523 if (!debugMarkers || name.isEmpty())
6526 QByteArray decoratedName = name;
6528 decoratedName +=
'/';
6529 decoratedName += QByteArray::number(slot);
6531 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6536#ifdef VK_EXT_debug_utils
6537 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6540 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6541 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6542 nameInfo.objectType = type;
6543 nameInfo.objectHandle = object;
6544 QByteArray decoratedName = name;
6546 decoratedName +=
'/';
6547 decoratedName += QByteArray::number(slot);
6549 nameInfo.pObjectName = decoratedName.constData();
6550 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6562 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6563 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6564 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6565 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6566 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6567 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6568 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6569 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6570 return VkBufferUsageFlagBits(u);
6576 case QRhiSampler::Nearest:
6577 return VK_FILTER_NEAREST;
6578 case QRhiSampler::Linear:
6579 return VK_FILTER_LINEAR;
6581 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6588 case QRhiSampler::None:
6589 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6590 case QRhiSampler::Nearest:
6591 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6592 case QRhiSampler::Linear:
6593 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6595 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6602 case QRhiSampler::Repeat:
6603 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6604 case QRhiSampler::ClampToEdge:
6605 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6606 case QRhiSampler::Mirror:
6607 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6609 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6616 case QRhiShaderStage::Vertex:
6617 return VK_SHADER_STAGE_VERTEX_BIT;
6618 case QRhiShaderStage::TessellationControl:
6619 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6620 case QRhiShaderStage::TessellationEvaluation:
6621 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6622 case QRhiShaderStage::Fragment:
6623 return VK_SHADER_STAGE_FRAGMENT_BIT;
6624 case QRhiShaderStage::Compute:
6625 return VK_SHADER_STAGE_COMPUTE_BIT;
6626 case QRhiShaderStage::Geometry:
6627 return VK_SHADER_STAGE_GEOMETRY_BIT;
6629 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6636 case QRhiVertexInputAttribute::Float4:
6637 return VK_FORMAT_R32G32B32A32_SFLOAT;
6638 case QRhiVertexInputAttribute::Float3:
6639 return VK_FORMAT_R32G32B32_SFLOAT;
6640 case QRhiVertexInputAttribute::Float2:
6641 return VK_FORMAT_R32G32_SFLOAT;
6642 case QRhiVertexInputAttribute::Float:
6643 return VK_FORMAT_R32_SFLOAT;
6644 case QRhiVertexInputAttribute::UNormByte4:
6645 return VK_FORMAT_R8G8B8A8_UNORM;
6646 case QRhiVertexInputAttribute::UNormByte2:
6647 return VK_FORMAT_R8G8_UNORM;
6648 case QRhiVertexInputAttribute::UNormByte:
6649 return VK_FORMAT_R8_UNORM;
6650 case QRhiVertexInputAttribute::UInt4:
6651 return VK_FORMAT_R32G32B32A32_UINT;
6652 case QRhiVertexInputAttribute::UInt3:
6653 return VK_FORMAT_R32G32B32_UINT;
6654 case QRhiVertexInputAttribute::UInt2:
6655 return VK_FORMAT_R32G32_UINT;
6656 case QRhiVertexInputAttribute::UInt:
6657 return VK_FORMAT_R32_UINT;
6658 case QRhiVertexInputAttribute::SInt4:
6659 return VK_FORMAT_R32G32B32A32_SINT;
6660 case QRhiVertexInputAttribute::SInt3:
6661 return VK_FORMAT_R32G32B32_SINT;
6662 case QRhiVertexInputAttribute::SInt2:
6663 return VK_FORMAT_R32G32_SINT;
6664 case QRhiVertexInputAttribute::SInt:
6665 return VK_FORMAT_R32_SINT;
6666 case QRhiVertexInputAttribute::Half4:
6667 return VK_FORMAT_R16G16B16A16_SFLOAT;
6668 case QRhiVertexInputAttribute::Half3:
6669 return VK_FORMAT_R16G16B16_SFLOAT;
6670 case QRhiVertexInputAttribute::Half2:
6671 return VK_FORMAT_R16G16_SFLOAT;
6672 case QRhiVertexInputAttribute::Half:
6673 return VK_FORMAT_R16_SFLOAT;
6674 case QRhiVertexInputAttribute::UShort4:
6675 return VK_FORMAT_R16G16B16A16_UINT;
6676 case QRhiVertexInputAttribute::UShort3:
6677 return VK_FORMAT_R16G16B16_UINT;
6678 case QRhiVertexInputAttribute::UShort2:
6679 return VK_FORMAT_R16G16_UINT;
6680 case QRhiVertexInputAttribute::UShort:
6681 return VK_FORMAT_R16_UINT;
6682 case QRhiVertexInputAttribute::SShort4:
6683 return VK_FORMAT_R16G16B16A16_SINT;
6684 case QRhiVertexInputAttribute::SShort3:
6685 return VK_FORMAT_R16G16B16_SINT;
6686 case QRhiVertexInputAttribute::SShort2:
6687 return VK_FORMAT_R16G16_SINT;
6688 case QRhiVertexInputAttribute::SShort:
6689 return VK_FORMAT_R16_SINT;
6691 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6698 case QRhiGraphicsPipeline::Triangles:
6699 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6700 case QRhiGraphicsPipeline::TriangleStrip:
6701 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6702 case QRhiGraphicsPipeline::TriangleFan:
6703 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6704 case QRhiGraphicsPipeline::Lines:
6705 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6706 case QRhiGraphicsPipeline::LineStrip:
6707 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6708 case QRhiGraphicsPipeline::Points:
6709 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6710 case QRhiGraphicsPipeline::Patches:
6711 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6713 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6720 case QRhiGraphicsPipeline::None:
6721 return VK_CULL_MODE_NONE;
6722 case QRhiGraphicsPipeline::Front:
6723 return VK_CULL_MODE_FRONT_BIT;
6724 case QRhiGraphicsPipeline::Back:
6725 return VK_CULL_MODE_BACK_BIT;
6727 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6734 case QRhiGraphicsPipeline::CCW:
6735 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6736 case QRhiGraphicsPipeline::CW:
6737 return VK_FRONT_FACE_CLOCKWISE;
6739 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6746 if (c.testFlag(QRhiGraphicsPipeline::R))
6747 f |= VK_COLOR_COMPONENT_R_BIT;
6748 if (c.testFlag(QRhiGraphicsPipeline::G))
6749 f |= VK_COLOR_COMPONENT_G_BIT;
6750 if (c.testFlag(QRhiGraphicsPipeline::B))
6751 f |= VK_COLOR_COMPONENT_B_BIT;
6752 if (c.testFlag(QRhiGraphicsPipeline::A))
6753 f |= VK_COLOR_COMPONENT_A_BIT;
6754 return VkColorComponentFlags(f);
6760 case QRhiGraphicsPipeline::Zero:
6761 return VK_BLEND_FACTOR_ZERO;
6762 case QRhiGraphicsPipeline::One:
6763 return VK_BLEND_FACTOR_ONE;
6764 case QRhiGraphicsPipeline::SrcColor:
6765 return VK_BLEND_FACTOR_SRC_COLOR;
6766 case QRhiGraphicsPipeline::OneMinusSrcColor:
6767 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6768 case QRhiGraphicsPipeline::DstColor:
6769 return VK_BLEND_FACTOR_DST_COLOR;
6770 case QRhiGraphicsPipeline::OneMinusDstColor:
6771 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6772 case QRhiGraphicsPipeline::SrcAlpha:
6773 return VK_BLEND_FACTOR_SRC_ALPHA;
6774 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6775 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6776 case QRhiGraphicsPipeline::DstAlpha:
6777 return VK_BLEND_FACTOR_DST_ALPHA;
6778 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6779 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
6780 case QRhiGraphicsPipeline::ConstantColor:
6781 return VK_BLEND_FACTOR_CONSTANT_COLOR;
6782 case QRhiGraphicsPipeline::OneMinusConstantColor:
6783 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
6784 case QRhiGraphicsPipeline::ConstantAlpha:
6785 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
6786 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6787 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
6788 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6789 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
6790 case QRhiGraphicsPipeline::Src1Color:
6791 return VK_BLEND_FACTOR_SRC1_COLOR;
6792 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6793 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
6794 case QRhiGraphicsPipeline::Src1Alpha:
6795 return VK_BLEND_FACTOR_SRC1_ALPHA;
6796 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6797 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
6799 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
6806 case QRhiGraphicsPipeline::Add:
6807 return VK_BLEND_OP_ADD;
6808 case QRhiGraphicsPipeline::Subtract:
6809 return VK_BLEND_OP_SUBTRACT;
6810 case QRhiGraphicsPipeline::ReverseSubtract:
6811 return VK_BLEND_OP_REVERSE_SUBTRACT;
6812 case QRhiGraphicsPipeline::Min:
6813 return VK_BLEND_OP_MIN;
6814 case QRhiGraphicsPipeline::Max:
6815 return VK_BLEND_OP_MAX;
6817 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
6824 case QRhiGraphicsPipeline::Never:
6825 return VK_COMPARE_OP_NEVER;
6826 case QRhiGraphicsPipeline::Less:
6827 return VK_COMPARE_OP_LESS;
6828 case QRhiGraphicsPipeline::Equal:
6829 return VK_COMPARE_OP_EQUAL;
6830 case QRhiGraphicsPipeline::LessOrEqual:
6831 return VK_COMPARE_OP_LESS_OR_EQUAL;
6832 case QRhiGraphicsPipeline::Greater:
6833 return VK_COMPARE_OP_GREATER;
6834 case QRhiGraphicsPipeline::NotEqual:
6835 return VK_COMPARE_OP_NOT_EQUAL;
6836 case QRhiGraphicsPipeline::GreaterOrEqual:
6837 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6838 case QRhiGraphicsPipeline::Always:
6839 return VK_COMPARE_OP_ALWAYS;
6841 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
6848 case QRhiGraphicsPipeline::StencilZero:
6849 return VK_STENCIL_OP_ZERO;
6850 case QRhiGraphicsPipeline::Keep:
6851 return VK_STENCIL_OP_KEEP;
6852 case QRhiGraphicsPipeline::Replace:
6853 return VK_STENCIL_OP_REPLACE;
6854 case QRhiGraphicsPipeline::IncrementAndClamp:
6855 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
6856 case QRhiGraphicsPipeline::DecrementAndClamp:
6857 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
6858 case QRhiGraphicsPipeline::Invert:
6859 return VK_STENCIL_OP_INVERT;
6860 case QRhiGraphicsPipeline::IncrementAndWrap:
6861 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
6862 case QRhiGraphicsPipeline::DecrementAndWrap:
6863 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
6865 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
6872 case QRhiGraphicsPipeline::Fill:
6873 return VK_POLYGON_MODE_FILL;
6874 case QRhiGraphicsPipeline::Line:
6875 return VK_POLYGON_MODE_LINE;
6877 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
6883 dst->failOp = toVkStencilOp(src.failOp);
6884 dst->passOp = toVkStencilOp(src.passOp);
6885 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
6886 dst->compareOp = toVkCompareOp(src.compareOp);
6892 case QRhiShaderResourceBinding::UniformBuffer:
6893 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
6894 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
6896 case QRhiShaderResourceBinding::SampledTexture:
6897 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6899 case QRhiShaderResourceBinding::Texture:
6900 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
6902 case QRhiShaderResourceBinding::Sampler:
6903 return VK_DESCRIPTOR_TYPE_SAMPLER;
6905 case QRhiShaderResourceBinding::ImageLoad:
6906 case QRhiShaderResourceBinding::ImageStore:
6907 case QRhiShaderResourceBinding::ImageLoadStore:
6908 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
6910 case QRhiShaderResourceBinding::BufferLoad:
6911 case QRhiShaderResourceBinding::BufferStore:
6912 case QRhiShaderResourceBinding::BufferLoadStore:
6913 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
6916 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
6923 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
6924 s |= VK_SHADER_STAGE_VERTEX_BIT;
6925 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
6926 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
6927 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
6928 s |= VK_SHADER_STAGE_COMPUTE_BIT;
6929 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
6930 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6931 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
6932 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6933 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
6934 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
6935 return VkShaderStageFlags(s);
6941 case QRhiSampler::Never:
6942 return VK_COMPARE_OP_NEVER;
6943 case QRhiSampler::Less:
6944 return VK_COMPARE_OP_LESS;
6945 case QRhiSampler::Equal:
6946 return VK_COMPARE_OP_EQUAL;
6947 case QRhiSampler::LessOrEqual:
6948 return VK_COMPARE_OP_LESS_OR_EQUAL;
6949 case QRhiSampler::Greater:
6950 return VK_COMPARE_OP_GREATER;
6951 case QRhiSampler::NotEqual:
6952 return VK_COMPARE_OP_NOT_EQUAL;
6953 case QRhiSampler::GreaterOrEqual:
6954 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6955 case QRhiSampler::Always:
6956 return VK_COMPARE_OP_ALWAYS;
6958 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
6966 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
6986 e.buffer.buffers[i] = buffers[i];
6988 e.buffer.stagingBuffers[i] = stagingBuffers[i];
6991 buffers[i] = VK_NULL_HANDLE;
6993 stagingBuffers[i] = VK_NULL_HANDLE;
6995 pendingDynamicUpdates[i].clear();
7003 rhiD->releaseQueue.append(e);
7004 rhiD->unregisterResource(
this);
7013 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7014 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7018 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7020 VkBufferCreateInfo bufferInfo = {};
7021 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7022 bufferInfo.size = nonZeroSize;
7023 bufferInfo.usage = toVkBufferUsage(m_usage);
7025 VmaAllocationCreateInfo allocInfo = {};
7027 if (m_type == Dynamic) {
7032 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7035 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7037 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7038 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7042 VkResult err = VK_SUCCESS;
7044 buffers[i] = VK_NULL_HANDLE;
7046 usageState[i].access = usageState[i].stage = 0;
7047 if (i == 0 || m_type == Dynamic) {
7048 VmaAllocation allocation;
7049 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7050 if (err != VK_SUCCESS)
7053 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7054 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7055 m_type == Dynamic ? i : -1);
7059 if (err != VK_SUCCESS) {
7060 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7061 rhiD->printExtraErrorInfo(err);
7067 rhiD->registerResource(
this);
7073 if (m_type == Dynamic) {
7079 b.objects[i] = &buffers[i];
7084 return { { &buffers[0] }, 1 };
7094 Q_ASSERT(m_type == Dynamic);
7096 Q_ASSERT(rhiD->inFrame);
7097 const int slot = rhiD->currentFrameSlot;
7099 VmaAllocation a = toVmaAllocation(allocations[slot]);
7100 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7101 if (err != VK_SUCCESS) {
7102 qWarning(
"Failed to map buffer: %d", err);
7105 return static_cast<
char *>(p);
7111 const int slot = rhiD->currentFrameSlot;
7112 VmaAllocation a = toVmaAllocation(allocations[slot]);
7113 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7114 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7118 int sampleCount, Flags flags,
7119 QRhiTexture::Format backingFormatHint)
7132 if (!memory && !backingTexture)
7139 e.renderBuffer.memory = memory;
7140 e.renderBuffer.image = image;
7141 e.renderBuffer.imageView = imageView;
7143 memory = VK_NULL_HANDLE;
7144 image = VK_NULL_HANDLE;
7145 imageView = VK_NULL_HANDLE;
7155 rhiD->releaseQueue.append(e);
7156 rhiD->unregisterResource(
this);
7162 if (memory || backingTexture)
7165 if (m_pixelSize.isEmpty())
7169 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7172 case QRhiRenderBuffer::Color:
7180 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7188 vkformat = backingTexture->vkformat;
7191 case QRhiRenderBuffer::DepthStencil:
7192 vkformat = rhiD->optimalDepthStencilFormat();
7193 if (!rhiD->createTransientImage(vkformat,
7195 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7196 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7205 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7214 rhiD->registerResource(
this);
7220 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7221 return m_backingFormatHint;
7223 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7227 int arraySize,
int sampleCount, Flags flags)
7231 stagingBuffers[i] = VK_NULL_HANDLE;
7234 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7235 perLevelImageViews[i] = VK_NULL_HANDLE;
7252 e.texture.image = owns ? image : VK_NULL_HANDLE;
7253 e.texture.imageView = imageView;
7257 e.texture.stagingBuffers[i] = stagingBuffers[i];
7260 stagingBuffers[i] = VK_NULL_HANDLE;
7264 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7265 e.texture.extraImageViews[i] = perLevelImageViews[i];
7266 perLevelImageViews[i] = VK_NULL_HANDLE;
7269 image = VK_NULL_HANDLE;
7270 imageView = VK_NULL_HANDLE;
7275 rhiD->releaseQueue.append(e);
7276 rhiD->unregisterResource(
this);
7286 vkformat = toVkTextureFormat(m_format, m_flags);
7287 if (m_writeViewFormat.format != UnknownFormat)
7288 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7290 viewFormat = vkformat;
7291 if (m_readViewFormat.format != UnknownFormat)
7292 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7294 viewFormatForSampling = vkformat;
7296 VkFormatProperties props;
7297 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7298 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7299 if (!canSampleOptimal) {
7300 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7304 const bool isCube = m_flags.testFlag(CubeMap);
7305 const bool isArray = m_flags.testFlag(TextureArray);
7306 const bool is3D = m_flags.testFlag(ThreeDimensional);
7307 const bool is1D = m_flags.testFlag(OneDimensional);
7308 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7310 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7311 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7313 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7314 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7315 if (mipLevelCount > maxLevels) {
7316 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7317 mipLevelCount = maxLevels;
7319 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7320 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7322 qWarning(
"Cubemap texture cannot be multisample");
7326 qWarning(
"3D texture cannot be multisample");
7330 qWarning(
"Multisample texture cannot have mipmaps");
7334 if (isCube && is3D) {
7335 qWarning(
"Texture cannot be both cube and 3D");
7338 if (isArray && is3D) {
7339 qWarning(
"Texture cannot be both array and 3D");
7342 if (isCube && is1D) {
7343 qWarning(
"Texture cannot be both cube and 1D");
7347 qWarning(
"Texture cannot be both 1D and 3D");
7350 if (m_depth > 1 && !is3D) {
7351 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7354 if (m_arraySize > 0 && !isArray) {
7355 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7358 if (m_arraySize < 1 && isArray) {
7359 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7363 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7364 usageState.access = 0;
7365 usageState.stage = 0;
7368 *adjustedSize = size;
7377 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7378 const bool isCube = m_flags.testFlag(CubeMap);
7379 const bool isArray = m_flags.testFlag(TextureArray);
7380 const bool is3D = m_flags.testFlag(ThreeDimensional);
7381 const bool is1D = m_flags.testFlag(OneDimensional);
7383 VkImageViewCreateInfo viewInfo = {};
7384 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7385 viewInfo.image = image;
7386 viewInfo.viewType = isCube
7387 ? VK_IMAGE_VIEW_TYPE_CUBE
7388 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7389 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7390 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7391 viewInfo.format = viewFormatForSampling;
7392 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7393 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7394 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7395 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7396 viewInfo.subresourceRange.aspectMask = aspectMask;
7399 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7400 viewInfo.subresourceRange.levelCount = mipLevelCount;
7401 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7402 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7403 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7405 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7408 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7409 if (err != VK_SUCCESS) {
7410 qWarning(
"Failed to create image view: %d", err);
7423 if (!prepareCreate(&size))
7427 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7428 const bool isDepth = isDepthTextureFormat(m_format);
7429 const bool isCube = m_flags.testFlag(CubeMap);
7430 const bool isArray = m_flags.testFlag(TextureArray);
7431 const bool is3D = m_flags.testFlag(ThreeDimensional);
7432 const bool is1D = m_flags.testFlag(OneDimensional);
7434 VkImageCreateInfo imageInfo = {};
7435 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7436 imageInfo.flags = 0;
7438 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7440 if (is3D && isRenderTarget) {
7446 if (!rhiD->caps.texture3DSliceAs2D)
7447 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7448#ifdef VK_VERSION_1_1
7449 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7451 imageInfo.flags |= 0x00000020;
7455 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7456 imageInfo.format = vkformat;
7457 imageInfo.extent.width = uint32_t(size.width());
7458 imageInfo.extent.height = uint32_t(size.height());
7459 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7460 imageInfo.mipLevels = mipLevelCount;
7461 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7462 imageInfo.samples = samples;
7463 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7464 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7466 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7467 if (isRenderTarget) {
7469 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7471 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7473 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7474 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7475 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7476 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7477 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7478 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7479#ifdef VK_KHR_fragment_shading_rate
7480 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7481 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7484 VmaAllocationCreateInfo allocInfo = {};
7485 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7487 VmaAllocation allocation;
7488 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7489 if (err != VK_SUCCESS) {
7490 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7491 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7492 int(imageInfo.format),
7493 imageInfo.mipLevels,
7494 imageInfo.arrayLayers,
7495 int(imageInfo.samples),
7497 rhiD->printExtraErrorInfo(err);
7501 rhiD->setAllocationName(allocation, m_objectName);
7506 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7509 rhiD->registerResource(
this);
7515 VkImage img = VkImage(src.object);
7519 if (!prepareCreate())
7527 usageState.layout = VkImageLayout(src.layout);
7531 rhiD->registerResource(
this);
7537 return {quint64(image), usageState.layout};
7542 usageState.layout = VkImageLayout(layout);
7547 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7548 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7549 return perLevelImageViews[level];
7551 const VkImageAspectFlags 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 = viewFormat;
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;
7571 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7572 viewInfo.subresourceRange.levelCount = 1;
7573 viewInfo.subresourceRange.baseArrayLayer = 0;
7574 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7576 VkImageView v = VK_NULL_HANDLE;
7578 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7579 if (err != VK_SUCCESS) {
7580 qWarning(
"Failed to create image view: %d", err);
7581 return VK_NULL_HANDLE;
7584 perLevelImageViews[level] = v;
7589 AddressMode u, AddressMode v, AddressMode w)
7608 e.sampler.sampler = sampler;
7609 sampler = VK_NULL_HANDLE;
7613 rhiD->releaseQueue.append(e);
7614 rhiD->unregisterResource(
this);
7623 VkSamplerCreateInfo samplerInfo = {};
7624 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7625 samplerInfo.magFilter = toVkFilter(m_magFilter);
7626 samplerInfo.minFilter = toVkFilter(m_minFilter);
7627 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7628 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7629 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7630 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7631 samplerInfo.maxAnisotropy = 1.0f;
7632 samplerInfo.compareEnable = m_compareOp != Never;
7633 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7634 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7637 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7638 if (err != VK_SUCCESS) {
7639 qWarning(
"Failed to create sampler: %d", err);
7645 rhiD->registerResource(
this);
7652 serializedFormatData.reserve(64);
7666 rp = VK_NULL_HANDLE;
7674 e.renderPass.rp = rp;
7676 rp = VK_NULL_HANDLE;
7680 rhiD->releaseQueue.append(e);
7681 rhiD->unregisterResource(
this);
7687 return a.format == b.format
7688 && a.samples == b.samples
7689 && a.loadOp == b.loadOp
7690 && a.storeOp == b.storeOp
7691 && a.stencilLoadOp == b.stencilLoadOp
7692 && a.stencilStoreOp == b.stencilStoreOp
7693 && a.initialLayout == b.initialLayout
7694 && a.finalLayout == b.finalLayout;
7707 if (attDescs.size() != o->attDescs.size())
7709 if (colorRefs.size() != o->colorRefs.size())
7711 if (resolveRefs.size() != o->resolveRefs.size())
7717 if (multiViewCount != o->multiViewCount)
7722 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7723 const uint32_t attIdx = colorRefs[i].attachment;
7724 if (attIdx != o->colorRefs[i].attachment)
7726 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7731 const uint32_t attIdx = dsRef.attachment;
7732 if (attIdx != o->dsRef.attachment)
7734 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7738 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7739 const uint32_t attIdx = resolveRefs[i].attachment;
7740 if (attIdx != o->resolveRefs[i].attachment)
7742 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7747 const uint32_t attIdx = dsResolveRef.attachment;
7748 if (attIdx != o->dsResolveRef.attachment)
7750 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7755 const uint32_t attIdx = shadingRateRef.attachment;
7756 if (attIdx != o->shadingRateRef.attachment)
7758 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7769 serializedFormatData.clear();
7770 auto p =
std::back_inserter(serializedFormatData);
7772 *p++ = attDescs.size();
7773 *p++ = colorRefs.size();
7774 *p++ = resolveRefs.size();
7778 *p++ = multiViewCount;
7780 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
7781 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
7782 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
7783 *p++ = used ? a->format : 0;
7784 *p++ = used ? a->samples : 0;
7785 *p++ = used ? a->loadOp : 0;
7786 *p++ = used ? a->storeOp : 0;
7787 *p++ = used ? a->stencilLoadOp : 0;
7788 *p++ = used ? a->stencilStoreOp : 0;
7789 *p++ = used ? a->initialLayout : 0;
7790 *p++ = used ? a->finalLayout : 0;
7793 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7794 const uint32_t attIdx = colorRefs[i].attachment;
7796 serializeAttachmentData(attIdx);
7800 const uint32_t attIdx = dsRef.attachment;
7802 serializeAttachmentData(attIdx);
7805 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7806 const uint32_t attIdx = resolveRefs[i].attachment;
7808 serializeAttachmentData(attIdx);
7812 const uint32_t attIdx = dsResolveRef.attachment;
7814 serializeAttachmentData(attIdx);
7818 const uint32_t attIdx = shadingRateRef.attachment;
7820 serializeAttachmentData(attIdx);
7829 rpD->attDescs = attDescs;
7830 rpD->colorRefs = colorRefs;
7831 rpD->resolveRefs = resolveRefs;
7832 rpD->subpassDeps = subpassDeps;
7836 rpD->multiViewCount = multiViewCount;
7838 rpD->dsResolveRef = dsResolveRef;
7839 rpD->shadingRateRef = shadingRateRef;
7841 VkRenderPassCreateInfo rpInfo;
7842 VkSubpassDescription subpassDesc;
7843 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
7847 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
7852#ifdef VK_KHR_create_renderpass2
7853 if (rhiD->caps.renderPass2KHR) {
7855 VkRenderPassCreateInfo2KHR rpInfo2;
7856 RenderPass2SetupHelper rp2Helper(rhiD);
7857 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
7861 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
7862 if (err != VK_SUCCESS) {
7863 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
7870 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
7871 if (err != VK_SUCCESS) {
7872 qWarning(
"Failed to create renderpass: %d", err);
7879 rhiD->registerResource(rpD);
7885 return serializedFormatData;
7890 nativeHandlesStruct.renderPass = rp;
7891 return &nativeHandlesStruct;
7917 texture =
QRHI_RES(QVkTexture, src);
7949 return d.sampleCount;
7953 const QRhiTextureRenderTargetDescription &desc,
7958 rtv[att] = VK_NULL_HANDLE;
7959 resrtv[att] = VK_NULL_HANDLE;
7977 e.textureRenderTarget.fb = d.fb;
7978 d.fb = VK_NULL_HANDLE;
7981 e.textureRenderTarget.rtv[att] = rtv[att];
7982 e.textureRenderTarget.resrtv[att] = resrtv[att];
7983 rtv[att] = VK_NULL_HANDLE;
7984 resrtv[att] = VK_NULL_HANDLE;
7987 e.textureRenderTarget.dsv = dsv;
7988 dsv = VK_NULL_HANDLE;
7989 e.textureRenderTarget.resdsv = resdsv;
7990 resdsv = VK_NULL_HANDLE;
7992 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
7993 shadingRateMapView = VK_NULL_HANDLE;
7997 rhiD->releaseQueue.append(e);
7998 rhiD->unregisterResource(
this);
8008 if (!rhiD->createOffscreenRenderPass(rp,
8009 m_desc.cbeginColorAttachments(),
8010 m_desc.cendColorAttachments(),
8011 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8012 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8013 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8014 m_desc.depthStencilBuffer(),
8015 m_desc.depthTexture(),
8016 m_desc.depthResolveTexture(),
8017 m_desc.shadingRateMap()))
8025 rhiD->registerResource(rp);
8034 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8035 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8036 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8039 QVarLengthArray<VkImageView, 8> views;
8040 d.multiViewCount = 0;
8042 d.colorAttCount = 0;
8044 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8045 d.colorAttCount += 1;
8048 Q_ASSERT(texD || rbD);
8050 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8051 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8052 const bool isMultiView = it->multiViewCount() >= 2;
8053 if (isMultiView && d.multiViewCount == 0)
8054 d.multiViewCount = it->multiViewCount();
8055 VkImageViewCreateInfo viewInfo = {};
8056 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8057 viewInfo.image = texD->image;
8058 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8059 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8060 : VK_IMAGE_VIEW_TYPE_2D);
8061 viewInfo.format = texD->viewFormat;
8062 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8063 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8064 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8065 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8066 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8067 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8068 viewInfo.subresourceRange.levelCount = 1;
8069 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8070 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8071 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8072 if (err != VK_SUCCESS) {
8073 qWarning(
"Failed to create render target image view: %d", err);
8076 views.append(rtv[attIndex]);
8077 if (attIndex == 0) {
8078 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8079 d.sampleCount = texD->samples;
8084 if (attIndex == 0) {
8085 d.pixelSize = rbD->pixelSize();
8086 d.sampleCount = rbD->samples;
8092 if (hasDepthStencil) {
8093 if (m_desc.depthTexture()) {
8096 VkImageViewCreateInfo viewInfo = {};
8097 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8098 viewInfo.image = depthTexD->image;
8099 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8100 viewInfo.format = depthTexD->viewFormat;
8101 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8102 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8103 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8104 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8105 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8106 viewInfo.subresourceRange.levelCount = 1;
8107 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8108 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8109 if (err != VK_SUCCESS) {
8110 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8114 if (d.colorAttCount == 0) {
8115 d.pixelSize = depthTexD->pixelSize();
8116 d.sampleCount = depthTexD->samples;
8120 views.append(depthRbD->imageView);
8121 if (d.colorAttCount == 0) {
8122 d.pixelSize = depthRbD->pixelSize();
8123 d.sampleCount = depthRbD->samples;
8131 d.resolveAttCount = 0;
8133 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8134 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8135 if (it->resolveTexture()) {
8137 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8138 d.resolveAttCount += 1;
8140 VkImageViewCreateInfo viewInfo = {};
8141 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8142 viewInfo.image = resTexD->image;
8143 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8144 : VK_IMAGE_VIEW_TYPE_2D;
8145 viewInfo.format = resTexD->viewFormat;
8146 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8147 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8148 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8149 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8150 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8151 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8152 viewInfo.subresourceRange.levelCount = 1;
8153 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8154 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8155 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8156 if (err != VK_SUCCESS) {
8157 qWarning(
"Failed to create render target resolve image view: %d", err);
8160 views.append(resrtv[attIndex]);
8164 if (m_desc.depthResolveTexture()) {
8166 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8168 VkImageViewCreateInfo viewInfo = {};
8169 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8170 viewInfo.image = resTexD->image;
8171 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8172 : VK_IMAGE_VIEW_TYPE_2D;
8173 viewInfo.format = resTexD->viewFormat;
8174 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8175 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8176 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8177 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8178 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8179 viewInfo.subresourceRange.baseMipLevel = 0;
8180 viewInfo.subresourceRange.levelCount = 1;
8181 viewInfo.subresourceRange.baseArrayLayer = 0;
8182 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8183 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8184 if (err != VK_SUCCESS) {
8185 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8188 views.append(resdsv);
8189 d.dsResolveAttCount = 1;
8191 d.dsResolveAttCount = 0;
8194 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8196 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8198 VkImageViewCreateInfo viewInfo = {};
8199 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8200 viewInfo.image = texD->image;
8201 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8202 : VK_IMAGE_VIEW_TYPE_2D;
8203 viewInfo.format = texD->viewFormat;
8204 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8205 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8206 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8207 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8208 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8209 viewInfo.subresourceRange.baseMipLevel = 0;
8210 viewInfo.subresourceRange.levelCount = 1;
8211 viewInfo.subresourceRange.baseArrayLayer = 0;
8212 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8213 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8214 if (err != VK_SUCCESS) {
8215 qWarning(
"Failed to create render target shading rate map view: %d", err);
8218 views.append(shadingRateMapView);
8219 d.shadingRateAttCount = 1;
8221 d.shadingRateAttCount = 0;
8224 if (!m_renderPassDesc)
8225 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8227 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8228 Q_ASSERT(d.rp && d.rp->rp);
8230 VkFramebufferCreateInfo fbInfo = {};
8231 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8232 fbInfo.renderPass = d.rp->rp;
8233 fbInfo.attachmentCount = uint32_t(views.count());
8234 fbInfo.pAttachments = views.constData();
8235 fbInfo.width = uint32_t(d.pixelSize.width());
8236 fbInfo.height = uint32_t(d.pixelSize.height());
8239 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8240 if (err != VK_SUCCESS) {
8241 qWarning(
"Failed to create framebuffer: %d", err);
8245 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8248 rhiD->registerResource(
this);
8254 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8267 return d.sampleCount;
8285 sortedBindings.clear();
8291 e.shaderResourceBindings.poolIndex =
poolIndex;
8292 e.shaderResourceBindings.layout = layout;
8295 layout = VK_NULL_HANDLE;
8296 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8297 descSets[i] = VK_NULL_HANDLE;
8301 rhiD->releaseQueue.append(e);
8302 rhiD->unregisterResource(
this);
8312 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8315 rhiD->updateLayoutDesc(
this);
8317 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8318 descSets[i] = VK_NULL_HANDLE;
8320 sortedBindings.clear();
8321 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8322 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8325 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8326 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8327 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8328 if (b->u.ubuf.hasDynamicOffset)
8329 hasDynamicOffset =
true;
8333 QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
8334 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8335 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8336 VkDescriptorSetLayoutBinding vkbinding = {};
8337 vkbinding.binding = uint32_t(b->binding);
8338 vkbinding.descriptorType = toVkDescriptorType(b);
8339 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8340 vkbinding.descriptorCount = b->u.stex.count;
8342 vkbinding.descriptorCount = 1;
8343 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8344 vkbindings.append(vkbinding);
8347 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8348 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8349 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8350 layoutInfo.pBindings = vkbindings.constData();
8352 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8353 if (err != VK_SUCCESS) {
8354 qWarning(
"Failed to create descriptor set layout: %d", err);
8358 VkDescriptorSetAllocateInfo allocInfo = {};
8359 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8362 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8363 layouts[i] = layout;
8364 allocInfo.pSetLayouts = layouts;
8365 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8369 boundResourceData[i].resize(sortedBindings.size());
8370 for (BoundResourceData &bd : boundResourceData[i])
8371 memset(&bd, 0,
sizeof(BoundResourceData));
8376 rhiD->registerResource(
this);
8382 sortedBindings.clear();
8383 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8384 if (!flags.testFlag(BindingsAreSorted))
8385 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8397 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8398 for (BoundResourceData &bd : boundResourceData[i])
8399 memset(&bd, 0,
sizeof(BoundResourceData));
8417 if (!pipeline && !layout)
8424 e.pipelineState.pipeline = pipeline;
8425 e.pipelineState.layout = layout;
8427 pipeline = VK_NULL_HANDLE;
8428 layout = VK_NULL_HANDLE;
8432 rhiD->releaseQueue.append(e);
8433 rhiD->unregisterResource(
this);
8443 rhiD->pipelineCreationStart();
8444 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8447 if (!rhiD->ensurePipelineCache())
8450 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8451 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8452 pipelineLayoutInfo.setLayoutCount = 1;
8454 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8455 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8456 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8457 if (err != VK_SUCCESS) {
8458 qWarning(
"Failed to create pipeline layout: %d", err);
8462 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8463 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8465 QVarLengthArray<VkShaderModule, 4> shaders;
8466 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8467 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8468 const QShader bakedShader = shaderStage.shader();
8469 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8470 if (spirv.shader().isEmpty()) {
8471 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8474 VkShaderModule shader = rhiD->createShader(spirv.shader());
8476 shaders.append(shader);
8477 VkPipelineShaderStageCreateInfo shaderInfo = {};
8478 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8479 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8480 shaderInfo.module = shader;
8481 shaderInfo.pName = spirv.entryPoint().constData();
8482 shaderStageCreateInfos.append(shaderInfo);
8485 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8486 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8488 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8489#ifdef VK_EXT_vertex_attribute_divisor
8490 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8492 int bindingIndex = 0;
8493 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8494 it != itEnd; ++it, ++bindingIndex)
8496 VkVertexInputBindingDescription bindingInfo = {
8497 uint32_t(bindingIndex),
8499 it->classification() == QRhiVertexInputBinding::PerVertex
8500 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8502 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8503#ifdef VK_EXT_vertex_attribute_divisor
8504 if (rhiD->caps.vertexAttribDivisor) {
8505 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8509 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8510 "VK_EXT_vertex_attribute_divisor on the device and "
8511 "VK_KHR_get_physical_device_properties2 on the instance");
8514 vertexBindings.append(bindingInfo);
8516 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8517 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8520 VkVertexInputAttributeDescription attributeInfo = {
8521 uint32_t(it->location()),
8522 uint32_t(it->binding()),
8523 toVkAttributeFormat(it->format()),
8526 vertexAttributes.append(attributeInfo);
8528 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8529 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8530 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8531 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8532 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8533 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8534#ifdef VK_EXT_vertex_attribute_divisor
8535 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8536 if (!nonOneStepRates.isEmpty()) {
8537 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8538 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8539 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8540 vertexInputInfo.pNext = &divisorInfo;
8543 pipelineInfo.pVertexInputState = &vertexInputInfo;
8545 QVarLengthArray<VkDynamicState, 8> dynEnable;
8546 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8547 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8548 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8549 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8550 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8551 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8552#ifdef VK_KHR_fragment_shading_rate
8553 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8554 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8557 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8558 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8559 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8560 dynamicInfo.pDynamicStates = dynEnable.constData();
8561 pipelineInfo.pDynamicState = &dynamicInfo;
8563 VkPipelineViewportStateCreateInfo viewportInfo = {};
8564 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8565 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8566 pipelineInfo.pViewportState = &viewportInfo;
8568 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8569 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8570 inputAsmInfo.topology = toVkTopology(m_topology);
8571 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8572 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8574 VkPipelineTessellationStateCreateInfo tessInfo = {};
8575#ifdef VK_VERSION_1_1
8576 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8578 if (m_topology == Patches) {
8579 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8580 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8587#ifdef VK_VERSION_1_1
8588 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8589 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8590 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8591 tessInfo.pNext = &originInfo;
8593 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8596 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8599 pipelineInfo.pTessellationState = &tessInfo;
8602 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8603 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8604 if (m_depthClamp && rhiD->caps.depthClamp)
8605 rastInfo.depthClampEnable = m_depthClamp;
8606 rastInfo.cullMode = toVkCullMode(m_cullMode);
8607 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8608 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8609 rastInfo.depthBiasEnable =
true;
8610 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8611 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8613 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8614 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8615 pipelineInfo.pRasterizationState = &rastInfo;
8617 VkPipelineMultisampleStateCreateInfo msInfo = {};
8618 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8619 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8620 pipelineInfo.pMultisampleState = &msInfo;
8622 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8623 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8624 dsInfo.depthTestEnable = m_depthTest;
8625 dsInfo.depthWriteEnable = m_depthWrite;
8626 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8627 dsInfo.stencilTestEnable = m_stencilTest;
8628 if (m_stencilTest) {
8629 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8630 dsInfo.front.compareMask = m_stencilReadMask;
8631 dsInfo.front.writeMask = m_stencilWriteMask;
8632 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8633 dsInfo.back.compareMask = m_stencilReadMask;
8634 dsInfo.back.writeMask = m_stencilWriteMask;
8636 pipelineInfo.pDepthStencilState = &dsInfo;
8638 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8639 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8640 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8641 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8642 VkPipelineColorBlendAttachmentState blend = {};
8643 blend.blendEnable = b.enable;
8644 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8645 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8646 blend.colorBlendOp = toVkBlendOp(b.opColor);
8647 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8648 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8649 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8650 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8651 vktargetBlends.append(blend);
8653 if (vktargetBlends.isEmpty()) {
8654 VkPipelineColorBlendAttachmentState blend = {};
8655 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8656 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8657 vktargetBlends.append(blend);
8659 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8660 blendInfo.pAttachments = vktargetBlends.constData();
8661 pipelineInfo.pColorBlendState = &blendInfo;
8663 pipelineInfo.layout = layout;
8665 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8666 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8668 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8670 for (VkShaderModule shader : shaders)
8671 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8673 if (err != VK_SUCCESS) {
8674 qWarning(
"Failed to create graphics pipeline: %d", err);
8678 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8680 rhiD->pipelineCreationEnd();
8683 rhiD->registerResource(
this);
8699 if (!pipeline && !layout)
8706 e.pipelineState.pipeline = pipeline;
8707 e.pipelineState.layout = layout;
8709 pipeline = VK_NULL_HANDLE;
8710 layout = VK_NULL_HANDLE;
8714 rhiD->releaseQueue.append(e);
8715 rhiD->unregisterResource(
this);
8725 rhiD->pipelineCreationStart();
8726 if (!rhiD->ensurePipelineCache())
8729 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8730 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8731 pipelineLayoutInfo.setLayoutCount = 1;
8733 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8734 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8735 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8736 if (err != VK_SUCCESS) {
8737 qWarning(
"Failed to create pipeline layout: %d", err);
8741 VkComputePipelineCreateInfo pipelineInfo = {};
8742 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8743 pipelineInfo.layout = layout;
8745 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
8746 qWarning(
"Compute pipeline requires a compute shader stage");
8749 const QShader bakedShader = m_shaderStage.shader();
8750 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
8751 if (spirv.shader().isEmpty()) {
8752 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8755 if (bakedShader.stage() != QShader::ComputeStage) {
8756 qWarning() << bakedShader <<
"is not a compute shader";
8759 VkShaderModule shader = rhiD->createShader(spirv.shader());
8760 VkPipelineShaderStageCreateInfo shaderInfo = {};
8761 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8762 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8763 shaderInfo.module = shader;
8764 shaderInfo.pName = spirv.entryPoint().constData();
8765 pipelineInfo.stage = shaderInfo;
8767 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8768 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8769 if (err != VK_SUCCESS) {
8770 qWarning(
"Failed to create graphics pipeline: %d", err);
8774 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8776 rhiD->pipelineCreationEnd();
8779 rhiD->registerResource(
this);
8808 nativeHandlesStruct.commandBuffer = cb;
8810 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
8811 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
8813 nativeHandlesStruct.commandBuffer = cb;
8816 return &nativeHandlesStruct;
8834 if (sc == VK_NULL_HANDLE)
8839 rhiD->swapchains.remove(
this);
8845 frame.cmdBuf = VK_NULL_HANDLE;
8849 surface = lastConnectedSurface = VK_NULL_HANDLE;
8852 rhiD->unregisterResource(
this);
8867 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
8877 VkSurfaceCapabilitiesKHR surfaceCaps = {};
8879 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
8880 VkExtent2D bufferSize = surfaceCaps.currentExtent;
8881 if (bufferSize.width == uint32_t(-1)) {
8882 Q_ASSERT(bufferSize.height == uint32_t(-1));
8883 return m_window->size() * m_window->devicePixelRatio();
8885 return QSize(
int(bufferSize.width),
int(bufferSize.height));
8891 case QRhiSwapChain::HDRExtendedSrgbLinear:
8892 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8893 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
8894 case QRhiSwapChain::HDR10:
8895 return (s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || s.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32)
8896 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
8897 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
8898 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8899 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
8912 qWarning(
"Attempted to call isFormatSupported() without a window set");
8917 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8920 uint32_t formatCount = 0;
8921 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
8922 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
8924 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
8925 for (uint32_t i = 0; i < formatCount; ++i) {
8926 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
8938 QRHI_RES_RHI(QRhiVulkan);
8940 if (m_window && rhiD->adapterLuidValid)
8941 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
8955 if (!rhiD->createDefaultRenderPass(rp,
8956 m_depthStencil !=
nullptr,
8967 rhiD->registerResource(rp);
8974 case VK_FORMAT_R8_SRGB:
8975 case VK_FORMAT_R8G8_SRGB:
8976 case VK_FORMAT_R8G8B8_SRGB:
8977 case VK_FORMAT_B8G8R8_SRGB:
8978 case VK_FORMAT_R8G8B8A8_SRGB:
8979 case VK_FORMAT_B8G8R8A8_SRGB:
8980 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
8995 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8997 qWarning(
"Failed to get surface for window");
9000 if (surface == surf)
9006 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9007 qWarning(
"Presenting not supported on this window");
9011 quint32 formatCount = 0;
9012 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9013 QList<VkSurfaceFormatKHR> formats(formatCount);
9015 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, formats.data());
9019 const bool srgbRequested = m_flags.testFlag(sRGB);
9020 for (
int i = 0; i <
int(formatCount); ++i) {
9021 if (formats[i].format != VK_FORMAT_UNDEFINED) {
9022 bool ok = srgbRequested == isSrgbFormat(formats[i].format);
9023 if (m_format != SDR)
9024 ok &= hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9026 colorFormat = formats[i].format;
9027 colorSpace = formats[i].colorSpace;
9028#if QT_CONFIG(wayland)
9033 const bool hasPassThrough = std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9034 return fmt.format == colorFormat && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9036 if (hasPassThrough) {
9037 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9045 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9047 quint32 presModeCount = 0;
9048 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9049 supportedPresentationModes.resize(presModeCount);
9050 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9051 supportedPresentationModes.data());
9059 const bool needsRegistration = !window || window != m_window;
9066 if (window && window != m_window)
9070 m_currentPixelSize = surfacePixelSize();
9071 pixelSize = m_currentPixelSize;
9074 qWarning(
"Failed to create new swapchain");
9078 if (needsRegistration || !rhiD->swapchains.contains(
this))
9079 rhiD->swapchains.insert(
this);
9081 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9082 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9083 m_depthStencil->sampleCount(), m_sampleCount);
9085 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9086 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9087 m_depthStencil->setPixelSize(pixelSize);
9088 if (!m_depthStencil->create())
9089 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9090 pixelSize.width(), pixelSize.height());
9092 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9093 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9094 pixelSize.width(), pixelSize.height());
9098 if (!m_renderPassDesc)
9099 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9101 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9102 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9103 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9105 rtWrapper.d.pixelSize = pixelSize;
9106 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9107 rtWrapper.d.sampleCount = samples;
9108 rtWrapper.d.colorAttCount = 1;
9109 if (m_depthStencil) {
9110 rtWrapper.d.dsAttCount = 1;
9111 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9113 rtWrapper.d.dsAttCount = 0;
9116 rtWrapper.d.dsResolveAttCount = 0;
9117 if (samples > VK_SAMPLE_COUNT_1_BIT)
9118 rtWrapper.d.resolveAttCount = 1;
9120 rtWrapper.d.resolveAttCount = 0;
9122 if (shadingRateMapView)
9123 rtWrapper.d.shadingRateAttCount = 1;
9125 rtWrapper.d.shadingRateAttCount = 0;
9130 QVarLengthArray<VkImageView, 4> views;
9131 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9133 views.append(
ds->imageView);
9134 if (samples > VK_SAMPLE_COUNT_1_BIT)
9135 views.append(image.imageView);
9136 if (shadingRateMapView)
9137 views.append(shadingRateMapView);
9139 VkFramebufferCreateInfo fbInfo = {};
9140 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9141 fbInfo.renderPass = rtWrapper.d.rp->rp;
9142 fbInfo.attachmentCount = uint32_t(views.count());
9143 fbInfo.pAttachments = views.constData();
9144 fbInfo.width = uint32_t(pixelSize.width());
9145 fbInfo.height = uint32_t(pixelSize.height());
9148 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9149 if (err != VK_SUCCESS) {
9150 qWarning(
"Failed to create framebuffer: %d", err);
9156 rtWrapperRight.setRenderPassDescriptor(
9158 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9159 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9161 rtWrapperRight.d.pixelSize = pixelSize;
9162 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9163 rtWrapperRight.d.sampleCount = samples;
9164 rtWrapperRight.d.colorAttCount = 1;
9165 if (m_depthStencil) {
9166 rtWrapperRight.d.dsAttCount = 1;
9167 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9169 rtWrapperRight.d.dsAttCount = 0;
9172 rtWrapperRight.d.dsResolveAttCount = 0;
9173 if (samples > VK_SAMPLE_COUNT_1_BIT)
9174 rtWrapperRight.d.resolveAttCount = 1;
9176 rtWrapperRight.d.resolveAttCount = 0;
9181 QVarLengthArray<VkImageView, 4> views;
9182 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9184 views.append(
ds->imageView);
9185 if (samples > VK_SAMPLE_COUNT_1_BIT)
9186 views.append(image.imageView);
9187 if (shadingRateMapView)
9188 views.append(shadingRateMapView);
9190 VkFramebufferCreateInfo fbInfo = {};
9191 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9192 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9193 fbInfo.attachmentCount = uint32_t(views.count());
9194 fbInfo.pAttachments = views.constData();
9195 fbInfo.width = uint32_t(pixelSize.width());
9196 fbInfo.height = uint32_t(pixelSize.height());
9199 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9200 if (err != VK_SUCCESS) {
9201 qWarning(
"Failed to create framebuffer: %d", err);
9209 if (needsRegistration)
9210 rhiD->registerResource(
this);
const char * constData() const
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker)
VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD=nullptr)
QRhiSwapChain * createSwapChain() override
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
int resourceLimit(QRhi::ResourceLimit limit) const override
bool isDeviceLost() const override
void prepareUploadSubres(QVkTexture *texD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, size_t *curOfs, void *mp, BufferImageCopyList *copyInfos)
void executeDeferredReleases(bool forced=false)
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex)
QRhi::FrameOpResult finish() override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples, VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count)
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void releaseCachedResources() override
QVkSwapChain * currentSwapChain
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams=nullptr)
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
QList< int > supportedSampleCounts() const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb)
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, QRhiShadingRateMap *shadingRateMap)
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot, VkAccessFlags access, VkPipelineStageFlags stage)
QRhi::FrameOpResult waitCommandCompletion(int frameSlot)
void endExternal(QRhiCommandBuffer *cb) override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex)
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
VkResult createDescriptorPool(VkDescriptorPool *pool)
void prepareNewFrame(QRhiCommandBuffer *cb)
void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, int startLayer, int layerCount, int startLevel, int levelCount)
QList< QSize > supportedShadingRates(int sampleCount) const override
void printExtraErrorInfo(VkResult err)
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb)
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, QVkTexture *texD, QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage)
bool releaseCachedResourcesCalledBeforeFrameStart
QRhiGraphicsPipeline * createGraphicsPipeline() override
QRhiComputePipeline * createComputePipeline() override
void setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot=-1)
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
const QRhiNativeHandles * nativeHandles(QRhiCommandBuffer *cb) override
bool recreateSwapChain(QRhiSwapChain *swapChain)
void printDeviceLossErrorInfo() const
bool ensurePipelineCache(const void *initialData=nullptr, size_t initialDataSize=0)
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD)
void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD, VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
VkShaderModule createShader(const QByteArray &spirv)
void enqueueTransitionPassResources(QVkCommandBuffer *cbD)
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
bool create(QRhi::Flags flags) override
QVulkanDeviceFunctions * df
void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot=-1)
bool isFeatureSupported(QRhi::Feature feature) const override
void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
bool isYUpInFramebuffer() const override
void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override
void debugMarkEnd(QRhiCommandBuffer *cb) override
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
void releaseSwapChainResources(QRhiSwapChain *swapChain)
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, QVkBuffer *bufD, int slot, QRhiPassResourceTracker::BufferAccess access, QRhiPassResourceTracker::BufferStage stage)
VkFormat optimalDepthStencilFormat()
QRhiStats statistics() override
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD)
void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
bool isYUpInNDC() const override
const QRhiNativeHandles * nativeHandles() override
QRhiShadingRateMap * createShadingRateMap() override
void setPipelineCacheData(const QByteArray &data) override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
QRhiShaderResourceBindings * createShaderResourceBindings() override
void finishActiveReadbacks(bool forced=false)
void ensureCommandPoolForNewFrame()
QByteArray pipelineCacheData() override
void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD)
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
bool isClipDepthZeroToOne() const override
void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
QMatrix4x4 clipSpaceCorrMatrix() const override
int ubufAlignment() const override
QRhiDriverInfo driverInfo() const override
void beginExternal(QRhiCommandBuffer *cb) override
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat, QRhiShadingRateMap *shadingRateMap)
QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence, VkSemaphore *waitSem, VkSemaphore *signalSem)
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount)
bool makeThreadLocalNativeContextCurrent() override
QRhiDriverInfo info() const override
Combined button and popup list for selecting options.
static VkPolygonMode toVkPolygonMode(QRhiGraphicsPipeline::PolygonMode mode)
static VkCullModeFlags toVkCullMode(QRhiGraphicsPipeline::CullMode c)
static bool accessIsWrite(VkAccessFlags access)
static VkCompareOp toVkTextureCompareOp(QRhiSampler::CompareOp op)
static QVulkanInstance * globalVulkanInstance
static VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
static QRhiTexture::Format swapchainReadbackTextureFormat(VkFormat format, QRhiTexture::Flags *flags)
static VkStencilOp toVkStencilOp(QRhiGraphicsPipeline::StencilOp op)
static bool qvk_debug_filter(QVulkanInstance::DebugMessageSeverityFlags severity, QVulkanInstance::DebugMessageTypeFlags type, const void *callbackData)
static QVkBuffer::UsageState toVkBufferUsageState(QRhiPassResourceTracker::UsageState usage)
static bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b)
static bool isSrgbFormat(VkFormat format)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::TextureStage stage)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::BufferAccess access)
static VkImageLayout toVkLayout(QRhiPassResourceTracker::TextureAccess access)
static VkFormat toVkAttributeFormat(QRhiVertexInputAttribute::Format format)
static QVkTexture::UsageState toVkTextureUsageState(QRhiPassResourceTracker::UsageState usage)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::BufferStage stage)
static QRhiDriverInfo::DeviceType toRhiDeviceType(VkPhysicalDeviceType type)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkBuffer::UsageState &bufUsage)
static VkColorComponentFlags toVkColorComponents(QRhiGraphicsPipeline::ColorMask c)
static VkFilter toVkFilter(QRhiSampler::Filter f)
static VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t)
static void qrhivk_releaseTexture(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df, void *allocator)
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::TextureAccess access)
static VmaAllocator toVmaAllocator(QVkAllocator a)
static VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
static constexpr bool isDepthTextureFormat(QRhiTexture::Format format)
static void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphicsPipeline::StencilOpState &src)
VkSampleCountFlagBits mask
static VkShaderStageFlags toVkShaderStageFlags(QRhiShaderResourceBinding::StageFlags stage)
static constexpr VkImageAspectFlags aspectMaskForTextureFormat(QRhiTexture::Format format)
static VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
static VkBlendFactor toVkBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
static void fillDriverInfo(QRhiDriverInfo *info, const VkPhysicalDeviceProperties &physDevProperties)
static VkBlendOp toVkBlendOp(QRhiGraphicsPipeline::BlendOp op)
static void qrhivk_releaseRenderBuffer(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static VkFrontFace toVkFrontFace(QRhiGraphicsPipeline::FrontFace f)
void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource, QRhiShaderResourceBinding::Type bindingType, int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
static VkFormat toVkTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
static VkCompareOp toVkCompareOp(QRhiGraphicsPipeline::CompareOp op)
static void fillRenderPassCreateInfo(VkRenderPassCreateInfo *rpInfo, VkSubpassDescription *subpassDesc, QVkRenderPassDescriptor *rpD)
static VkSamplerMipmapMode toVkMipmapMode(QRhiSampler::Filter f)
static bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, const VkSurfaceFormatKHR &s)
static void qrhivk_releaseSampler(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static constexpr bool isStencilTextureFormat(QRhiTexture::Format format)
static QVkRenderTargetData * maybeRenderTargetData(QVkCommandBuffer *cbD)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkTexture::UsageState &texUsage)
static VmaAllocation toVmaAllocation(QVkAlloc a)
static void addToChain(T *head, void *entry)
static VkShaderStageFlagBits toVkShaderStage(QRhiShaderStage::Type type)
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS
static const int QVK_DESC_SETS_PER_POOL
static const int QVK_FRAMES_IN_FLIGHT
bool prepare(VkRenderPassCreateInfo *rpInfo, int multiViewCount, bool multiViewCap)
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
QRhiBuffer::NativeBuffer nativeBuffer() override
bool create() override
Creates the corresponding native graphics resources.
char * beginFullDynamicBufferUpdateForCurrentFrame() override
@ TransitionPassResources
QVkCommandBuffer(QRhiImplementation *rhi)
const QRhiNativeHandles * nativeHandles()
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
int currentPassResTrackerIndex
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkComputePipeline(QRhiImplementation *rhi)
QVkGraphicsPipeline(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags, QRhiTexture::Format backingFormatHint)
QRhiTexture::Format backingFormat() const override
bool create() override
Creates the corresponding native graphics resources.
QVkTexture * backingTexture
const QRhiNativeHandles * nativeHandles() override
void updateSerializedFormat()
bool hasDepthStencilResolve
~QVkRenderPassDescriptor()
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVector< quint32 > serializedFormat() const override
QVkRenderPassDescriptor(QRhiImplementation *rhi)
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QVkRenderPassDescriptor * rp
static const int MAX_COLOR_ATTACHMENTS
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
void updateResources(UpdateFlags flags) override
QVkShaderResourceBindings(QRhiImplementation *rhi)
bool create() override
Creates the corresponding resource binding set.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
~QVkShaderResourceBindings()
bool createFrom(QRhiTexture *src) override
Sets up the shading rate map to use the texture src as the image containing the per-tile shading rate...
QVkShadingRateMap(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QSize pixelSize() const override
int sampleCount() const override
float devicePixelRatio() const override
~QVkSwapChainRenderTarget()
QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
@ ScImageUseTransferSource
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QRhiRenderTarget * currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override
bool isFormatSupported(Format f) override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
QVkSwapChain(QRhiImplementation *rhi)
QSize surfacePixelSize() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderTarget * currentFrameRenderTarget() override
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::limitsType
QRhiCommandBuffer * currentFrameCommandBuffer() override
QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
~QVkTextureRenderTarget()
float devicePixelRatio() const override
bool create() override
Creates the corresponding native graphics resources.
int sampleCount() const override
QSize pixelSize() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
VkImageView perLevelImageViewForLoadStore(int level)
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
void setNativeLayout(int layout) override
With some graphics APIs, such as Vulkan, integrating custom rendering code that uses the graphics API...
QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
NativeTexture nativeTexture() override
bool prepareCreate(QSize *adjustedSize=nullptr)