6#include <qpa/qplatformvulkaninstance.h>
8#define VMA_IMPLEMENTATION
9#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
10#define VMA_STATIC_VULKAN_FUNCTIONS 0
11#define VMA_RECORDING_ENABLED 0
12#define VMA_DEDICATED_ALLOCATION 0
14Q_STATIC_LOGGING_CATEGORY(QRHI_LOG_VMA,
"qt.rhi.vma")
16#define VMA_ASSERT(expr) Q_ASSERT(expr)
18#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1
19#define VMA_DEBUG_LOG(str) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), (str))
20#define VMA_DEBUG_LOG_FORMAT(format, ...) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, __VA_ARGS__)
22template<
typename... Args>
23static void debugVmaLeak(
const char *format, Args&&... args)
27 static bool leakCheck =
true;
30 static bool leakCheck = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)(
"QT_RHI_LEAK_CHECK");
33 QT_PREPEND_NAMESPACE(qWarning)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, std::forward<Args>(args)...);
35#define VMA_LEAK_LOG_FORMAT(format, ...) debugVmaLeak(format, __VA_ARGS__)
37QT_WARNING_DISABLE_GCC(
"-Wsuggest-override")
38QT_WARNING_DISABLE_GCC(
"-Wundef")
39QT_WARNING_DISABLE_CLANG(
"-Wundef")
40#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1100
41QT_WARNING_DISABLE_CLANG(
"-Wdeprecated-copy")
43#include "vk_mem_alloc.h"
47#include <QVulkanFunctions>
48#include <QtGui/qwindow.h>
49#include <private/qvulkandefaultinstance_p.h>
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
196
197
198
199
200
203
204
205
206
209
210
211
212
213
217
218
219
220
221
222
223
224
225
226
229
230
231
232
235
236
237
238
239
242
243
244
245
248
249
250
251
254
255
256
257
258
261
262
263
264
265
268
269
270
271
272
276
277
278
279
280
281
282
283
284
285
286
287
288
289
292
293
294
295
299
300
301
302
303
304
305
306
309
310
311
312
316
317
318
319
320
321
322
325
326
327
328
329
330
333
334
335
336
337
338
341
342
343
344
345
346
349
350
351
352
353
354
357
358
359
360
361
362
365
366
367
368
369
370
373inline Int aligned(Int v, Int byteAlign)
375 return (v + byteAlign - 1) & ~(byteAlign - 1);
380static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
382 return globalVulkanInstance->getInstanceProcAddr(pName);
385static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
387 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
392 return reinterpret_cast<VmaAllocation>(a);
397 return reinterpret_cast<VmaAllocator>(a);
401
402
403
404
405
406
407QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
410 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"),
412 QByteArrayLiteral(
"VK_EXT_swapchain_colorspace")
417
418
419
420
421QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
424 QByteArrayLiteral(
"VK_KHR_swapchain"),
425 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
426 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
427 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
428 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
441 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
442 inst = QVulkanDefaultInstance::instance();
446 requestedDeviceExtensions = params->deviceExtensions;
449 physDev = importParams->physDev;
450 dev = importParams->dev;
451 if (dev && physDev) {
453 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
454 gfxQueueIdx = importParams->gfxQueueIdx;
456 if (importParams->vmemAllocator) {
465 QVulkanInstance::DebugMessageTypeFlags type,
466 const void *callbackData)
470#ifdef VK_EXT_debug_utils
471 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
475 if (strstr(d->pMessage,
"Mapping an image with layout")
476 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
487 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
490 Q_UNUSED(callbackData);
498 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
499 return QRhiDriverInfo::UnknownDevice;
500 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
501 return QRhiDriverInfo::IntegratedDevice;
502 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
503 return QRhiDriverInfo::DiscreteDevice;
504 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
505 return QRhiDriverInfo::VirtualDevice;
506 case VK_PHYSICAL_DEVICE_TYPE_CPU:
507 return QRhiDriverInfo::CpuDevice;
509 return QRhiDriverInfo::UnknownDevice;
513static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
515 info->deviceName = QByteArray(physDevProperties.deviceName);
516 info->deviceId = physDevProperties.deviceID;
517 info->vendorId = physDevProperties.vendorID;
518 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
524 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
526 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
532 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
538 if (!inst->isValid()) {
539 qWarning(
"Vulkan instance is not valid");
544 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
546 globalVulkanInstance = inst;
547 f = inst->functions();
548 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
549 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
550 const QByteArrayList extensions = inst->extensions();
551 for (
const char *ext : extensions)
552 qCDebug(QRHI_LOG_INFO,
" %s", ext);
556 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
558 QList<VkQueueFamilyProperties> queueFamilyProps;
559 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
560 uint32_t queueCount = 0;
561 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
562 queueFamilyProps.resize(
int(queueCount));
563 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
568 uint32_t physDevCount = 0;
569 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
571 qWarning(
"No physical devices");
574 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
575 VkResult err =
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
576 if (err != VK_SUCCESS || !physDevCount) {
577 qWarning(
"Failed to enumerate physical devices: %d", err);
581 int physDevIndex = -1;
582 int requestedPhysDevIndex = -1;
583 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
584 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
586 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
587 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
588 for (
int i = 0; i <
int(physDevCount); ++i) {
589 if (physDevs[i] == requestedPhysDev) {
590 requestedPhysDevIndex = i;
596 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
597 for (
int i = 0; i <
int(physDevCount); ++i) {
598 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
599 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
600 requestedPhysDevIndex = i;
606 for (
int i = 0; i <
int(physDevCount); ++i) {
607 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
608 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
610 physDevProperties.deviceName,
611 VK_VERSION_MAJOR(physDevProperties.driverVersion),
612 VK_VERSION_MINOR(physDevProperties.driverVersion),
613 VK_VERSION_PATCH(physDevProperties.driverVersion),
614 VK_VERSION_MAJOR(physDevProperties.apiVersion),
615 VK_VERSION_MINOR(physDevProperties.apiVersion),
616 VK_VERSION_PATCH(physDevProperties.apiVersion),
617 physDevProperties.vendorID,
618 physDevProperties.deviceID,
619 physDevProperties.deviceType);
620 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
622 qCDebug(QRHI_LOG_INFO,
" using this physical device");
626 if (physDevIndex < 0) {
627 qWarning(
"No matching physical device");
630 physDev = physDevs[physDevIndex];
631 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
633 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
634 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
635 physDevProperties.deviceName,
636 VK_VERSION_MAJOR(physDevProperties.driverVersion),
637 VK_VERSION_MINOR(physDevProperties.driverVersion),
638 VK_VERSION_PATCH(physDevProperties.driverVersion),
639 VK_VERSION_MAJOR(physDevProperties.apiVersion),
640 VK_VERSION_MINOR(physDevProperties.apiVersion),
641 VK_VERSION_PATCH(physDevProperties.apiVersion),
642 physDevProperties.vendorID,
643 physDevProperties.deviceID,
644 physDevProperties.deviceType);
647 caps.apiVersion = inst->apiVersion();
653 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
654 VK_VERSION_MINOR(physDevProperties.apiVersion));
655 if (physDevApiVersion < caps.apiVersion) {
656 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
657 <<
"whereas the chosen physical device has" << physDevApiVersion
658 <<
"- restricting to the latter";
659 caps.apiVersion = physDevApiVersion;
664 QVulkanInfoVector<QVulkanExtension> devExts;
665 uint32_t devExtCount = 0;
666 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
668 QList<VkExtensionProperties> extProps(devExtCount);
669 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
670 for (
const VkExtensionProperties &p : std::as_const(extProps))
671 devExts.append({ p.extensionName, p.specVersion });
673 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
675 bool featuresQueried =
false;
677 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
678 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
681#ifdef VK_KHR_fragment_shading_rate
682 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
683 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
684 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
685 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
687#ifdef VK_EXT_device_fault
688 VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
689 deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
690 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
691 addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
697 if (!featuresQueried) {
699 if (caps.apiVersion >= QVersionNumber(1, 2)) {
700 physDevFeatures11IfApi12OrNewer = {};
701 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
702 physDevFeatures12 = {};
703 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
705 physDevFeatures13 = {};
706 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
708 physDevFeatures14 = {};
709 physDevFeatures14.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
712 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
713 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
715 if (caps.apiVersion >= QVersionNumber(1, 3))
716 physDevFeatures12.pNext = &physDevFeatures13;
718 if (caps.apiVersion >= QVersionNumber(1, 4))
719 physDevFeatures13.pNext = &physDevFeatures14;
722 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
723 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
724 featuresQueried =
true;
731 if (!featuresQueried) {
739 if (caps.apiVersion == QVersionNumber(1, 1)) {
741 multiviewFeaturesIfApi11 = {};
742 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
743 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
746 shaderDrawParametersFeaturesIfApi11 = {};
747 shaderDrawParametersFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
748 addToChain(&physDevFeaturesChainable, &shaderDrawParametersFeaturesIfApi11);
750 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
751 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
752 featuresQueried =
true;
757 if (!featuresQueried) {
760 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
761 featuresQueried =
true;
769 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
770 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
771 queryQueueFamilyProps();
772 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
773 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
774 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
775 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
776 if (!gfxQueueFamilyIdxOpt.has_value()
777 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
778 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
780 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
781 gfxQueueFamilyIdxOpt = i;
782 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
783 computelessGfxQueueCandidateIdxOpt = i;
786 if (gfxQueueFamilyIdxOpt.has_value()) {
787 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
789 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
790 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
792 qWarning(
"No graphics (or no graphics+present) queue family found");
797 VkDeviceQueueCreateInfo queueInfo = {};
798 const float prio[] = { 0 };
799 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
800 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
801 queueInfo.queueCount = 1;
802 queueInfo.pQueuePriorities = prio;
804 QList<
const char *> devLayers;
805 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
806 devLayers.append(
"VK_LAYER_KHRONOS_validation");
808 QList<
const char *> requestedDevExts;
809 requestedDevExts.append(
"VK_KHR_swapchain");
811 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
813 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
814 if (hasPhysDevProp2) {
815 requestedDevExts.append(
"VK_KHR_portability_subset");
817 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
818 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
823#ifdef VK_EXT_vertex_attribute_divisor
824 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
825 if (hasPhysDevProp2) {
826 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
827 caps.vertexAttribDivisor =
true;
832#ifdef VK_KHR_create_renderpass2
833 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
834 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
835 caps.renderPass2KHR =
true;
839#ifdef VK_KHR_depth_stencil_resolve
840 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
841 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
842 caps.depthStencilResolveKHR =
true;
846#ifdef VK_KHR_fragment_shading_rate
847 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
848 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
851#ifdef VK_EXT_device_fault
852 if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
853 requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
854 caps.deviceFault =
true;
858 for (
const QByteArray &ext : std::as_const(requestedDeviceExtensions)) {
859 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
860 if (devExts.contains(ext)) {
861 requestedDevExts.append(ext.constData());
863 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
869 const QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
870 for (
const QByteArray &ext : envExtList) {
871 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
872 if (devExts.contains(ext)) {
873 requestedDevExts.append(ext.constData());
875 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
881 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
882 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
883 for (
const char *ext : std::as_const(requestedDevExts))
884 qCDebug(QRHI_LOG_INFO,
" %s", ext);
887 VkDeviceCreateInfo devInfo = {};
888 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
889 devInfo.queueCreateInfoCount = 1;
890 devInfo.pQueueCreateInfos = &queueInfo;
891 devInfo.enabledLayerCount = uint32_t(devLayers.size());
892 devInfo.ppEnabledLayerNames = devLayers.constData();
893 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
894 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
910 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
913 physDevFeatures13.robustImageAccess = VK_FALSE;
917 if (caps.apiVersion >= QVersionNumber(1, 1)) {
924 devInfo.pNext = &physDevFeaturesChainable;
928 physDevFeatures.robustBufferAccess = VK_FALSE;
929 devInfo.pEnabledFeatures = &physDevFeatures;
932 VkResult err =
f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
933 if (err != VK_SUCCESS) {
934 qWarning(
"Failed to create device: %d", err);
938 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
943 caps.deviceFault =
true;
944 caps.vertexAttribDivisor =
true;
945 caps.renderPass2KHR =
true;
946 caps.depthStencilResolveKHR =
true;
949 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
950 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
951 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
952 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
953 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
954 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
956 df = inst->deviceFunctions(dev);
958 VkCommandPoolCreateInfo poolInfo = {};
959 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
960 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
962 VkResult err =
df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
963 if (err != VK_SUCCESS) {
964 qWarning(
"Failed to create command pool: %d", err);
969 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
970 gfxQueueFamilyIdx, gfxQueueIdx);
972 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
974 if (queueFamilyProps.isEmpty())
975 queryQueueFamilyProps();
977 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
978 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
980 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
983 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
985 caps.depthClamp = physDevFeatures.depthClamp;
987 caps.wideLines = physDevFeatures.wideLines;
989 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
991 caps.tessellation = physDevFeatures.tessellationShader;
992 caps.geometryShader = physDevFeatures.geometryShader;
994 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
996 caps.drawIndirectMulti = physDevFeatures.multiDrawIndirect;
999 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1000 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
1001 caps.shaderDrawParameters = physDevFeatures11IfApi12OrNewer.shaderDrawParameters;
1005#ifdef VK_VERSION_1_1
1006 if (caps.apiVersion == QVersionNumber(1, 1)) {
1007 caps.multiView = multiviewFeaturesIfApi11.multiview;
1008 caps.shaderDrawParameters = shaderDrawParametersFeaturesIfApi11.shaderDrawParameters;
1012#ifdef VK_KHR_fragment_shading_rate
1013 fragmentShadingRates.clear();
1014 if (caps.apiVersion >= QVersionNumber(1, 1)) {
1015 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
1016 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
1017 if (caps.imageBasedShadingRate) {
1018 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
1019 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
1020 VkPhysicalDeviceProperties2 props2 = {};
1021 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1022 props2.pNext = &shadingRateProps;
1023 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1024 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
1027 if (caps.perDrawShadingRate) {
1028 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
1029 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
1030 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
1031 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
1033 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
1034 fragmentShadingRates.resize(count);
1035 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
1037 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1039 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1041 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1042 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1051#ifdef VK_KHR_create_renderpass2
1052 if (caps.renderPass2KHR) {
1053 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1054 if (!vkCreateRenderPass2KHR)
1055 caps.renderPass2KHR =
false;
1061 adapterLuidValid =
false;
1063#ifdef VK_VERSION_1_2
1064 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1065 VkPhysicalDeviceVulkan11Properties v11props = {};
1066 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1067 VkPhysicalDeviceProperties2 props2 = {};
1068 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1069 props2.pNext = &v11props;
1070 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1071 if (v11props.deviceLUIDValid) {
1072 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1073 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1074 adapterLuidValid =
true;
1075 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1076 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1077 adapterLuid.LowPart, adapterLuid.HighPart);
1084 VmaVulkanFunctions funcs = {};
1085 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1086 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1088 VmaAllocatorCreateInfo allocatorInfo = {};
1091 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1092 allocatorInfo.physicalDevice = physDev;
1093 allocatorInfo.device = dev;
1094 allocatorInfo.pVulkanFunctions = &funcs;
1095 allocatorInfo.instance = inst->vkInstance();
1103#ifdef VK_VERSION_1_4
1104 if (caps.apiVersion >= QVersionNumber(1, 4))
1105 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1108#ifdef VK_VERSION_1_3
1109 if (caps.apiVersion >= QVersionNumber(1, 3))
1110 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1113#ifdef VK_VERSION_1_2
1114 if (caps.apiVersion >= QVersionNumber(1, 2))
1115 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1118#ifdef VK_VERSION_1_1
1119 if (caps.apiVersion >= QVersionNumber(1, 1))
1120 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1123#ifdef VK_VERSION_1_0
1124 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1127 VmaAllocator vmaallocator;
1128 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1129 if (err != VK_SUCCESS) {
1130 qWarning(
"Failed to create allocator: %d", err);
1136 inst->installDebugOutputFilter(qvk_debug_filter);
1138 VkDescriptorPool pool;
1139 VkResult err = createDescriptorPool(&pool);
1140 if (err == VK_SUCCESS)
1141 descriptorPools.append(pool);
1143 qWarning(
"Failed to create initial descriptor pool: %d", err);
1145 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1146 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1147 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1149 err =
df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1150 if (err != VK_SUCCESS) {
1151 qWarning(
"Failed to create timestamp query pool: %d", err);
1154 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1155 timestampQueryPoolMap.fill(
false);
1157#ifdef VK_EXT_debug_utils
1158 if (caps.debugUtils) {
1159 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1160 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1161 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1162 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1166#ifdef VK_EXT_device_fault
1167 if (caps.deviceFault) {
1168 vkGetDeviceFaultInfoEXT =
reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev,
"vkGetDeviceFaultInfoEXT"));
1174 nativeHandlesStruct.physDev = physDev;
1175 nativeHandlesStruct.dev = dev;
1176 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1177 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1178 nativeHandlesStruct.gfxQueue = gfxQueue;
1179 nativeHandlesStruct.vmemAllocator = allocator;
1180 nativeHandlesStruct.inst = inst;
1191 df->vkDeviceWaitIdle(dev);
1198 dxgiHdrInfo =
nullptr;
1202 if (ofr.cmdFence[i]) {
1203 df->vkDestroyFence(dev, ofr.cmdFence[i],
nullptr);
1204 ofr.cmdFence[i] = VK_NULL_HANDLE;
1206 ofr.cmdFenceWaitable[i] =
false;
1209 if (pipelineCache) {
1210 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1211 pipelineCache = VK_NULL_HANDLE;
1214 for (
const DescriptorPoolData &pool : descriptorPools)
1215 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1217 descriptorPools.clear();
1219 if (timestampQueryPool) {
1220 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1221 timestampQueryPool = VK_NULL_HANDLE;
1225 vmaDestroyAllocator(toVmaAllocator(allocator));
1231 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1232 cmdPool[i] = VK_NULL_HANDLE;
1234 freeSecondaryCbs[i].clear();
1235 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1238 if (!importedDevice && dev) {
1239 df->vkDestroyDevice(dev,
nullptr);
1240 inst->resetDeviceFunctions(dev);
1241 dev = VK_NULL_HANDLE;
1251QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1253 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1254 if (nativeHandles) {
1255 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1256 requestedPhysDev = h->physDev;
1259 QRhi::AdapterList list;
1260 QVulkanFunctions *f = inst->functions();
1261 uint32_t physDevCount = 0;
1262 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1266 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1267 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1268 if (err != VK_SUCCESS || !physDevCount)
1271 VkPhysicalDeviceProperties physDevProperties = {};
1272 for (uint32_t i = 0; i < physDevCount; ++i) {
1273 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1276 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1277 QVulkanAdapter *a =
new QVulkanAdapter;
1278 a->physDev = physDevs[i];
1279 fillDriverInfo(&a->adapterInfo, physDevProperties);
1293 VkDescriptorPoolSize descPoolSizes[] = {
1294 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1295 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1296 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1297 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, QVK_SAMPLED_IMAGES_PER_POOL },
1298 { VK_DESCRIPTOR_TYPE_SAMPLER, QVK_SAMPLERS_PER_POOL },
1299 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1300 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1302 VkDescriptorPoolCreateInfo descPoolInfo = {};
1303 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1307 descPoolInfo.flags = 0;
1309 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1310 descPoolInfo.pPoolSizes = descPoolSizes;
1311 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1316 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1317 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1318 VkResult r =
df->vkAllocateDescriptorSets(dev, allocInfo, result);
1319 if (r == VK_SUCCESS)
1320 descriptorPools[poolIndex].refCount += 1;
1324 int lastPoolIdx = descriptorPools.size() - 1;
1325 for (
int i = lastPoolIdx; i >= 0; --i) {
1326 if (descriptorPools[i].refCount == 0) {
1327 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1328 descriptorPools[i].allocedDescSets = 0;
1330 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1331 VkResult err = tryAllocate(i);
1332 if (err == VK_SUCCESS) {
1333 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1334 *resultPoolIndex = i;
1340 VkDescriptorPool newPool;
1341 VkResult poolErr = createDescriptorPool(&newPool);
1342 if (poolErr == VK_SUCCESS) {
1343 descriptorPools.append(newPool);
1344 lastPoolIdx = descriptorPools.size() - 1;
1345 VkResult err = tryAllocate(lastPoolIdx);
1346 if (err != VK_SUCCESS) {
1347 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1350 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1351 *resultPoolIndex = lastPoolIdx;
1354 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1361 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1363 case QRhiTexture::RGBA8:
1364 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1365 case QRhiTexture::BGRA8:
1366 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1367 case QRhiTexture::R8:
1368 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1369 case QRhiTexture::RG8:
1370 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1371 case QRhiTexture::R16:
1372 return VK_FORMAT_R16_UNORM;
1373 case QRhiTexture::RG16:
1374 return VK_FORMAT_R16G16_UNORM;
1375 case QRhiTexture::RED_OR_ALPHA8:
1376 return VK_FORMAT_R8_UNORM;
1378 case QRhiTexture::RGBA16F:
1379 return VK_FORMAT_R16G16B16A16_SFLOAT;
1380 case QRhiTexture::RGBA32F:
1381 return VK_FORMAT_R32G32B32A32_SFLOAT;
1382 case QRhiTexture::R16F:
1383 return VK_FORMAT_R16_SFLOAT;
1384 case QRhiTexture::R32F:
1385 return VK_FORMAT_R32_SFLOAT;
1387 case QRhiTexture::RGB10A2:
1389 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1391 case QRhiTexture::R8SI:
1392 return VK_FORMAT_R8_SINT;
1393 case QRhiTexture::R32SI:
1394 return VK_FORMAT_R32_SINT;
1395 case QRhiTexture::RG32SI:
1396 return VK_FORMAT_R32G32_SINT;
1397 case QRhiTexture::RGBA32SI:
1398 return VK_FORMAT_R32G32B32A32_SINT;
1400 case QRhiTexture::R8UI:
1401 return VK_FORMAT_R8_UINT;
1402 case QRhiTexture::R32UI:
1403 return VK_FORMAT_R32_UINT;
1404 case QRhiTexture::RG32UI:
1405 return VK_FORMAT_R32G32_UINT;
1406 case QRhiTexture::RGBA32UI:
1407 return VK_FORMAT_R32G32B32A32_UINT;
1409 case QRhiTexture::D16:
1410 return VK_FORMAT_D16_UNORM;
1411 case QRhiTexture::D24:
1412 return VK_FORMAT_X8_D24_UNORM_PACK32;
1413 case QRhiTexture::D24S8:
1414 return VK_FORMAT_D24_UNORM_S8_UINT;
1415 case QRhiTexture::D32F:
1416 return VK_FORMAT_D32_SFLOAT;
1417 case QRhiTexture::D32FS8:
1418 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1420 case QRhiTexture::BC1:
1421 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1422 case QRhiTexture::BC2:
1423 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1424 case QRhiTexture::BC3:
1425 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1426 case QRhiTexture::BC4:
1427 return VK_FORMAT_BC4_UNORM_BLOCK;
1428 case QRhiTexture::BC5:
1429 return VK_FORMAT_BC5_UNORM_BLOCK;
1430 case QRhiTexture::BC6H:
1431 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1432 case QRhiTexture::BC7:
1433 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1435 case QRhiTexture::ETC2_RGB8:
1436 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1437 case QRhiTexture::ETC2_RGB8A1:
1438 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1439 case QRhiTexture::ETC2_RGBA8:
1440 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1442 case QRhiTexture::ASTC_4x4:
1443 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1444 case QRhiTexture::ASTC_5x4:
1445 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1446 case QRhiTexture::ASTC_5x5:
1447 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1448 case QRhiTexture::ASTC_6x5:
1449 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1450 case QRhiTexture::ASTC_6x6:
1451 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1452 case QRhiTexture::ASTC_8x5:
1453 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1454 case QRhiTexture::ASTC_8x6:
1455 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1456 case QRhiTexture::ASTC_8x8:
1457 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1458 case QRhiTexture::ASTC_10x5:
1459 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1460 case QRhiTexture::ASTC_10x6:
1461 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1462 case QRhiTexture::ASTC_10x8:
1463 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1464 case QRhiTexture::ASTC_10x10:
1465 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1466 case QRhiTexture::ASTC_12x10:
1467 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1468 case QRhiTexture::ASTC_12x12:
1469 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1472 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1479 case VK_FORMAT_R8G8B8A8_UNORM:
1480 return QRhiTexture::RGBA8;
1481 case VK_FORMAT_R8G8B8A8_SRGB:
1483 (*flags) |= QRhiTexture::sRGB;
1484 return QRhiTexture::RGBA8;
1485 case VK_FORMAT_B8G8R8A8_UNORM:
1486 return QRhiTexture::BGRA8;
1487 case VK_FORMAT_B8G8R8A8_SRGB:
1489 (*flags) |= QRhiTexture::sRGB;
1490 return QRhiTexture::BGRA8;
1491 case VK_FORMAT_R16G16B16A16_SFLOAT:
1492 return QRhiTexture::RGBA16F;
1493 case VK_FORMAT_R32G32B32A32_SFLOAT:
1494 return QRhiTexture::RGBA32F;
1495 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1496 return QRhiTexture::RGB10A2;
1498 qWarning(
"VkFormat %d cannot be read back", format);
1501 return QRhiTexture::UnknownFormat;
1507 case QRhiTexture::Format::D16:
1508 case QRhiTexture::Format::D24:
1509 case QRhiTexture::Format::D24S8:
1510 case QRhiTexture::Format::D32F:
1511 case QRhiTexture::Format::D32FS8:
1522 case QRhiTexture::Format::D24S8:
1523 case QRhiTexture::Format::D32FS8:
1533 if (isDepthTextureFormat(format)) {
1534 if (isStencilTextureFormat(format))
1535 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1537 return VK_IMAGE_ASPECT_DEPTH_BIT;
1539 return VK_IMAGE_ASPECT_COLOR_BIT;
1550 VkPhysicalDeviceMemoryProperties physDevMemProps;
1551 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1553 VkMemoryRequirements memReq;
1554 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1555 uint32_t memTypeIndex = uint32_t(-1);
1557 if (memReq.memoryTypeBits) {
1559 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1560 bool foundDevLocal =
false;
1561 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1562 if (memReq.memoryTypeBits & (1 << i)) {
1563 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1564 if (!foundDevLocal) {
1565 foundDevLocal =
true;
1568 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1577 return memTypeIndex;
1581 const QSize &pixelSize,
1582 VkImageUsageFlags usage,
1583 VkImageAspectFlags aspectMask,
1584 VkSampleCountFlagBits samples,
1585 VkDeviceMemory *mem,
1590 VkMemoryRequirements memReq;
1593 *mem = VK_NULL_HANDLE;
1594 for (
int i = 0; i < count; ++i) {
1595 images[i] = VK_NULL_HANDLE;
1596 views[i] = VK_NULL_HANDLE;
1599 auto cleanup = qScopeGuard([
this, mem, images, views, count] {
1600 for (
int i = 0; i < count; ++i) {
1602 df->vkDestroyImageView(dev, views[i],
nullptr);
1603 views[i] = VK_NULL_HANDLE;
1606 df->vkDestroyImage(dev, images[i],
nullptr);
1607 images[i] = VK_NULL_HANDLE;
1611 df->vkFreeMemory(dev, *mem,
nullptr);
1612 *mem = VK_NULL_HANDLE;
1616 for (
int i = 0; i < count; ++i) {
1617 VkImageCreateInfo imgInfo = {};
1618 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1619 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1620 imgInfo.format = format;
1621 imgInfo.extent.width = uint32_t(pixelSize.width());
1622 imgInfo.extent.height = uint32_t(pixelSize.height());
1623 imgInfo.extent.depth = 1;
1624 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1625 imgInfo.samples = samples;
1626 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1627 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1628 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1630 err =
df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1631 if (err != VK_SUCCESS) {
1632 qWarning(
"Failed to create image: %d", err);
1639 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1642 VkMemoryAllocateInfo memInfo = {};
1643 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1644 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1646 uint32_t startIndex = 0;
1648 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1649 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1650 qWarning(
"No suitable memory type found");
1653 startIndex = memInfo.memoryTypeIndex + 1;
1654 err =
df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1655 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1656 qWarning(
"Failed to allocate image memory: %d", err);
1659 }
while (err != VK_SUCCESS);
1661 VkDeviceSize ofs = 0;
1662 for (
int i = 0; i < count; ++i) {
1663 err =
df->vkBindImageMemory(dev, images[i], *mem, ofs);
1664 if (err != VK_SUCCESS) {
1665 qWarning(
"Failed to bind image memory: %d", err);
1668 ofs += aligned(memReq.size, memReq.alignment);
1670 VkImageViewCreateInfo imgViewInfo = {};
1671 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1672 imgViewInfo.image = images[i];
1673 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1674 imgViewInfo.format = format;
1675 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1676 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1677 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1678 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1679 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1680 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1682 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1683 if (err != VK_SUCCESS) {
1684 qWarning(
"Failed to create image view: %d", err);
1695 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1696 return optimalDsFormat;
1698 const VkFormat dsFormatCandidates[] = {
1699 VK_FORMAT_D24_UNORM_S8_UINT,
1700 VK_FORMAT_D32_SFLOAT_S8_UINT,
1701 VK_FORMAT_D16_UNORM_S8_UINT
1703 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1704 int dsFormatIdx = 0;
1705 while (dsFormatIdx < dsFormatCandidateCount) {
1706 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1707 VkFormatProperties fmtProp;
1708 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1709 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1713 if (dsFormatIdx == dsFormatCandidateCount)
1714 qWarning(
"Failed to find an optimal depth-stencil format");
1716 return optimalDsFormat;
1721 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1723 if (multiViewCount < 2)
1725 if (!multiViewCap) {
1726 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1729#ifdef VK_VERSION_1_1
1730 uint32_t allViewsMask = 0;
1731 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1732 allViewsMask |= (1 << i);
1733 multiViewMask = allViewsMask;
1734 multiViewCorrelationMask = allViewsMask;
1735 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1736 multiViewInfo.subpassCount = 1;
1737 multiViewInfo.pViewMasks = &multiViewMask;
1738 multiViewInfo.correlationMaskCount = 1;
1739 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1740 rpInfo->pNext = &multiViewInfo;
1745#ifdef VK_VERSION_1_1
1752#ifdef VK_KHR_create_renderpass2
1756struct RenderPass2SetupHelper
1758 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1760 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1764 if (multiViewCount >= 2) {
1765 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1766 viewMask |= (1 << i);
1769 attDescs2.resize(rpInfo->attachmentCount);
1770 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1771 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1772 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1774 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1775 att2.flags = att.flags;
1776 att2.format = att.format;
1777 att2.samples = att.samples;
1778 att2.loadOp = att.loadOp;
1779 att2.storeOp = att.storeOp;
1780 att2.stencilLoadOp = att.stencilLoadOp;
1781 att2.stencilStoreOp = att.stencilStoreOp;
1782 att2.initialLayout = att.initialLayout;
1783 att2.finalLayout = att.finalLayout;
1788 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1789 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1790 subpass2.flags = subpassDesc.flags;
1791 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1792 if (multiViewCount >= 2)
1793 subpass2.viewMask = viewMask;
1796 qsizetype startIndex = attRefs2.count();
1797 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1798 attRefs2.append({});
1799 VkAttachmentReference2KHR &attref2(attRefs2.last());
1800 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1801 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1802 attref2.attachment = attref.attachment;
1803 attref2.layout = attref.layout;
1804 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1806 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1807 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1810 if (subpassDesc.pResolveAttachments) {
1811 startIndex = attRefs2.count();
1812 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1813 attRefs2.append({});
1814 VkAttachmentReference2KHR &attref2(attRefs2.last());
1815 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1816 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1817 attref2.attachment = attref.attachment;
1818 attref2.layout = attref.layout;
1819 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1821 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1825 if (subpassDesc.pDepthStencilAttachment) {
1826 startIndex = attRefs2.count();
1827 attRefs2.append({});
1828 VkAttachmentReference2KHR &attref2(attRefs2.last());
1829 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1830 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1831 attref2.attachment = attref.attachment;
1832 attref2.layout = attref.layout;
1833 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1834 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1838#ifdef VK_KHR_depth_stencil_resolve
1840 if (rpD->hasDepthStencilResolve) {
1841 startIndex = attRefs2.count();
1842 attRefs2.append({});
1843 VkAttachmentReference2KHR &attref2(attRefs2.last());
1844 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1845 attref2.attachment = rpD->dsResolveRef.attachment;
1846 attref2.layout = rpD->dsResolveRef.layout;
1847 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1848 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1849 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1850 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1851 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1852 addToChain(&subpass2, &dsResolveDesc);
1856#ifdef VK_KHR_fragment_shading_rate
1857 shadingRateAttInfo = {};
1858 if (rpD->hasShadingRateMap) {
1859 startIndex = attRefs2.count();
1860 attRefs2.append({});
1861 VkAttachmentReference2KHR &attref2(attRefs2.last());
1862 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1863 attref2.attachment = rpD->shadingRateRef.attachment;
1864 attref2.layout = rpD->shadingRateRef.layout;
1865 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1866 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1867 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1868 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1869 addToChain(&subpass2, &shadingRateAttInfo);
1875 subpassDeps2.clear();
1876 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1877 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1878 subpassDeps2.append({});
1879 VkSubpassDependency2 &dep2(subpassDeps2.last());
1880 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1881 dep2.srcSubpass = dep.srcSubpass;
1882 dep2.dstSubpass = dep.dstSubpass;
1883 dep2.srcStageMask = dep.srcStageMask;
1884 dep2.dstStageMask = dep.dstStageMask;
1885 dep2.srcAccessMask = dep.srcAccessMask;
1886 dep2.dstAccessMask = dep.dstAccessMask;
1887 dep2.dependencyFlags = dep.dependencyFlags;
1890 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1891 rpInfo2->pNext =
nullptr;
1892 rpInfo2->flags = rpInfo->flags;
1893 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1894 rpInfo2->pAttachments = attDescs2.constData();
1895 rpInfo2->subpassCount = 1;
1896 rpInfo2->pSubpasses = &subpass2;
1897 rpInfo2->dependencyCount = subpassDeps2.count();
1898 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1899 if (multiViewCount >= 2) {
1900 rpInfo2->correlatedViewMaskCount = 1;
1901 rpInfo2->pCorrelatedViewMasks = &viewMask;
1907 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1908 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1909 VkSubpassDescription2KHR subpass2;
1910 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1911#ifdef VK_KHR_depth_stencil_resolve
1912 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1914#ifdef VK_KHR_fragment_shading_rate
1915 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1922 VkSubpassDescription *subpassDesc,
1925 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1926 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1927 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1928 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1929 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1930 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1932 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1933 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1934 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1935 rpInfo->pAttachments = rpD->attDescs.constData();
1936 rpInfo->subpassCount = 1;
1937 rpInfo->pSubpasses = subpassDesc;
1938 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1939 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1943 bool hasDepthStencil,
1944 VkSampleCountFlagBits samples,
1945 VkFormat colorFormat,
1946 QRhiShadingRateMap *shadingRateMap)
1950 VkAttachmentDescription attDesc = {};
1951 attDesc.format = colorFormat;
1952 attDesc.samples = samples;
1953 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1954 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1955 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1956 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1957 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1958 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1959 rpD->attDescs.append(attDesc);
1961 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1966 rpD->multiViewCount = 0;
1968 if (hasDepthStencil) {
1972 attDesc.format = optimalDepthStencilFormat();
1973 attDesc.samples = samples;
1974 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1975 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1976 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1977 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1978 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1979 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1980 rpD->attDescs.append(attDesc);
1982 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1987 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1989 attDesc.format = colorFormat;
1990 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1991 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1992 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1993 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1994 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1995 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1996 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1997 rpD->attDescs.append(attDesc);
1999 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
2002 rpD->dsResolveRef = {};
2004 rpD->shadingRateRef = {};
2005#ifdef VK_KHR_fragment_shading_rate
2006 if (shadingRateMap) {
2008 attDesc.format = VK_FORMAT_R8_UINT;
2009 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2010 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2011 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2012 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2013 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2014 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2015 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2016 rpD->attDescs.append(attDesc);
2018 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2023 VkSubpassDependency subpassDep = {};
2024 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2025 subpassDep.dstSubpass = 0;
2026 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2027 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2028 subpassDep.srcAccessMask = 0;
2029 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2030 rpD->subpassDeps.append(subpassDep);
2031 if (hasDepthStencil) {
2032 memset(&subpassDep, 0,
sizeof(subpassDep));
2033 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
2034 subpassDep.dstSubpass = 0;
2035 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2036 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2037 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2038 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2039 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2040 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
2041 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
2042 rpD->subpassDeps.append(subpassDep);
2045 VkRenderPassCreateInfo rpInfo;
2046 VkSubpassDescription subpassDesc;
2047 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2049#ifdef VK_KHR_create_renderpass2
2050 if (caps.renderPass2KHR) {
2052 VkRenderPassCreateInfo2KHR rpInfo2;
2053 RenderPass2SetupHelper rp2Helper(
this);
2054 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
2056 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2057 if (err != VK_SUCCESS) {
2058 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2065 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2066 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2067 if (err != VK_SUCCESS) {
2068 qWarning(
"Failed to create renderpass: %d", err);
2077 const QRhiColorAttachment *colorAttachmentsBegin,
2078 const QRhiColorAttachment *colorAttachmentsEnd,
2082 QRhiRenderBuffer *depthStencilBuffer,
2083 QRhiTexture *depthTexture,
2084 QRhiTexture *depthResolveTexture,
2086 QRhiShadingRateMap *shadingRateMap)
2090 int multiViewCount = 0;
2091 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2094 Q_ASSERT(texD || rbD);
2095 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2096 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2098 VkAttachmentDescription attDesc = {};
2099 attDesc.format = vkformat;
2100 attDesc.samples = samples;
2101 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2102 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2103 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2104 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2106 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2107 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2108 rpD->attDescs.append(attDesc);
2110 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2111 rpD->colorRefs.append(ref);
2113 if (it->multiViewCount() >= 2) {
2114 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2115 qWarning(
"Inconsistent multiViewCount in color attachment set");
2117 multiViewCount = it->multiViewCount();
2118 }
else if (multiViewCount > 0) {
2119 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2122 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2123 rpD->multiViewCount = uint32_t(multiViewCount);
2127 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2128 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2129 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2130 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2131 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2132 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2133 VkAttachmentDescription attDesc = {};
2134 attDesc.format = dsFormat;
2135 attDesc.samples = samples;
2136 attDesc.loadOp = loadOp;
2137 attDesc.storeOp = storeOp;
2138 attDesc.stencilLoadOp = loadOp;
2139 attDesc.stencilStoreOp = storeOp;
2140 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2141 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2142 rpD->attDescs.append(attDesc);
2143 if (depthTexture && depthTexture->arraySize() >= 2 && depthLayer == -1 && colorAttachmentsBegin == colorAttachmentsEnd) {
2144 multiViewCount = depthTexture->arraySize();
2145 rpD->multiViewCount = multiViewCount;
2147 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2152 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2153 if (it->resolveTexture()) {
2155 const VkFormat dstFormat = rtexD->vkformat;
2156 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2157 qWarning(
"Resolving into a multisample texture is not supported");
2161 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2162 if (srcFormat != dstFormat) {
2166 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2167 int(srcFormat),
int(dstFormat));
2170 VkAttachmentDescription attDesc = {};
2171 attDesc.format = rtexD->viewFormat;
2172 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2173 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2174 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2175 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2176 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2177 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2178 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2179 rpD->attDescs.append(attDesc);
2181 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2182 rpD->resolveRefs.append(ref);
2184 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2185 rpD->resolveRefs.append(ref);
2188 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2193 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2194 qWarning(
"Resolving into a multisample depth texture is not supported");
2195 const VkFormat dstFormat = rtexD->vkformat;
2199 Q_ASSERT(texD || rbD);
2200 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2201 if (srcFormat != dstFormat) {
2202 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2203 int(srcFormat),
int(dstFormat));
2206 VkAttachmentDescription attDesc = {};
2207 attDesc.format = rtexD->viewFormat;
2208 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2209 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2210 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2211 attDesc.stencilLoadOp = attDesc.loadOp;
2212 attDesc.stencilStoreOp = attDesc.storeOp;
2213 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2214 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2215 rpD->attDescs.append(attDesc);
2216 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2218 rpD->dsResolveRef = {};
2222 rpD->shadingRateRef = {};
2223#ifdef VK_KHR_fragment_shading_rate
2224 if (shadingRateMap) {
2225 VkAttachmentDescription attDesc = {};
2226 attDesc.format = VK_FORMAT_R8_UINT;
2227 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2228 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2229 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2230 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2231 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2232 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2233 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2234 rpD->attDescs.append(attDesc);
2235 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2240 VkSubpassDependency selfDependency = {};
2241 VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
2242 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
2243 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2244 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2245 selfDependency.srcSubpass = 0;
2246 selfDependency.dstSubpass = 0;
2247 selfDependency.srcStageMask = stageMask;
2248 selfDependency.dstStageMask = stageMask;
2249 selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2250 selfDependency.dstAccessMask = selfDependency.srcAccessMask;
2251 VkDependencyFlags depFlags = VK_DEPENDENCY_BY_REGION_BIT;
2252#ifdef VK_VERSION_1_1
2253 if (rpD->multiViewCount >= 2)
2254 depFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
2256 selfDependency.dependencyFlags = depFlags;
2257 rpD->subpassDeps.append(selfDependency);
2264 VkRenderPassCreateInfo rpInfo;
2265 VkSubpassDescription subpassDesc;
2266 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2269 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2272#ifdef VK_KHR_create_renderpass2
2273 if (caps.renderPass2KHR) {
2275 VkRenderPassCreateInfo2KHR rpInfo2;
2276 RenderPass2SetupHelper rp2Helper(
this);
2277 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2280 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2281 if (err != VK_SUCCESS) {
2282 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2289 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2290 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2293 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2294 VkResult err =
df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2295 if (err != VK_SUCCESS) {
2296 qWarning(
"Failed to create renderpass: %d", err);
2307 if (swapChainD->pixelSize.isEmpty()) {
2308 qWarning(
"Surface size is 0, cannot create swapchain");
2312 df->vkDeviceWaitIdle(dev);
2314 if (!vkCreateSwapchainKHR) {
2315 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2316 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2317 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2318 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2319 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2320 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2321 qWarning(
"Swapchain functions not available");
2326 VkSurfaceCapabilitiesKHR surfaceCaps;
2327 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2328 quint32 reqBufferCount;
2329 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2330 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2332 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2334 VkSurfaceTransformFlagBitsKHR preTransform =
2335 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2336 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2337 : surfaceCaps.currentTransform;
2363 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2364 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2365 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2366 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2368 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2369 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2370 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2371 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2372 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2373 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2374 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2375 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2376 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2377 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2380 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2381 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2382 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2383 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2385 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2386 && surfaceCaps.maxImageArrayLayers > 1;
2389 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2390 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2394 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2395 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2396 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2397 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2405 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2407 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2408 reuseExisting ?
"recycled" :
"new",
2409 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2411 VkSwapchainCreateInfoKHR swapChainInfo = {};
2412 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2413 swapChainInfo.surface = swapChainD->surface;
2414 swapChainInfo.minImageCount = reqBufferCount;
2415 swapChainInfo.imageFormat = swapChainD->colorFormat;
2416 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2417 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2418 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2419 swapChainInfo.imageUsage = usage;
2420 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2421 swapChainInfo.preTransform = preTransform;
2422 swapChainInfo.compositeAlpha = compositeAlpha;
2423 swapChainInfo.presentMode = presentMode;
2424 swapChainInfo.clipped =
true;
2425 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2427 VkSwapchainKHR newSwapChain;
2428 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2429 if (err != VK_SUCCESS) {
2430 qWarning(
"Failed to create swapchain: %d", err);
2433 setObjectName(uint64_t(newSwapChain), VK_OBJECT_TYPE_SWAPCHAIN_KHR, swapChainD->m_objectName);
2438 swapChainD->sc = newSwapChain;
2439 swapChainD->lastConnectedSurface = swapChainD->surface;
2441 quint32 actualSwapChainBufferCount = 0;
2442 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2443 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2444 qWarning(
"Failed to get swapchain images: %d", err);
2448 if (actualSwapChainBufferCount != reqBufferCount)
2449 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2452 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2453 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2454 if (err != VK_SUCCESS) {
2455 qWarning(
"Failed to get swapchain images: %d", err);
2459 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2460 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2461 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2462 if (!createTransientImage(swapChainD->colorFormat,
2463 swapChainD->pixelSize,
2464 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2465 VK_IMAGE_ASPECT_COLOR_BIT,
2466 swapChainD->samples,
2467 &swapChainD->msaaImageMem,
2470 swapChainD->bufferCount))
2472 qWarning(
"Failed to create transient image for MSAA color buffer");
2477 VkFenceCreateInfo fenceInfo = {};
2478 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2479 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2482 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2486 image.image = swapChainImages[i];
2487 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2488 image.msaaImage = msaaImages[i];
2489 image.msaaImageView = msaaViews[i];
2492 VkImageViewCreateInfo imgViewInfo = {};
2493 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2494 imgViewInfo.image = swapChainImages[i];
2495 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2496 imgViewInfo.format = swapChainD->colorFormat;
2497 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2498 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2499 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2500 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2501 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2502 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2503 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2504 if (err != VK_SUCCESS) {
2505 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2511 VkSemaphoreCreateInfo semInfo = {};
2512 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2513 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2518 image.image = swapChainImages[i];
2519 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2520 image.msaaImage = msaaImages[i];
2521 image.msaaImageView = msaaViews[i];
2524 VkImageViewCreateInfo imgViewInfo = {};
2525 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2526 imgViewInfo.image = swapChainImages[i];
2527 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2528 imgViewInfo.format = swapChainD->colorFormat;
2529 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2530 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2531 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2532 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2533 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2534 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2535 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2536 err =
df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2537 if (err != VK_SUCCESS) {
2538 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2542 VkSemaphoreCreateInfo semInfo = {};
2543 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2544 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2550 swapChainD->currentImageIndex = 0;
2552 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2554 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2555 VkImageViewCreateInfo viewInfo = {};
2556 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2557 viewInfo.image = texD->image;
2558 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2559 viewInfo.format = texD->viewFormat;
2560 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2561 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2562 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2563 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2564 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2565 viewInfo.subresourceRange.baseMipLevel = 0;
2566 viewInfo.subresourceRange.levelCount = 1;
2567 viewInfo.subresourceRange.baseArrayLayer = 0;
2568 viewInfo.subresourceRange.layerCount = 1;
2569 VkResult err =
df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2570 if (err != VK_SUCCESS) {
2571 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2576 VkSemaphoreCreateInfo semInfo = {};
2577 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2585 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2587 err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2588 if (err != VK_SUCCESS) {
2589 qWarning(
"Failed to create command buffer fence: %d", err);
2602 if (swapChainD->sc == VK_NULL_HANDLE)
2606 df->vkDeviceWaitIdle(dev);
2610 if (frame.cmdFence) {
2612 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2613 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2614 frame.cmdFence = VK_NULL_HANDLE;
2617 if (frame.imageSem) {
2618 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2619 frame.imageSem = VK_NULL_HANDLE;
2626 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2627 image.fb = VK_NULL_HANDLE;
2629 if (image.imageView) {
2630 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2631 image.imageView = VK_NULL_HANDLE;
2633 if (image.msaaImageView) {
2634 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2635 image.msaaImageView = VK_NULL_HANDLE;
2637 if (image.msaaImage) {
2638 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2639 image.msaaImage = VK_NULL_HANDLE;
2641 if (image.drawSem) {
2642 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2643 image.drawSem = VK_NULL_HANDLE;
2647 if (swapChainD->msaaImageMem) {
2648 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2649 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2652 if (swapChainD->shadingRateMapView) {
2653 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2654 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2657 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2658 swapChainD->sc = VK_NULL_HANDLE;
2665 VkCommandPoolResetFlags flags = 0;
2670 if (releaseCachedResourcesCalledBeforeFrameStart)
2671 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2674 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2680 for (quint64 i = 0; i < timestampValidBits; i += 8)
2681 mask |= 0xFFULL << i;
2682 const quint64 ts0 = timestamp[0] & mask;
2683 const quint64 ts1 = timestamp[1] & mask;
2684 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2685 if (!qFuzzyIsNull(nsecsPerTick)) {
2686 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2687 const double elapsedSec = elapsedMs / 1000.0;
2698 const int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2701 inst->handle()->beginFrame(swapChainD->window);
2711 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2712 if (waitResult != QRhi::FrameOpSuccess)
2717 uint32_t imageIndex = 0;
2718 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2719 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2721 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2722 swapChainD->currentImageIndex = imageIndex;
2725 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2726 return QRhi::FrameOpSwapChainOutOfDate;
2728 if (err == VK_ERROR_DEVICE_LOST) {
2729 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2730 printExtraErrorInfo(err);
2732 return QRhi::FrameOpDeviceLost;
2734 qWarning(
"Failed to acquire next swapchain image: %d", err);
2735 return QRhi::FrameOpError;
2741 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2747 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2748 if (cbres != QRhi::FrameOpSuccess)
2751 swapChainD->cbWrapper.cb = frame.cmdBuf;
2754 swapChainD->rtWrapper.d.fb = image.fb;
2758 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2759 swapChainD->rtWrapperRight.d.fb = image.fb;
2766 quint64 timestamp[2] = { 0, 0 };
2767 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame
.timestampQueryIndex), 2,
2768 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2769 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2770 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2772 if (err == VK_SUCCESS) {
2774 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2776 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2778 qWarning(
"Failed to query timestamp: %d", err);
2783 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2784 int timestampQueryIdx = -1;
2785 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2786 if (!timestampQueryPoolMap.testBit(i)) {
2787 timestampQueryPoolMap.setBit(i);
2788 timestampQueryIdx = i * 2;
2792 if (timestampQueryIdx >= 0) {
2793 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2795 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2796 timestampQueryPool, uint32_t(timestampQueryIdx));
2801 return QRhi::FrameOpSuccess;
2809 auto cleanup = qScopeGuard([
this, swapChainD] {
2810 inst->handle()->endFrame(swapChainD->window);
2815 int frameResIndex = swapChainD->bufferCount > 1 ? currentFrameSlot : 0;
2820 VkImageMemoryBarrier presTrans = {};
2821 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2822 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2823 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2824 presTrans.image = image.image;
2825 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2826 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2830 presTrans.srcAccessMask = 0;
2831 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2832 df->vkCmdPipelineBarrier(frame.cmdBuf,
2833 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2834 0, 0,
nullptr, 0,
nullptr,
2838 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2839 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2840 df->vkCmdPipelineBarrier(frame.cmdBuf,
2841 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2842 0, 0,
nullptr, 0,
nullptr,
2850 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2856 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2857 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2859 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2860 needsPresent ? &image.drawSem :
nullptr);
2861 if (submitres != QRhi::FrameOpSuccess)
2869 VkPresentInfoKHR presInfo = {};
2870 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2871 presInfo.swapchainCount = 1;
2872 presInfo.pSwapchains = &swapChainD->sc;
2873 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2874 waitSemaphoresForPresent.append(image.drawSem);
2875 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2876 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2880 inst->presentAboutToBeQueued(swapChainD->window);
2882 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2883 waitSemaphoresForPresent.clear();
2884 if (err != VK_SUCCESS) {
2885 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2886 return QRhi::FrameOpSwapChainOutOfDate;
2887 }
else if (err != VK_SUBOPTIMAL_KHR) {
2888 if (err == VK_ERROR_DEVICE_LOST) {
2889 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2890 printExtraErrorInfo(err);
2892 return QRhi::FrameOpDeviceLost;
2894 qWarning(
"Failed to present: %d", err);
2895 return QRhi::FrameOpError;
2901 inst->presentQueued(swapChainD->window);
2906 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
2911 return QRhi::FrameOpSuccess;
2925 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2935 VkCommandBufferAllocateInfo cmdBufInfo = {};
2936 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2937 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2938 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2939 cmdBufInfo.commandBufferCount = 1;
2941 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2942 if (err != VK_SUCCESS) {
2943 if (err == VK_ERROR_DEVICE_LOST) {
2944 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2945 printExtraErrorInfo(err);
2947 return QRhi::FrameOpDeviceLost;
2949 qWarning(
"Failed to allocate frame command buffer: %d", err);
2950 return QRhi::FrameOpError;
2954 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2955 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2957 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2958 if (err != VK_SUCCESS) {
2959 if (err == VK_ERROR_DEVICE_LOST) {
2960 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2961 printExtraErrorInfo(err);
2963 return QRhi::FrameOpDeviceLost;
2965 qWarning(
"Failed to begin frame command buffer: %d", err);
2966 return QRhi::FrameOpError;
2969 return QRhi::FrameOpSuccess;
2973 VkSemaphore *waitSem, VkSemaphore *signalSem)
2975 VkResult err =
df->vkEndCommandBuffer(cb);
2976 if (err != VK_SUCCESS) {
2977 if (err == VK_ERROR_DEVICE_LOST) {
2978 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2979 printExtraErrorInfo(err);
2981 return QRhi::FrameOpDeviceLost;
2983 qWarning(
"Failed to end frame command buffer: %d", err);
2984 return QRhi::FrameOpError;
2987 VkSubmitInfo submitInfo = {};
2988 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2989 submitInfo.commandBufferCount = 1;
2990 submitInfo.pCommandBuffers = &cb;
2993 waitSemaphoresForQueueSubmit.append(*waitSem);
2995 signalSemaphoresForQueueSubmit.append(*signalSem);
2997 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2998 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2999 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
3000 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3001 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
3003 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
3004 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
3005 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
3008 err =
df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
3010 waitSemaphoresForQueueSubmit.clear();
3011 signalSemaphoresForQueueSubmit.clear();
3013 if (err != VK_SUCCESS) {
3014 if (err == VK_ERROR_DEVICE_LOST) {
3015 qWarning(
"Device loss detected in vkQueueSubmit()");
3016 printExtraErrorInfo(err);
3018 return QRhi::FrameOpDeviceLost;
3020 qWarning(
"Failed to submit to graphics queue: %d", err);
3021 return QRhi::FrameOpError;
3024 return QRhi::FrameOpSuccess;
3029 for (QVkSwapChain *sc : std::as_const(swapchains)) {
3030 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
3031 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
3032 if (frame.cmdFenceWaitable) {
3033 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
3035 if (err != VK_SUCCESS) {
3036 if (err == VK_ERROR_DEVICE_LOST) {
3037 qWarning(
"Device loss detected in vkWaitForFences()");
3038 printExtraErrorInfo(err);
3040 return QRhi::FrameOpDeviceLost;
3042 qWarning(
"Failed to wait for fence: %d", err);
3043 return QRhi::FrameOpError;
3046 df->vkResetFences(dev, 1, &frame.cmdFence);
3047 frame.cmdFenceWaitable =
false;
3051 if (ofr.cmdFenceWaitable[frameSlot]) {
3052 VkResult err =
df->vkWaitForFences(dev, 1, &ofr.cmdFence[frameSlot], VK_TRUE, UINT64_MAX);
3053 if (err != VK_SUCCESS) {
3054 if (err == VK_ERROR_DEVICE_LOST) {
3055 qWarning(
"Device loss detected in vkWaitForFences()");
3056 printExtraErrorInfo(err);
3058 return QRhi::FrameOpDeviceLost;
3060 qWarning(
"Failed to wait for offscreen fence: %d", err);
3061 return QRhi::FrameOpError;
3063 df->vkResetFences(dev, 1, &ofr.cmdFence[frameSlot]);
3064 ofr.cmdFenceWaitable[frameSlot] =
false;
3067 return QRhi::FrameOpSuccess;
3072 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
3073 if (waitResult != QRhi::FrameOpSuccess)
3079 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
3080 if (cbres != QRhi::FrameOpSuccess)
3086 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3087 quint64 timestamp[2] = { 0, 0 };
3088 VkResult err =
df->vkGetQueryPoolResults(dev, timestampQueryPool,
3089 uint32_t(ofr.timestampQueryIndex[currentFrameSlot]), 2,
3090 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3091 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3092 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex[currentFrameSlot] / 2);
3093 ofr.timestampQueryIndex[currentFrameSlot] = -1;
3094 if (err == VK_SUCCESS) {
3096 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3100 qWarning(
"Failed to query timestamp: %d", err);
3104 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
3105 int timestampQueryIdx = -1;
3106 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
3107 if (!timestampQueryPoolMap.testBit(i)) {
3108 timestampQueryPoolMap.setBit(i);
3109 timestampQueryIdx = i * 2;
3113 if (timestampQueryIdx >= 0) {
3114 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
3116 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3117 timestampQueryPool, uint32_t(timestampQueryIdx));
3118 ofr.timestampQueryIndex[currentFrameSlot] = timestampQueryIdx;
3123 return QRhi::FrameOpSuccess;
3129 Q_ASSERT(ofr.active);
3135 const bool readbacksPending = !activeTextureReadbacks.isEmpty() || !activeBufferReadbacks.isEmpty();
3139 if (ofr.timestampQueryIndex[currentFrameSlot] >= 0) {
3140 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3141 timestampQueryPool, uint32_t(ofr.timestampQueryIndex[currentFrameSlot] + 1));
3144 if (!ofr.cmdFence[currentFrameSlot]) {
3145 VkFenceCreateInfo fenceInfo = {};
3146 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3147 VkResult err =
df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence[currentFrameSlot]);
3148 if (err != VK_SUCCESS) {
3149 qWarning(
"Failed to create command buffer fence: %d", err);
3150 return QRhi::FrameOpError;
3154 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence[currentFrameSlot],
nullptr,
nullptr);
3155 if (submitres != QRhi::FrameOpSuccess)
3158 ofr.cmdFenceWaitable[currentFrameSlot] =
true;
3161 if (readbacksPending) {
3162 df->vkWaitForFences(dev, 1, &ofr.cmdFence[currentFrameSlot], VK_TRUE, UINT64_MAX);
3163 df->vkResetFences(dev, 1, &ofr.cmdFence[currentFrameSlot]);
3164 ofr.cmdFenceWaitable[currentFrameSlot] =
false;
3171 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
3173 return QRhi::FrameOpSuccess;
3195 swapChainD->cbWrapper.resetCommands();
3196 cb = swapChainD->cbWrapper.cb;
3198 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3199 if (submitres != QRhi::FrameOpSuccess)
3203 df->vkQueueWaitIdle(gfxQueue);
3210 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3213 startPrimaryCommandBuffer(&frame.cmdBuf);
3214 swapChainD->cbWrapper.cb = frame.cmdBuf;
3221 return QRhi::FrameOpSuccess;
3228 u
.access =
int(bufUsage.access);
3229 u
.stage =
int(bufUsage.stage);
3237 u
.access =
int(texUsage.access);
3238 u
.stage =
int(texUsage.stage);
3244 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3247 rtD->lastActiveFrameSlot = currentFrameSlot;
3248 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3250 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3258 texD->lastActiveFrameSlot = currentFrameSlot;
3263 rbD->lastActiveFrameSlot = currentFrameSlot;
3269 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3272 if (rtD->m_desc.depthStencilBuffer()) {
3274 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3281 rbD->lastActiveFrameSlot = currentFrameSlot;
3283 if (rtD->m_desc.depthTexture()) {
3288 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3290 if (rtD->m_desc.depthResolveTexture()) {
3295 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3297 if (rtD->m_desc.shadingRateMap()) {
3302 texD->lastActiveFrameSlot = currentFrameSlot;
3316 VkCommandBuffer secondaryCb;
3318 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3319 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3320 freeSecondaryCbs[currentFrameSlot].removeLast();
3322 VkCommandBufferAllocateInfo cmdBufInfo = {};
3323 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3324 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3325 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3326 cmdBufInfo.commandBufferCount = 1;
3328 VkResult err =
df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3329 if (err != VK_SUCCESS) {
3330 qWarning(
"Failed to create secondary command buffer: %d", err);
3331 return VK_NULL_HANDLE;
3335 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3336 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3337 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3338 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3339 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3340 cmdBufInheritInfo.subpass = 0;
3342 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3343 cmdBufInheritInfo.framebuffer = rtD->fb;
3345 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3347 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3348 if (err != VK_SUCCESS) {
3349 qWarning(
"Failed to begin secondary command buffer: %d", err);
3350 return VK_NULL_HANDLE;
3358 VkResult err =
df->vkEndCommandBuffer(cb);
3359 if (err != VK_SUCCESS)
3360 qWarning(
"Failed to end secondary command buffer: %d", err);
3364 cmd.args.executeSecondary.cb = cb;
3368 e.lastActiveFrameSlot = currentFrameSlot;
3369 e.secondaryCommandBuffer.cb = cb;
3370 releaseQueue.append(e);
3374 QRhiRenderTarget *rt,
3375 const QColor &colorClearValue,
3376 const QRhiDepthStencilClearValue &depthStencilClearValue,
3377 QRhiResourceUpdateBatch *resourceUpdates,
3378 QRhiCommandBuffer::BeginPassFlags flags)
3383 if (resourceUpdates)
3393 switch (rt->resourceType()) {
3394 case QRhiResource::SwapChainRenderTarget:
3396 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3406 texD->lastActiveFrameSlot = currentFrameSlot;
3409 case QRhiResource::TextureRenderTarget:
3423 cbD->currentTarget = rt;
3428 VkRenderPassBeginInfo rpBeginInfo = {};
3429 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3430 rpBeginInfo.renderPass = rtD
->rp->rp;
3431 rpBeginInfo.framebuffer = rtD->fb;
3432 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3433 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3435 const bool rpHasAnyClearOp = std::any_of(rtD->rp->attDescs.cbegin(), rtD->rp->attDescs.cend(),
3436 [](
const VkAttachmentDescription &attDesc) {
3437 return (attDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR
3438 || attDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
3441 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3442 if (rpHasAnyClearOp) {
3444 VkClearValue cv = {};
3445 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3446 colorClearValue.alphaF() } };
3450 VkClearValue cv = {};
3451 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3455 VkClearValue cv = {};
3456 cv.color = { { colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
3457 colorClearValue.alphaF() } };
3461 VkClearValue cv = {};
3462 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3466 VkClearValue cv = {};
3467 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3471 Q_ASSERT(!rpHasAnyClearOp || cvs.size() == rtD
->rp->attDescs.size());
3472 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3476 cmd.args.beginRenderPass.desc = rpBeginInfo;
3477 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3479 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3482 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3487 rateCmd.args.setShadingRate.w = 1;
3488 rateCmd.args.setShadingRate.h = 1;
3500 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3501 cbD->activeSecondaryCbStack.removeLast();
3502 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3509 cbD->currentTarget =
nullptr;
3511 if (resourceUpdates)
3516 QRhiResourceUpdateBatch *resourceUpdates,
3517 QRhiCommandBuffer::BeginPassFlags flags)
3522 if (resourceUpdates)
3530 cbD->computePassState.reset();
3533 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3544 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3545 cbD->activeSecondaryCbStack.removeLast();
3546 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3551 if (resourceUpdates)
3558 Q_ASSERT(psD->pipeline);
3562 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3564 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3568 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3569 cmd.args.bindPipeline.pipeline = psD->pipeline;
3572 cbD->currentGraphicsPipeline =
nullptr;
3573 cbD->currentComputePipeline = ps;
3574 cbD->currentPipelineGeneration = psD->generation;
3577 psD->lastActiveFrameSlot = currentFrameSlot;
3582 QRhiShaderResourceBinding::Type bindingType,
3583 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3585 VkAccessFlags access = 0;
3586 if (bindingType == loadTypeVal) {
3587 access = VK_ACCESS_SHADER_READ_BIT;
3589 access = VK_ACCESS_SHADER_WRITE_BIT;
3590 if (bindingType == loadStoreTypeVal)
3591 access |= VK_ACCESS_SHADER_READ_BIT;
3593 auto it = writtenResources->find(resource);
3594 if (it != writtenResources->end())
3595 it->second.accessFlags |= access;
3596 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3597 writtenResources->insert(resource, { access,
true });
3607 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3608 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3609 if (cbD->currentComputeSrb) {
3613 for (
auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources)
3614 accessAndIsNewFlag = { 0,
false };
3617 for (
auto &binding : srbD->m_bindings) {
3618 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
3620 case QRhiShaderResourceBinding::ImageLoad:
3621 case QRhiShaderResourceBinding::ImageStore:
3622 case QRhiShaderResourceBinding::ImageLoadStore:
3623 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3626 QRhiShaderResourceBinding::ImageLoad,
3627 QRhiShaderResourceBinding::ImageStore,
3628 QRhiShaderResourceBinding::ImageLoadStore);
3630 case QRhiShaderResourceBinding::BufferLoad:
3631 case QRhiShaderResourceBinding::BufferStore:
3632 case QRhiShaderResourceBinding::BufferLoadStore:
3633 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3636 QRhiShaderResourceBinding::BufferLoad,
3637 QRhiShaderResourceBinding::BufferStore,
3638 QRhiShaderResourceBinding::BufferLoadStore);
3645 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3646 const VkAccessFlags accessInThisDispatch = it->second.accessFlags;
3647 const bool isNewInThisDispatch = it->second.isNew;
3648 if (accessInThisDispatch && !isNewInThisDispatch) {
3649 if (it.key()->resourceType() == QRhiResource::Texture) {
3651 VkImageMemoryBarrier barrier = {};
3652 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3653 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3655 barrier.subresourceRange.baseMipLevel = 0;
3656 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3657 barrier.subresourceRange.baseArrayLayer = 0;
3658 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3659 barrier.oldLayout = texD->usageState.layout;
3660 barrier.newLayout = texD->usageState.layout;
3661 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3662 barrier.dstAccessMask = accessInThisDispatch;
3663 barrier.image = texD->image;
3664 imageBarriers.append(barrier);
3667 VkBufferMemoryBarrier barrier = {};
3668 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3669 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3670 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3671 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3672 barrier.dstAccessMask = accessInThisDispatch;
3673 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3674 barrier.size = VK_WHOLE_SIZE;
3675 bufferBarriers.append(barrier);
3681 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3682 it = cbD->computePassState.writtenResources.erase(it);
3689 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3690 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3691 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3693 bufferBarriers.size(), bufferBarriers.isEmpty() ?
nullptr : bufferBarriers.constData(),
3694 imageBarriers.size(), imageBarriers.isEmpty() ?
nullptr : imageBarriers.constData());
3696 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3698 if (!imageBarriers.isEmpty() || !bufferBarriers.isEmpty()) {
3701 cmd.args.imageAndBufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3702 cmd.args.imageAndBufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3703 cmd.args.imageAndBufferBarrier.imageCount = imageBarriers.size();
3704 cmd.args.imageAndBufferBarrier.imageIndex = cbD->pools.imageBarrier.size();
3705 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3706 cmd.args.imageAndBufferBarrier.bufferCount = bufferBarriers.size();
3707 cmd.args.imageAndBufferBarrier.bufferIndex = cbD->pools.bufferBarrier.size();
3708 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3712 cmd.args.dispatch.x = x;
3713 cmd.args.dispatch.y = y;
3714 cmd.args.dispatch.z = z;
3720 VkShaderModuleCreateInfo shaderInfo = {};
3721 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3722 shaderInfo.codeSize = size_t(spirv.size());
3723 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3724 VkShaderModule shaderModule;
3725 VkResult err =
df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3726 if (err != VK_SUCCESS) {
3727 qWarning(
"Failed to create shader module: %d", err);
3728 return VK_NULL_HANDLE;
3730 return shaderModule;
3738 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3739 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3740 pipelineCacheInfo.initialDataSize = initialDataSize;
3741 pipelineCacheInfo.pInitialData = initialData;
3742 VkResult err =
df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3743 if (err != VK_SUCCESS) {
3744 qWarning(
"Failed to create pipeline cache: %d", err);
3754 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3755 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3756 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3757 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3758 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3760 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3761 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3764 VkWriteDescriptorSet writeInfo = {};
3765 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3766 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3767 writeInfo.dstBinding = uint32_t(b->binding);
3768 writeInfo.descriptorCount = 1;
3770 int bufferInfoIndex = -1;
3771 int imageInfoIndex = -1;
3774 case QRhiShaderResourceBinding::UniformBuffer:
3776 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3777 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3778 QRhiBuffer *buf = b->u.ubuf.buf;
3780 bd.ubuf.id = bufD->m_id;
3781 bd.ubuf.generation = bufD->generation;
3782 VkDescriptorBufferInfo bufInfo = {};
3783 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3784 bufInfo.offset = b->u.ubuf.offset;
3785 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3787 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3788 bufferInfoIndex = bufferInfos.size();
3789 bufferInfos.append(bufInfo);
3792 case QRhiShaderResourceBinding::SampledTexture:
3794 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3795 writeInfo.descriptorCount = data->count;
3796 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3797 ArrayOfImageDesc imageInfo(data->count);
3798 for (
int elem = 0; elem < data->count; ++elem) {
3801 bd.stex.d[elem].texId = texD->m_id;
3802 bd.stex.d[elem].texGeneration = texD->generation;
3803 bd.stex.d[elem].samplerId = samplerD->m_id;
3804 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3805 imageInfo[elem].sampler = samplerD->sampler;
3806 imageInfo[elem].imageView = texD->imageView;
3807 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3809 bd.stex.count = data->count;
3810 imageInfoIndex = imageInfos.size();
3811 imageInfos.append(imageInfo);
3814 case QRhiShaderResourceBinding::Texture:
3816 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3817 writeInfo.descriptorCount = data->count;
3818 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3819 ArrayOfImageDesc imageInfo(data->count);
3820 for (
int elem = 0; elem < data->count; ++elem) {
3822 bd.stex.d[elem].texId = texD->m_id;
3823 bd.stex.d[elem].texGeneration = texD->generation;
3824 bd.stex.d[elem].samplerId = 0;
3825 bd.stex.d[elem].samplerGeneration = 0;
3826 imageInfo[elem].sampler = VK_NULL_HANDLE;
3827 imageInfo[elem].imageView = texD->imageView;
3828 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3830 bd.stex.count = data->count;
3831 imageInfoIndex = imageInfos.size();
3832 imageInfos.append(imageInfo);
3835 case QRhiShaderResourceBinding::Sampler:
3838 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3839 bd.stex.d[0].texId = 0;
3840 bd.stex.d[0].texGeneration = 0;
3841 bd.stex.d[0].samplerId = samplerD->m_id;
3842 bd.stex.d[0].samplerGeneration = samplerD->generation;
3843 ArrayOfImageDesc imageInfo(1);
3844 imageInfo[0].sampler = samplerD->sampler;
3845 imageInfo[0].imageView = VK_NULL_HANDLE;
3846 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3847 imageInfoIndex = imageInfos.size();
3848 imageInfos.append(imageInfo);
3851 case QRhiShaderResourceBinding::ImageLoad:
3852 case QRhiShaderResourceBinding::ImageStore:
3853 case QRhiShaderResourceBinding::ImageLoadStore:
3856 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3858 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3859 bd.simage.id = texD->m_id;
3860 bd.simage.generation = texD->generation;
3861 ArrayOfImageDesc imageInfo(1);
3862 imageInfo[0].sampler = VK_NULL_HANDLE;
3863 imageInfo[0].imageView = view;
3864 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3865 imageInfoIndex = imageInfos.size();
3866 imageInfos.append(imageInfo);
3870 case QRhiShaderResourceBinding::BufferLoad:
3871 case QRhiShaderResourceBinding::BufferStore:
3872 case QRhiShaderResourceBinding::BufferLoadStore:
3875 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3876 bd.sbuf.id = bufD->m_id;
3877 bd.sbuf.generation = bufD->generation;
3878 VkDescriptorBufferInfo bufInfo = {};
3879 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3880 bufInfo.offset = b->u.sbuf.offset;
3881 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3882 bufferInfoIndex = bufferInfos.size();
3883 bufferInfos.append(bufInfo);
3890 writeInfos.append(writeInfo);
3891 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3894 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3895 const int bufferInfoIndex = infoIndices[i].first;
3896 const int imageInfoIndex = infoIndices[i].second;
3897 if (bufferInfoIndex >= 0)
3898 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3899 else if (imageInfoIndex >= 0)
3900 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3903 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3908 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3909 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3910 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3911 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3912 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3913 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3917 VkAccessFlags access, VkPipelineStageFlags stage)
3920 Q_ASSERT(access && stage);
3928 if (s.access == access && s.stage == stage) {
3931 if (!accessIsWrite(access))
3935 VkBufferMemoryBarrier bufMemBarrier = {};
3936 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3937 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3938 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3939 bufMemBarrier.srcAccessMask = s.access;
3940 bufMemBarrier.dstAccessMask = access;
3941 bufMemBarrier.buffer = bufD->buffers[slot];
3942 bufMemBarrier.size = VK_WHOLE_SIZE;
3946 cmd.args.bufferBarrier.srcStageMask = s.stage;
3947 cmd.args.bufferBarrier.dstStageMask = stage;
3948 cmd.args.bufferBarrier.count = 1;
3949 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3950 cbD->pools.bufferBarrier.append(bufMemBarrier);
3957 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3960 Q_ASSERT(layout && access && stage);
3962 if (s.access == access && s.stage == stage && s.layout == layout) {
3963 if (!accessIsWrite(access))
3967 VkImageMemoryBarrier barrier = {};
3968 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3969 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3970 barrier.subresourceRange.baseMipLevel = 0;
3971 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3972 barrier.subresourceRange.baseArrayLayer = 0;
3973 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3974 barrier.oldLayout = s.layout;
3975 barrier.newLayout = layout;
3976 barrier.srcAccessMask = s.access;
3977 barrier.dstAccessMask = access;
3978 barrier.image = texD->image;
3980 VkPipelineStageFlags srcStage = s.stage;
3983 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3987 cmd.args.imageBarrier.srcStageMask = srcStage;
3988 cmd.args.imageBarrier.dstStageMask = stage;
3989 cmd.args.imageBarrier.count = 1;
3990 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3991 cbD->pools.imageBarrier.append(barrier);
4002 VkImageMemoryBarrier barrier = {};
4003 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4004 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
4005 barrier.subresourceRange.baseMipLevel = 0;
4006 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
4007 barrier.subresourceRange.baseArrayLayer = 0;
4008 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
4009 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4010 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
4011 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4012 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
4013 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
4014 barrier.image = rbD->image;
4016 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
4017 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
4021 cmd.args.imageBarrier.srcStageMask = stages;
4022 cmd.args.imageBarrier.dstStageMask = stages;
4023 cmd.args.imageBarrier.count = 1;
4024 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4025 cbD->pools.imageBarrier.append(barrier);
4029 VkImageLayout oldLayout, VkImageLayout newLayout,
4030 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
4031 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
4032 int startLayer,
int layerCount,
4033 int startLevel,
int levelCount)
4036 VkImageMemoryBarrier barrier = {};
4037 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
4038 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4039 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
4040 barrier.subresourceRange.levelCount = uint32_t(levelCount);
4041 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
4042 barrier.subresourceRange.layerCount = uint32_t(layerCount);
4043 barrier.oldLayout = oldLayout;
4044 barrier.newLayout = newLayout;
4045 barrier.srcAccessMask = srcAccess;
4046 barrier.dstAccessMask = dstAccess;
4047 barrier.image = image;
4051 cmd.args.imageBarrier.srcStageMask = srcStage;
4052 cmd.args.imageBarrier.dstStageMask = dstStage;
4053 cmd.args.imageBarrier.count = 1;
4054 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
4055 cbD->pools.imageBarrier.append(barrier);
4060 VkDeviceSize size = 0;
4061 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
4062 subresDesc.data().size() : subresDesc.image().sizeInBytes();
4063 if (imageSizeBytes > 0)
4064 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4069 const QRhiTextureSubresourceUploadDescription &subresDesc,
4070 size_t *curOfs,
void *mp,
4071 BufferImageCopyList *copyInfos)
4073 qsizetype copySizeBytes = 0;
4074 qsizetype imageSizeBytes = 0;
4075 const void *src =
nullptr;
4076 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4077 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
4079 VkBufferImageCopy copyInfo = {};
4080 copyInfo.bufferOffset = *curOfs;
4081 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4082 copyInfo.imageSubresource.mipLevel = uint32_t(level);
4083 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
4084 copyInfo.imageSubresource.layerCount = 1;
4085 copyInfo.imageExtent.depth = 1;
4087 copyInfo.imageOffset.z = uint32_t(layer);
4089 copyInfo.imageOffset.y = uint32_t(layer);
4091 const QByteArray rawData = subresDesc.data();
4092 const QPoint dp = subresDesc.destinationTopLeft();
4093 QImage image = subresDesc.image();
4094 if (!image.isNull()) {
4095 copySizeBytes = imageSizeBytes = image.sizeInBytes();
4096 QSize size = image.size();
4097 src = image.constBits();
4100 int bpc = qMax(1, image.depth() / 8);
4102 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4103 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
4104 const int sx = subresDesc.sourceTopLeft().x();
4105 const int sy = subresDesc.sourceTopLeft().y();
4106 if (!subresDesc.sourceSize().isEmpty())
4107 size = subresDesc.sourceSize();
4108 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4109 if (size.width() == image.width()) {
4112 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4113 copySizeBytes = size.height() * image.bytesPerLine();
4115 image = image.copy(sx, sy, size.width(), size.height());
4116 src = image.constBits();
4119 copySizeBytes = image.sizeInBytes();
4120 bpc = qMax(1, image.depth() / 8);
4121 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4124 size = clampedSubResourceUploadSize(size, dp, level, texD->m_pixelSize);
4126 copyInfo.imageOffset.x = dp.x();
4127 copyInfo.imageOffset.y = dp.y();
4128 copyInfo.imageExtent.width = uint32_t(size.width());
4129 copyInfo.imageExtent.height = uint32_t(size.height());
4130 copyInfos->append(copyInfo);
4131 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4132 copySizeBytes = imageSizeBytes = rawData.size();
4133 src = rawData.constData();
4134 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4135 const int subresw = size.width();
4136 const int subresh = size.height();
4137 if (!subresDesc.sourceSize().isEmpty())
4138 size = subresDesc.sourceSize();
4139 const int w = size.width();
4140 const int h = size.height();
4142 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4144 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4145 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4148 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4149 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4150 copyInfos->append(copyInfo);
4151 }
else if (!rawData.isEmpty()) {
4152 copySizeBytes = imageSizeBytes = rawData.size();
4153 src = rawData.constData();
4154 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4155 if (subresDesc.dataStride()) {
4156 quint32 bytesPerPixel = 0;
4157 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4159 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4161 if (!subresDesc.sourceSize().isEmpty())
4162 size = subresDesc.sourceSize();
4163 copyInfo.imageOffset.x = dp.x();
4164 copyInfo.imageOffset.y = dp.y();
4165 copyInfo.imageExtent.width = uint32_t(size.width());
4166 copyInfo.imageExtent.height = uint32_t(size.height());
4167 copyInfos->append(copyInfo);
4169 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4173 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4174 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4180 if (err == VK_ERROR_DEVICE_LOST)
4182 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4183 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4188#ifdef VK_EXT_device_fault
4189 if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
4192 VkDeviceFaultCountsEXT faultCounts{};
4193 faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
4194 faultCounts.pNext =
nullptr;
4196 VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts,
nullptr);
4197 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4198 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4201 faultCounts.vendorBinarySize = 0;
4203 QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
4204 addressInfos.resize(faultCounts.addressInfoCount);
4206 QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
4207 vendorInfos.resize(faultCounts.vendorInfoCount);
4209 VkDeviceFaultInfoEXT info{};
4210 info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
4211 info.pNext =
nullptr;
4212 info.pAddressInfos = addressInfos.isEmpty() ?
nullptr : addressInfos.data();
4213 info.pVendorInfos = vendorInfos.isEmpty() ?
nullptr : vendorInfos.data();
4214 info.pVendorBinaryData =
nullptr;
4216 result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
4217 if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
4218 qWarning(
"vkGetDeviceFaultInfoEXT failed with %d", result);
4222 const char *desc = info.description[0] ? info.description :
"n/a";
4223 qWarning(
"VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
4224 faultCounts.addressInfoCount,
4225 faultCounts.vendorInfoCount,
4226 (
unsigned long long)faultCounts.vendorBinarySize,
4229 for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
4230 const auto &a = addressInfos[i];
4231 auto addressTypeString = [](
const VkDeviceFaultAddressTypeEXT type) {
4233 case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT:
return "NONE";
4234 case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT:
return "READ_INVALID";
4235 case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT:
return "WRITE_INVALID";
4236 case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT:
return "EXECUTE_INVALID";
4237 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT:
return "INSTRUCTION_POINTER_UNKNOWN";
4238 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT:
return "INSTRUCTION_POINTER_INVALID";
4239 case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT:
return "INSTRUCTION_POINTER_FAULT";
4240 default:
return "UNKNOWN";
4243 qWarning(
" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
4245 addressTypeString(a.addressType),
4246 (
unsigned long long)a.reportedAddress,
4247 (
unsigned long long)a.addressPrecision);
4250 for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
4251 const auto &v = vendorInfos[i];
4252 qWarning(
" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
4254 (
unsigned long long)v.vendorFaultCode,
4255 (
unsigned long long)v.vendorFaultData,
4269 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4271 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4272 bufD->pendingDynamicUpdates[i].clear();
4273 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4277 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4278 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4280 if (!bufD->stagingBuffers[currentFrameSlot]) {
4281 VkBufferCreateInfo bufferInfo = {};
4282 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4285 bufferInfo.size = bufD->m_size;
4286 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4288 VmaAllocationCreateInfo allocInfo = {};
4289 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4291 VmaAllocation allocation;
4292 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4293 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4294 if (err == VK_SUCCESS) {
4295 bufD->stagingAllocations[currentFrameSlot] = allocation;
4296 setAllocationName(allocation, bufD->name());
4298 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4299 printExtraErrorInfo(err);
4304 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u
.data.constData(),
4305 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4306 u.offset, u
.data.size());
4307 if (err != VK_SUCCESS) {
4308 qWarning(
"Failed to copy memory to buffer: %d", err);
4312 trackedBufferBarrier(cbD, bufD, 0,
4313 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4315 VkBufferCopy copyInfo = {};
4316 copyInfo.srcOffset = u.offset;
4317 copyInfo.dstOffset = u.offset;
4318 copyInfo.size = u
.data.size();
4322 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4323 cmd.args.copyBuffer.dst = bufD->buffers[0];
4324 cmd.args.copyBuffer.desc = copyInfo;
4333 bufD->lastActiveFrameSlot = currentFrameSlot;
4335 if (bufD->m_type == QRhiBuffer::Immutable) {
4338 e.lastActiveFrameSlot = currentFrameSlot;
4339 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4340 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4341 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4342 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4343 releaseQueue.append(e);
4347 if (bufD->m_type == QRhiBuffer::Dynamic) {
4349 u.result->data.resizeForOverwrite(u.readSize);
4350 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4351 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4352 u.offset, u.result->data.data(), u.readSize);
4353 if (err != VK_SUCCESS) {
4354 qWarning(
"Failed to copy memory from buffer: %d", err);
4355 u.result->data.clear();
4357 if (u.result->completed)
4358 u.result->completed();
4367 readback.activeFrameSlot = currentFrameSlot;
4368 readback.result = u.result;
4369 readback.byteSize = u.readSize;
4371 VkBufferCreateInfo bufferInfo = {};
4372 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4373 bufferInfo.size = readback.byteSize;
4374 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4376 VmaAllocationCreateInfo allocInfo = {};
4377 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4379 VmaAllocation allocation;
4380 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4381 if (err == VK_SUCCESS) {
4383 setAllocationName(allocation, bufD->name());
4385 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4386 printExtraErrorInfo(err);
4390 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4392 VkBufferCopy copyInfo = {};
4393 copyInfo.srcOffset = u.offset;
4394 copyInfo.size = u.readSize;
4398 cmd.args.copyBuffer.src = bufD->buffers[0];
4399 cmd.args.copyBuffer.dst = readback.stagingBuf;
4400 cmd.args.copyBuffer.desc = copyInfo;
4402 bufD->lastActiveFrameSlot = currentFrameSlot;
4404 activeBufferReadbacks.append(readback);
4414 VkDeviceSize stagingSize = 0;
4415 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4416 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4417 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4418 stagingSize += subresUploadByteSize(subresDesc);
4422 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4423 VkBufferCreateInfo bufferInfo = {};
4424 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4425 bufferInfo.size = stagingSize;
4426 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4428 VmaAllocationCreateInfo allocInfo = {};
4429 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4431 VmaAllocation allocation;
4432 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4433 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4434 if (err != VK_SUCCESS) {
4435 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4436 printExtraErrorInfo(err);
4439 utexD->stagingAllocations[currentFrameSlot] = allocation;
4440 setAllocationName(allocation, utexD->name());
4442 BufferImageCopyList copyInfos;
4445 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4446 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4447 if (err != VK_SUCCESS) {
4448 qWarning(
"Failed to map image data: %d", err);
4449 vmaDestroyBuffer(toVmaAllocator(allocator), utexD->stagingBuffers[currentFrameSlot], a);
4450 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4451 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4455 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4456 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4457 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4460 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4461 prepareUploadSubres(utexD, layer, level,
4462 subresDesc, &curOfs, mp, ©Infos);
4466 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4467 vmaUnmapMemory(toVmaAllocator(allocator), a);
4469 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4470 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4474 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4475 cmd.args.copyBufferToImage.dst = utexD->image;
4476 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4477 cmd.args.copyBufferToImage.count = copyInfos.size();
4478 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4479 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4484 e.lastActiveFrameSlot = currentFrameSlot;
4485 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4486 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4487 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4488 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4489 releaseQueue.append(e);
4494 utexD->lastActiveFrameSlot = currentFrameSlot;
4498 qWarning(
"Texture copy with matching source and destination is not supported");
4503 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4504 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4506 VkImageCopy region = {};
4507 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4508 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4509 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4510 region.srcSubresource.layerCount = 1;
4512 region.srcOffset.x = u.desc.sourceTopLeft().x();
4513 region.srcOffset.y = u.desc.sourceTopLeft().y();
4515 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4517 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4518 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4519 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4520 region.dstSubresource.layerCount = 1;
4522 region.dstOffset.x = u.desc.destinationTopLeft().x();
4523 region.dstOffset.y = u.desc.destinationTopLeft().y();
4525 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4527 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4528 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4529 region.extent.width = uint32_t(copySize.width());
4530 region.extent.height = uint32_t(copySize.height());
4531 region.extent.depth = 1;
4533 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4534 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4535 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4536 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4540 cmd.args.copyImage.src = srcD->image;
4541 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4542 cmd.args.copyImage.dst = dstD->image;
4543 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4544 cmd.args.copyImage.desc = region;
4546 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4549 readback.activeFrameSlot = currentFrameSlot;
4550 readback.desc = u.rb;
4551 readback.result = u.result;
4557 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4558 qWarning(
"Multisample texture cannot be read back");
4561 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4562 if (u.rb.rect().isValid())
4563 readback.rect = u.rb.rect();
4565 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4566 readback.format = texD->m_format;
4567 texD->lastActiveFrameSlot = currentFrameSlot;
4572 qWarning(
"Swapchain does not support readback");
4575 if (u.rb.rect().isValid())
4576 readback.rect = u.rb.rect();
4578 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4579 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4580 if (readback.format == QRhiTexture::UnknownFormat)
4586 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4589 VkBufferCreateInfo bufferInfo = {};
4590 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4591 bufferInfo.size = readback.byteSize;
4592 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4594 VmaAllocationCreateInfo allocInfo = {};
4595 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4597 VmaAllocation allocation;
4598 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4599 if (err == VK_SUCCESS) {
4601 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4603 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4604 printExtraErrorInfo(err);
4609 VkBufferImageCopy copyDesc = {};
4610 copyDesc.bufferOffset = 0;
4611 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4612 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4613 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4614 copyDesc.imageSubresource.layerCount = 1;
4615 copyDesc.imageOffset.x = readback.rect.x();
4616 copyDesc.imageOffset.y = readback.rect.y();
4618 copyDesc.imageOffset.z = u.rb.layer();
4619 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4620 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4621 copyDesc.imageExtent.depth = 1;
4624 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4625 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4628 cmd.args.copyImageToBuffer.src = texD->image;
4629 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4630 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4631 cmd.args.copyImageToBuffer.desc = copyDesc;
4635 VkImage image = imageRes.image;
4638 qWarning(
"Attempted to read back undefined swapchain image content, "
4639 "results are undefined. (do a render pass first)");
4641 subresourceBarrier(cbD, image,
4642 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4643 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4644 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4652 cmd.args.copyImageToBuffer.src = image;
4653 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4654 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4655 cmd.args.copyImageToBuffer.desc = copyDesc;
4658 activeTextureReadbacks.append(readback);
4661 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4662 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4663 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4664 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4666 VkImageLayout origLayout = utexD->usageState.layout;
4667 VkAccessFlags origAccess = utexD->usageState.access;
4668 VkPipelineStageFlags origStage = utexD->usageState.stage;
4670 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4672 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4673 int w = utexD->m_pixelSize.width();
4674 int h = utexD->m_pixelSize.height();
4675 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4676 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4678 subresourceBarrier(cbD, utexD->image,
4679 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4680 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4681 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4685 subresourceBarrier(cbD, utexD->image,
4686 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4687 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4688 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4693 subresourceBarrier(cbD, utexD->image,
4694 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4695 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4696 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4700 VkImageBlit region = {};
4701 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4702 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4703 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4704 region.srcSubresource.layerCount = 1;
4706 region.srcOffsets[1].x = qMax(1, w);
4707 region.srcOffsets[1].y = qMax(1, h);
4708 region.srcOffsets[1].z = qMax(1, depth);
4710 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4711 region.dstSubresource.mipLevel = uint32_t(level);
4712 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4713 region.dstSubresource.layerCount = 1;
4715 region.dstOffsets[1].x = qMax(1, w >> 1);
4716 region.dstOffsets[1].y = qMax(1, h >> 1);
4717 region.dstOffsets[1].z = qMax(1, depth >> 1);
4721 cmd.args.blitImage.src = utexD->image;
4722 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4723 cmd.args.blitImage.dst = utexD->image;
4724 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4725 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4726 cmd.args.blitImage.desc = region;
4733 if (utexD->mipLevelCount > 1) {
4734 subresourceBarrier(cbD, utexD->image,
4735 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4736 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4737 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4739 0,
int(utexD->mipLevelCount) - 1);
4740 subresourceBarrier(cbD, utexD->image,
4741 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4742 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4743 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4745 int(utexD->mipLevelCount) - 1, 1);
4748 utexD->lastActiveFrameSlot = currentFrameSlot;
4757 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4760 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4762 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4766 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4767 if (err != VK_SUCCESS) {
4768 qWarning(
"Failed to map buffer: %d", err);
4771 quint32 changeBegin = UINT32_MAX;
4772 quint32 changeEnd = 0;
4773 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4774 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4775 if (u.offset < changeBegin)
4776 changeBegin = u.offset;
4777 if (u.offset + u.data.size() > changeEnd)
4778 changeEnd = u.offset + u.data.size();
4780 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4781 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4782 vmaUnmapMemory(toVmaAllocator(allocator), a);
4784 bufD->pendingDynamicUpdates[slot].clear();
4790 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4791 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4797 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4798 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4799 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4804 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4805 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4807 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4808 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4809 if (e.texture.extraImageViews[i])
4810 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4816 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4821 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4823 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4826 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4827 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4830 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4831 if (e.shaderResourceBindings.poolIndex >= 0) {
4832 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4833 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4840 qrhivk_releaseRenderBuffer(e, dev,
df);
4846 qrhivk_releaseSampler(e, dev,
df);
4849 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4851 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4852 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4854 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4855 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4856 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4859 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4862 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4864 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4865 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4871 releaseQueue.removeAt(i);
4878 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4880 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4882 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4883 readback.result->format = readback.format;
4884 readback.result->pixelSize = readback.rect.size();
4885 readback.result->data.resizeForOverwrite(readback.byteSize);
4886 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4887 toVmaAllocation(readback.stagingAlloc),
4888 0, readback.result->data.data(), readback.byteSize);
4889 if (err != VK_SUCCESS) {
4890 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4891 readback.result->data.clear();
4894 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4896 if (readback.result->completed)
4897 completedCallbacks.append(readback.result->completed);
4899 activeTextureReadbacks.remove(i);
4903 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4905 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4906 readback.result->data.resizeForOverwrite(readback.byteSize);
4907 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4908 toVmaAllocation(readback.stagingAlloc),
4909 0, readback.result->data.data(), readback.byteSize);
4910 if (err != VK_SUCCESS) {
4911 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4912 readback.result->data.clear();
4915 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4917 if (readback.result->completed)
4918 completedCallbacks.append(readback.result->completed);
4920 activeBufferReadbacks.remove(i);
4924 for (
const auto &f : completedCallbacks)
4931} qvk_sampleCounts[] = {
4933 { VK_SAMPLE_COUNT_1_BIT, 1 },
4934 { VK_SAMPLE_COUNT_2_BIT, 2 },
4935 { VK_SAMPLE_COUNT_4_BIT, 4 },
4936 { VK_SAMPLE_COUNT_8_BIT, 8 },
4937 { VK_SAMPLE_COUNT_16_BIT, 16 },
4938 { VK_SAMPLE_COUNT_32_BIT, 32 },
4939 { VK_SAMPLE_COUNT_64_BIT, 64 }
4944 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4945 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4946 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4947 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4950 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4951 if ((color & qvk_sampleCount.mask)
4952 && (depth & qvk_sampleCount.mask)
4953 && (stencil & qvk_sampleCount.mask))
4955 result.append(qvk_sampleCount.count);
4964 const int s = effectiveSampleCount(sampleCount);
4966 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4967 if (qvk_sampleCount.count == s)
4968 return qvk_sampleCount.mask;
4971 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4976 QList<QSize> result;
4977#ifdef VK_KHR_fragment_shading_rate
4978 sampleCount = qMax(1, sampleCount);
4979 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4980 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4981 if (qvk_sampleCount.count == sampleCount) {
4982 mask = qvk_sampleCount.mask;
4986 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4987 if (s.sampleCounts & mask)
4988 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4991 Q_UNUSED(sampleCount);
4992 result.append(QSize(1, 1));
4999 cbD->passResTrackers.emplace_back();
5004 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
5011 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
5015 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
5016 1, &cmd.args.copyBuffer.desc);
5019 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
5020 cmd.args.copyBufferToImage.dstLayout,
5021 uint32_t(cmd.args.copyBufferToImage.count),
5022 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
5025 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
5026 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
5027 1, &cmd.args.copyImage.desc);
5030 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
5031 cmd.args.copyImageToBuffer.dst,
5032 1, &cmd.args.copyImageToBuffer.desc);
5035 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
5036 0, 0,
nullptr, 0,
nullptr,
5037 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
5040 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
5042 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
5046 const auto &barrier = cmd.args.imageAndBufferBarrier;
5047 const VkBufferMemoryBarrier *bufferBarrierData = barrier.bufferCount
5048 ? cbD->pools.bufferBarrier.constData() + barrier.bufferIndex :
nullptr;
5049 const VkImageMemoryBarrier *imageBarrierData = barrier.imageCount
5050 ? cbD->pools.imageBarrier.constData() + barrier.imageIndex :
nullptr;
5051 df->vkCmdPipelineBarrier(cbD->cb, barrier.srcStageMask, barrier.dstStageMask,
5053 barrier.bufferCount, bufferBarrierData,
5054 barrier.imageCount, imageBarrierData);
5057 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
5058 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
5059 1, &cmd.args.blitImage.desc,
5060 cmd.args.blitImage.filter);
5063 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
5064 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
5065 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
5066 : VK_SUBPASS_CONTENTS_INLINE);
5069 VkMemoryBarrier barrier = {};
5070 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5071 barrier.pNext =
nullptr;
5072 barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
5073 barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
5074 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
5080 df->vkCmdEndRenderPass(cbD->cb);
5083 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
5087 const uint32_t *offsets =
nullptr;
5088 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
5089 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
5090 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
5091 cmd.args.bindDescriptorSet.pipelineLayout,
5092 0, 1, &cmd.args.bindDescriptorSet.descSet,
5093 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
5098 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
5099 uint32_t(cmd.args.bindVertexBuffer.count),
5100 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
5101 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
5104 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
5105 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
5108 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
5111 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
5114 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
5117 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
5120 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
5121 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
5124 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
5125 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
5126 cmd.args.drawIndexed.firstInstance);
5129 df->vkCmdDrawIndirect(cbD->cb, cmd.args.drawIndirect.indirectBuffer,
5130 cmd.args.drawIndirect.indirectBufferOffset,
5131 cmd.args.drawIndirect.drawCount,
5132 cmd.args.drawIndirect.stride);
5135 df->vkCmdDrawIndexedIndirect(cbD->cb, cmd.args.drawIndexedIndirect.indirectBuffer,
5136 cmd.args.drawIndexedIndirect.indirectBufferOffset,
5137 cmd.args.drawIndexedIndirect.drawCount,
5138 cmd.args.drawIndexedIndirect.stride);
5141#ifdef VK_EXT_debug_utils
5142 cmd.args.debugMarkerBegin.label.pLabelName =
5143 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
5144 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
5148#ifdef VK_EXT_debug_utils
5149 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
5153#ifdef VK_EXT_debug_utils
5154 cmd.args.debugMarkerInsert.label.pLabelName =
5155 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
5156 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
5163 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
5166 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
5170#ifdef VK_KHR_fragment_shading_rate
5171 VkFragmentShadingRateCombinerOpKHR op[2] = {
5172 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
5173 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
5175 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
5176 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
5189 case QRhiPassResourceTracker::BufIndirectDraw:
5190 return VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
5191 case QRhiPassResourceTracker::BufVertexInput:
5192 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
5193 case QRhiPassResourceTracker::BufIndexRead:
5194 return VK_ACCESS_INDEX_READ_BIT;
5195 case QRhiPassResourceTracker::BufUniformRead:
5196 return VK_ACCESS_UNIFORM_READ_BIT;
5197 case QRhiPassResourceTracker::BufStorageLoad:
5198 return VK_ACCESS_SHADER_READ_BIT;
5199 case QRhiPassResourceTracker::BufStorageStore:
5200 return VK_ACCESS_SHADER_WRITE_BIT;
5201 case QRhiPassResourceTracker::BufStorageLoadStore:
5202 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5213 case QRhiPassResourceTracker::BufIndirectDrawStage:
5214 return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
5215 case QRhiPassResourceTracker::BufVertexInputStage:
5216 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
5217 case QRhiPassResourceTracker::BufVertexStage:
5218 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5219 case QRhiPassResourceTracker::BufTCStage:
5220 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5221 case QRhiPassResourceTracker::BufTEStage:
5222 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5223 case QRhiPassResourceTracker::BufFragmentStage:
5224 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5225 case QRhiPassResourceTracker::BufComputeStage:
5226 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5227 case QRhiPassResourceTracker::BufGeometryStage:
5228 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5239 u.access = VkAccessFlags(usage
.access);
5240 u.stage = VkPipelineStageFlags(usage
.stage);
5247 case QRhiPassResourceTracker::TexSample:
5248 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5249 case QRhiPassResourceTracker::TexColorOutput:
5250 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5251 case QRhiPassResourceTracker::TexDepthOutput:
5252 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5253 case QRhiPassResourceTracker::TexStorageLoad:
5254 case QRhiPassResourceTracker::TexStorageStore:
5255 case QRhiPassResourceTracker::TexStorageLoadStore:
5256 return VK_IMAGE_LAYOUT_GENERAL;
5257 case QRhiPassResourceTracker::TexShadingRate:
5258#ifdef VK_KHR_fragment_shading_rate
5259 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5261 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5267 return VK_IMAGE_LAYOUT_GENERAL;
5273 case QRhiPassResourceTracker::TexSample:
5274 return VK_ACCESS_SHADER_READ_BIT;
5275 case QRhiPassResourceTracker::TexColorOutput:
5276 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5277 case QRhiPassResourceTracker::TexDepthOutput:
5278 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5279 case QRhiPassResourceTracker::TexStorageLoad:
5280 return VK_ACCESS_SHADER_READ_BIT;
5281 case QRhiPassResourceTracker::TexStorageStore:
5282 return VK_ACCESS_SHADER_WRITE_BIT;
5283 case QRhiPassResourceTracker::TexStorageLoadStore:
5284 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5297 case QRhiPassResourceTracker::TexVertexStage:
5298 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5299 case QRhiPassResourceTracker::TexTCStage:
5300 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5301 case QRhiPassResourceTracker::TexTEStage:
5302 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5303 case QRhiPassResourceTracker::TexFragmentStage:
5304 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5305 case QRhiPassResourceTracker::TexColorOutputStage:
5306 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5307 case QRhiPassResourceTracker::TexDepthOutputStage:
5308 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5309 case QRhiPassResourceTracker::TexComputeStage:
5310 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5311 case QRhiPassResourceTracker::TexGeometryStage:
5312 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5323 u.layout = VkImageLayout(usage
.layout);
5324 u.access = VkAccessFlags(usage
.access);
5325 u.stage = VkPipelineStageFlags(usage
.stage);
5336 const VkAccessFlags newAccess = toVkAccess(access);
5337 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5338 if (u.access == newAccess && u.stage == newStage) {
5339 if (!accessIsWrite(newAccess))
5343 u.access = newAccess;
5353 const VkAccessFlags newAccess = toVkAccess(access);
5354 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5355 const VkImageLayout newLayout = toVkLayout(access);
5356 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5357 if (!accessIsWrite(newAccess))
5361 u.layout = newLayout;
5362 u.access = newAccess;
5371 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5372 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5373 VkAccessFlags access = toVkAccess(trackedB.access);
5374 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5375 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5378 if (s.access == access && s.stage == stage) {
5379 if (!accessIsWrite(access))
5382 VkBufferMemoryBarrier bufMemBarrier = {};
5383 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5384 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5385 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5386 bufMemBarrier.srcAccessMask = s.access;
5387 bufMemBarrier.dstAccessMask = access;
5388 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5389 bufMemBarrier.size = VK_WHOLE_SIZE;
5390 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5396 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5397 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5398 VkImageLayout layout = toVkLayout(trackedT.access);
5399 VkAccessFlags access = toVkAccess(trackedT.access);
5400 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5401 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5402 if (s.access == access && s.stage == stage && s.layout == layout) {
5403 if (!accessIsWrite(access))
5406 VkImageMemoryBarrier barrier = {};
5407 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5408 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5409 barrier.subresourceRange.baseMipLevel = 0;
5410 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5411 barrier.subresourceRange.baseArrayLayer = 0;
5412 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5413 barrier.oldLayout = s.layout;
5414 barrier.newLayout = layout;
5415 barrier.srcAccessMask = s.access;
5416 barrier.dstAccessMask = access;
5417 barrier.image = texD->image;
5418 VkPipelineStageFlags srcStage = s.stage;
5421 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5422 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5431 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5432 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5433 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5435 qWarning(
"Physical device surface queries not available");
5439 return new QVkSwapChain(
this);
5442QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5444 return new QVkBuffer(
this, type, usage, size);
5449 return int(ubufAlign);
5472 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
5473 0.0f, -1.0f, 0.0f, 0.0f,
5474 0.0f, 0.0f, 0.5f, 0.5f,
5475 0.0f, 0.0f, 0.0f, 1.0f);
5484 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5485 if (!physDevFeatures.textureCompressionBC)
5489 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5490 if (!physDevFeatures.textureCompressionETC2)
5494 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5495 if (!physDevFeatures.textureCompressionASTC_LDR)
5499 VkFormat vkformat = toVkTextureFormat(format, flags);
5500 VkFormatProperties props;
5501 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5502 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5508 case QRhi::MultisampleTexture:
5510 case QRhi::MultisampleRenderBuffer:
5512 case QRhi::DebugMarkers:
5513 return caps.debugUtils;
5514 case QRhi::Timestamps:
5515 return timestampValidBits != 0;
5516 case QRhi::Instancing:
5518 case QRhi::CustomInstanceStepRate:
5519 return caps.vertexAttribDivisor;
5520 case QRhi::PrimitiveRestart:
5522 case QRhi::NonDynamicUniformBuffers:
5524 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5526 case QRhi::NPOTTextureRepeat:
5528 case QRhi::RedOrAlpha8IsRed:
5530 case QRhi::ElementIndexUint:
5533 return caps.compute;
5534 case QRhi::WideLines:
5535 return caps.wideLines;
5536 case QRhi::VertexShaderPointSize:
5538 case QRhi::BaseVertex:
5540 case QRhi::BaseInstance:
5542 case QRhi::TriangleFanTopology:
5544 case QRhi::ReadBackNonUniformBuffer:
5546 case QRhi::ReadBackNonBaseMipLevel:
5548 case QRhi::TexelFetch:
5550 case QRhi::RenderToNonBaseMipLevel:
5552 case QRhi::IntAttributes:
5554 case QRhi::ScreenSpaceDerivatives:
5556 case QRhi::ReadBackAnyTextureFormat:
5558 case QRhi::PipelineCacheDataLoadSave:
5560 case QRhi::ImageDataStride:
5562 case QRhi::RenderBufferImport:
5564 case QRhi::ThreeDimensionalTextures:
5566 case QRhi::RenderTo3DTextureSlice:
5567 return caps.texture3DSliceAs2D;
5568 case QRhi::TextureArrays:
5570 case QRhi::Tessellation:
5571 return caps.tessellation;
5572 case QRhi::GeometryShader:
5573 return caps.geometryShader;
5574 case QRhi::TextureArrayRange:
5576 case QRhi::NonFillPolygonMode:
5577 return caps.nonFillPolygonMode;
5578 case QRhi::OneDimensionalTextures:
5580 case QRhi::OneDimensionalTextureMipmaps:
5582 case QRhi::HalfAttributes:
5584 case QRhi::RenderToOneDimensionalTexture:
5586 case QRhi::ThreeDimensionalTextureMipmaps:
5588 case QRhi::MultiView:
5589 return caps.multiView;
5590 case QRhi::TextureViewFormat:
5592 case QRhi::ResolveDepthStencil:
5593 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5594 case QRhi::VariableRateShading:
5595 return caps.renderPass2KHR && caps.perDrawShadingRate;
5596 case QRhi::VariableRateShadingMap:
5597 case QRhi::VariableRateShadingMapWithTexture:
5598 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5599 case QRhi::PerRenderTargetBlending:
5600 case QRhi::SampleVariables:
5602 case QRhi::InstanceIndexIncludesBaseInstance:
5604 case QRhi::DepthClamp:
5605 return caps.depthClamp;
5606 case QRhi::DrawIndirect:
5608 case QRhi::DrawIndirectMulti:
5609 return caps.drawIndirectMulti;
5610 case QRhi::ShaderDrawParameters:
5611 return caps.shaderDrawParameters;
5613 Q_UNREACHABLE_RETURN(
false);
5620 case QRhi::TextureSizeMin:
5622 case QRhi::TextureSizeMax:
5623 return int(physDevProperties.limits.maxImageDimension2D);
5624 case QRhi::MaxColorAttachments:
5625 return int(physDevProperties.limits.maxColorAttachments);
5626 case QRhi::FramesInFlight:
5628 case QRhi::MaxAsyncReadbackFrames:
5630 case QRhi::MaxThreadGroupsPerDimension:
5631 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5632 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5633 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5634 case QRhi::MaxThreadsPerThreadGroup:
5635 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5636 case QRhi::MaxThreadGroupX:
5637 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5638 case QRhi::MaxThreadGroupY:
5639 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5640 case QRhi::MaxThreadGroupZ:
5641 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5642 case QRhi::TextureArraySizeMax:
5643 return int(physDevProperties.limits.maxImageArrayLayers);
5644 case QRhi::MaxUniformBufferRange:
5645 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5646 case QRhi::MaxVertexInputs:
5647 return physDevProperties.limits.maxVertexInputAttributes;
5648 case QRhi::MaxVertexOutputs:
5649 return physDevProperties.limits.maxVertexOutputComponents / 4;
5650 case QRhi::ShadingRateImageTileSize:
5651 return caps.imageBasedShadingRateTileSize;
5653 Q_UNREACHABLE_RETURN(0);
5659 return &nativeHandlesStruct;
5664 return driverInfoStruct;
5670 result.totalPipelineCreationTime = totalPipelineCreationTime();
5672 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5673 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5675 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5676 for (uint32_t i = 0; i < count; ++i) {
5677 const VmaStatistics &stats(budgets[i].statistics);
5678 result.blockCount += stats.blockCount;
5679 result.allocCount += stats.allocationCount;
5680 result.usedBytes += stats.allocationBytes;
5681 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5695 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5699 waitSemaphoresForQueueSubmit.clear();
5700 if (sp->waitSemaphoreCount)
5701 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5703 signalSemaphoresForQueueSubmit.clear();
5704 if (sp->signalSemaphoreCount)
5705 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5707 waitSemaphoresForPresent.clear();
5708 if (sp->presentWaitSemaphoreCount)
5709 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5739 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5742 size_t dataSize = 0;
5743 VkResult err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5744 if (err != VK_SUCCESS) {
5745 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5746 return QByteArray();
5749 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5750 data.resize(dataOffset + dataSize);
5751 err =
df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5752 if (err != VK_SUCCESS) {
5753 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5754 return QByteArray();
5758 header.rhiId = pipelineCacheRhiId();
5759 header.arch = quint32(
sizeof(
void*));
5760 header.driverVersion = physDevProperties.driverVersion;
5761 header.vendorId = physDevProperties.vendorID;
5762 header.deviceId = physDevProperties.deviceID;
5763 header.dataSize = quint32(dataSize);
5764 header.uuidSize = VK_UUID_SIZE;
5765 header.reserved = 0;
5766 memcpy(data.data(), &header, headerSize);
5767 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5778 if (data.size() < qsizetype(headerSize)) {
5779 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5783 memcpy(&header, data.constData(), headerSize);
5785 const quint32 rhiId = pipelineCacheRhiId();
5786 if (header.rhiId != rhiId) {
5787 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5788 rhiId, header.rhiId);
5791 const quint32 arch = quint32(
sizeof(
void*));
5792 if (header.arch != arch) {
5793 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5797 if (header.driverVersion != physDevProperties.driverVersion) {
5798 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5799 physDevProperties.driverVersion, header.driverVersion);
5802 if (header.vendorId != physDevProperties.vendorID) {
5803 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5804 physDevProperties.vendorID, header.vendorId);
5807 if (header.deviceId != physDevProperties.deviceID) {
5808 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5809 physDevProperties.deviceID, header.deviceId);
5812 if (header.uuidSize != VK_UUID_SIZE) {
5813 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5814 quint32(VK_UUID_SIZE), header.uuidSize);
5818 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5819 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5822 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5823 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5827 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5828 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5829 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5833 if (pipelineCache) {
5834 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5835 pipelineCache = VK_NULL_HANDLE;
5838 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5839 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5840 int(header.dataSize));
5842 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5846QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5847 int sampleCount, QRhiRenderBuffer::Flags flags,
5848 QRhiTexture::Format backingFormatHint)
5850 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5854 const QSize &pixelSize,
int depth,
int arraySize,
5855 int sampleCount, QRhiTexture::Flags flags)
5857 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5861 QRhiSampler::Filter mipmapMode,
5862 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5864 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5869 return new QVkShadingRateMap(
this);
5873 QRhiTextureRenderTarget::Flags flags)
5880 return new QVkGraphicsPipeline(
this);
5885 return new QVkComputePipeline(
this);
5890 return new QVkShaderResourceBindings(
this);
5896 Q_ASSERT(psD->pipeline);
5900 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5902 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5906 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5907 cmd.args.bindPipeline.pipeline = psD->pipeline;
5910 cbD->currentGraphicsPipeline = ps;
5911 cbD->currentComputePipeline =
nullptr;
5912 cbD->currentPipelineGeneration = psD->generation;
5918 psD->lastActiveFrameSlot = currentFrameSlot;
5922 int dynamicOffsetCount,
5923 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5933 srb = gfxPsD->m_shaderResourceBindings;
5935 srb = compPsD->m_shaderResourceBindings;
5939 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5940 bool rewriteDescSet =
false;
5941 bool addWriteBarrier =
false;
5942 VkPipelineStageFlags writeBarrierSrcStageMask = 0;
5943 VkPipelineStageFlags writeBarrierDstStageMask = 0;
5947 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5948 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5951 case QRhiShaderResourceBinding::UniformBuffer:
5954 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5955 sanityCheckResourceOwnership(bufD);
5957 if (bufD->m_type == QRhiBuffer::Dynamic)
5960 bufD->lastActiveFrameSlot = currentFrameSlot;
5961 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5963 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5969 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5970 rewriteDescSet =
true;
5971 bd.ubuf.id = bufD->m_id;
5972 bd.ubuf.generation = bufD->generation;
5976 case QRhiShaderResourceBinding::SampledTexture:
5977 case QRhiShaderResourceBinding::Texture:
5978 case QRhiShaderResourceBinding::Sampler:
5980 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5981 if (bd.stex.count != data->count) {
5982 bd.stex.count = data->count;
5983 rewriteDescSet =
true;
5985 for (
int elem = 0; elem < data->count; ++elem) {
5991 Q_ASSERT(texD || samplerD);
5992 sanityCheckResourceOwnership(texD);
5993 sanityCheckResourceOwnership(samplerD);
5995 texD->lastActiveFrameSlot = currentFrameSlot;
6001 samplerD->lastActiveFrameSlot = currentFrameSlot;
6002 const quint64 texId = texD ? texD->m_id : 0;
6003 const uint texGen = texD ? texD->generation : 0;
6004 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
6005 const uint samplerGen = samplerD ? samplerD->generation : 0;
6006 if (texGen != bd.stex.d[elem].texGeneration
6007 || texId != bd.stex.d[elem].texId
6008 || samplerGen != bd.stex.d[elem].samplerGeneration
6009 || samplerId != bd.stex.d[elem].samplerId)
6011 rewriteDescSet =
true;
6012 bd.stex.d[elem].texId = texId;
6013 bd.stex.d[elem].texGeneration = texGen;
6014 bd.stex.d[elem].samplerId = samplerId;
6015 bd.stex.d[elem].samplerGeneration = samplerGen;
6020 case QRhiShaderResourceBinding::ImageLoad:
6021 case QRhiShaderResourceBinding::ImageStore:
6022 case QRhiShaderResourceBinding::ImageLoadStore:
6025 sanityCheckResourceOwnership(texD);
6026 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
6027 texD->lastActiveFrameSlot = currentFrameSlot;
6029 if (b->type == QRhiShaderResourceBinding::ImageLoad)
6031 else if (b->type == QRhiShaderResourceBinding::ImageStore)
6036 const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
6037 const auto prevAccess = passResTracker.textures().find(texD);
6038 if (prevAccess != passResTracker.textures().end()) {
6042 addWriteBarrier =
true;
6043 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6044 writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
6052 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
6053 rewriteDescSet =
true;
6054 bd.simage.id = texD->m_id;
6055 bd.simage.generation = texD->generation;
6059 case QRhiShaderResourceBinding::BufferLoad:
6060 case QRhiShaderResourceBinding::BufferStore:
6061 case QRhiShaderResourceBinding::BufferLoadStore:
6064 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
6065 sanityCheckResourceOwnership(bufD);
6067 if (bufD->m_type == QRhiBuffer::Dynamic)
6070 bufD->lastActiveFrameSlot = currentFrameSlot;
6072 if (b->type == QRhiShaderResourceBinding::BufferLoad)
6074 else if (b->type == QRhiShaderResourceBinding::BufferStore)
6079 const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
6080 const auto prevAccess = passResTracker.buffers().find(bufD);
6081 if (prevAccess != passResTracker.buffers().end()) {
6085 addWriteBarrier =
true;
6086 writeBarrierDstStageMask |= toVkPipelineStage(stage);
6087 writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
6090 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
6094 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
6095 rewriteDescSet =
true;
6096 bd.sbuf.id = bufD->m_id;
6097 bd.sbuf.generation = bufD->generation;
6107 if (addWriteBarrier) {
6109 VkMemoryBarrier barrier = {};
6110 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6111 barrier.pNext =
nullptr;
6112 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6113 barrier.srcAccessMask = barrier.dstAccessMask;
6114 df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
6121 cmd.args.memoryBarrier.dependencyFlags = 0;
6122 cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
6123 cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
6124 cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6125 cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
6131 updateShaderResourceBindings(srb);
6135 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot
6136 || !srbD->sortedDynamicOffsetBindingNumbers.isEmpty();
6138 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
6140 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
6141 QVarLengthArray<uint32_t, 4> dynOfs;
6146 for (
int bindingNumber : std::as_const(srbD->sortedDynamicOffsetBindingNumbers)) {
6147 uint32_t offset = 0;
6148 for (
int i = 0; i < dynamicOffsetCount; ++i) {
6149 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
6150 if (bindingOffsetPair.first == bindingNumber) {
6151 offset = bindingOffsetPair.second;
6155 dynOfs.append(offset);
6159 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
6160 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
6161 gfxPsD ? gfxPsD->layout : compPsD->layout,
6162 0, 1, &srbD->descSets[currentFrameSlot],
6163 uint32_t(dynOfs.size()),
6164 dynOfs.size() ? dynOfs.constData() :
nullptr);
6168 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
6169 : VK_PIPELINE_BIND_POINT_COMPUTE;
6170 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
6171 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
6172 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
6173 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
6174 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
6178 cbD->currentGraphicsSrb = srb;
6179 cbD->currentComputeSrb =
nullptr;
6181 cbD->currentGraphicsSrb =
nullptr;
6182 cbD->currentComputeSrb = srb;
6184 cbD->currentSrbGeneration = srbD->generation;
6185 cbD->currentDescSetSlot = currentFrameSlot;
6188 srbD->lastActiveFrameSlot = currentFrameSlot;
6192 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
6193 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
6199 bool needsBindVBuf =
false;
6200 for (
int i = 0; i < bindingCount; ++i) {
6201 const int inputSlot = startBinding + i;
6203 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
6204 bufD->lastActiveFrameSlot = currentFrameSlot;
6205 if (bufD->m_type == QRhiBuffer::Dynamic)
6208 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
6209 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
6210 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
6212 needsBindVBuf =
true;
6213 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
6214 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
6218 if (needsBindVBuf) {
6219 QVarLengthArray<VkBuffer, 4> bufs;
6220 QVarLengthArray<VkDeviceSize, 4> ofs;
6221 for (
int i = 0; i < bindingCount; ++i) {
6223 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6224 bufs.append(bufD->buffers[slot]);
6225 ofs.append(bindings[i].second);
6232 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
6233 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
6237 cmd.args.bindVertexBuffer.startBinding = startBinding;
6238 cmd.args.bindVertexBuffer.count = bufs.size();
6239 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
6240 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
6241 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
6242 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
6248 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
6249 ibufD->lastActiveFrameSlot = currentFrameSlot;
6250 if (ibufD->m_type == QRhiBuffer::Dynamic)
6253 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6254 const VkBuffer vkindexbuf = ibufD->buffers[slot];
6255 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
6256 : VK_INDEX_TYPE_UINT32;
6258 if (cbD->currentIndexBuffer != vkindexbuf
6259 || cbD->currentIndexOffset != indexOffset
6260 || cbD->currentIndexFormat != type)
6262 cbD->currentIndexBuffer = vkindexbuf;
6263 cbD->currentIndexOffset = indexOffset;
6264 cbD->currentIndexFormat = type;
6267 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
6271 cmd.args.bindIndexBuffer.buf = vkindexbuf;
6272 cmd.args.bindIndexBuffer.ofs = indexOffset;
6273 cmd.args.bindIndexBuffer.type = type;
6287 const QSize outputSize = cbD->currentTarget->pixelSize();
6288 std::array<
float, 4> vp = cbD->currentViewport.viewport();
6289 float x = 0, y = 0, w = 0, h = 0;
6291 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
6294 w = outputSize.width();
6295 h = outputSize.height();
6298 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, vp, &x, &y, &w, &h);
6302 VkRect2D *s = &cmd.args.setScissor.scissor;
6303 s->offset.x = int32_t(x);
6304 s->offset.y = int32_t(y);
6305 s->extent.width = uint32_t(w);
6306 s->extent.height = uint32_t(h);
6309 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6310 cbD->commands.unget();
6320 const QSize outputSize = cbD->currentTarget->pixelSize();
6324 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6328 VkViewport *vp = &cmd.args.setViewport.viewport;
6333 vp->minDepth = viewport.minDepth();
6334 vp->maxDepth = viewport.maxDepth();
6337 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6338 cbD->commands.unget();
6343 cbD->currentViewport = viewport;
6344 if (cbD->currentGraphicsPipeline
6345 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
6355 Q_ASSERT(!cbD->currentGraphicsPipeline
6357 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6358 const QSize outputSize = cbD->currentTarget->pixelSize();
6362 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6366 VkRect2D *s = &cmd.args.setScissor.scissor;
6369 s->extent.width = uint32_t(w);
6370 s->extent.height = uint32_t(h);
6373 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6374 cbD->commands.unget();
6388 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6389 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6393 cmd.args.setBlendConstants.c[0] = c.redF();
6394 cmd.args.setBlendConstants.c[1] = c.greenF();
6395 cmd.args.setBlendConstants.c[2] = c.blueF();
6396 cmd.args.setBlendConstants.c[3] = c.alphaF();
6406 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6410 cmd.args.setStencilRef.ref = refValue;
6416#ifdef VK_KHR_fragment_shading_rate
6417 if (!vkCmdSetFragmentShadingRateKHR)
6420 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6421 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6422 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6424 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6425 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6426 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6428 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6429 if (cbD->passUsesSecondaryCb) {
6430 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6432 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6433 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6434 cmd.args.setShadingRate.w = size.width;
6435 cmd.args.setShadingRate.h = size.height;
6437 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6438 cbD->hasShadingRateSet =
true;
6441 Q_UNUSED(coarsePixelSize);
6446 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6452 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6456 cmd.args.draw.vertexCount = vertexCount;
6457 cmd.args.draw.instanceCount = instanceCount;
6458 cmd.args.draw.firstVertex = firstVertex;
6459 cmd.args.draw.firstInstance = firstInstance;
6464 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6470 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6471 firstIndex, vertexOffset, firstInstance);
6475 cmd.args.drawIndexed.indexCount = indexCount;
6476 cmd.args.drawIndexed.instanceCount = instanceCount;
6477 cmd.args.drawIndexed.firstIndex = firstIndex;
6478 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6479 cmd.args.drawIndexed.firstInstance = firstInstance;
6484 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6491 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6492 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6494 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6498 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6501 if (caps.drawIndirectMulti) {
6502 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6503 indirectBufVk, indirectBufferOffset,
6506 VkDeviceSize offset = indirectBufferOffset;
6507 for (quint32 i = 0; i < drawCount; ++i) {
6508 df->vkCmdDrawIndirect(cbD->activeSecondaryCbStack.last(),
6509 indirectBufVk, offset,
6515 if (caps.drawIndirectMulti) {
6518 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6519 cmd.args.drawIndirect.indirectBufferOffset = indirectBufferOffset;
6520 cmd.args.drawIndirect.drawCount = drawCount;
6521 cmd.args.drawIndirect.stride = stride;
6523 VkDeviceSize offset = indirectBufferOffset;
6524 for (quint32 i = 0; i < drawCount; ++i) {
6527 cmd.args.drawIndirect.indirectBuffer = indirectBufVk;
6528 cmd.args.drawIndirect.indirectBufferOffset = offset;
6529 cmd.args.drawIndirect.drawCount = 1;
6530 cmd.args.drawIndirect.stride = stride;
6538 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
6545 indirectBufD->lastActiveFrameSlot = currentFrameSlot;
6546 if (indirectBufD->m_type == QRhiBuffer::Dynamic)
6548 const int indirectBufSlot = indirectBufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
6552 VkBuffer indirectBufVk = indirectBufD->buffers[indirectBufSlot];
6555 if (caps.drawIndirectMulti) {
6556 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6557 indirectBufVk, indirectBufferOffset,
6560 VkDeviceSize offset = indirectBufferOffset;
6561 for (quint32 i = 0; i < drawCount; ++i) {
6562 df->vkCmdDrawIndexedIndirect(cbD->activeSecondaryCbStack.last(),
6563 indirectBufVk, offset,
6569 if (caps.drawIndirectMulti) {
6572 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6573 cmd.args.drawIndexedIndirect.indirectBufferOffset = indirectBufferOffset;
6574 cmd.args.drawIndexedIndirect.drawCount = drawCount;
6575 cmd.args.drawIndexedIndirect.stride = stride;
6577 VkDeviceSize offset = indirectBufferOffset;
6578 for (quint32 i = 0; i < drawCount; ++i) {
6581 cmd.args.drawIndexedIndirect.indirectBuffer = indirectBufVk;
6582 cmd.args.drawIndexedIndirect.indirectBufferOffset = offset;
6583 cmd.args.drawIndexedIndirect.drawCount = 1;
6584 cmd.args.drawIndexedIndirect.stride = stride;
6593#ifdef VK_EXT_debug_utils
6594 if (!debugMarkers || !caps.debugUtils)
6597 VkDebugUtilsLabelEXT label = {};
6598 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6600 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6601 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6602 label.pLabelName = name.constData();
6603 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6605 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6606 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6607 cmd.args.debugMarkerBegin.label = label;
6608 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6609 cbD->pools.debugMarkerData.append(name);
6619#ifdef VK_EXT_debug_utils
6620 if (!debugMarkers || !caps.debugUtils)
6623 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6624 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6625 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6627 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6628 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6637#ifdef VK_EXT_debug_utils
6638 if (!debugMarkers || !caps.debugUtils)
6641 VkDebugUtilsLabelEXT label = {};
6642 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6644 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6645 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6646 label.pLabelName = msg.constData();
6647 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6649 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6650 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6651 cmd.args.debugMarkerInsert.label = label;
6652 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6653 cbD->pools.debugMarkerData.append(msg);
6663 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6668 Q_ASSERT(cbD->currentTarget);
6671 switch (cbD->currentTarget->resourceType()) {
6672 case QRhiResource::SwapChainRenderTarget:
6675 case QRhiResource::TextureRenderTarget:
6707 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6708 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6712 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6713 cbD->activeSecondaryCbStack.removeLast();
6714 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6716 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6718 cbD->activeSecondaryCbStack.append(extCb);
6730 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6731 cbD->activeSecondaryCbStack.removeLast();
6732 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6733 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6747 if (!debugMarkers || name.isEmpty())
6750 QByteArray decoratedName = name;
6752 decoratedName +=
'/';
6753 decoratedName += QByteArray::number(slot);
6755 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6760#ifdef VK_EXT_debug_utils
6761 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6764 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6765 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6766 nameInfo.objectType = type;
6767 nameInfo.objectHandle = object;
6768 QByteArray decoratedName = name;
6770 decoratedName +=
'/';
6771 decoratedName += QByteArray::number(slot);
6773 nameInfo.pObjectName = decoratedName.constData();
6774 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6786 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6787 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6788 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6789 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6790 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6791 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6792 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6793 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6794 if (usage.testFlag(QRhiBuffer::IndirectBuffer))
6795 u |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
6796 return VkBufferUsageFlagBits(u);
6802 case QRhiSampler::Nearest:
6803 return VK_FILTER_NEAREST;
6804 case QRhiSampler::Linear:
6805 return VK_FILTER_LINEAR;
6807 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6814 case QRhiSampler::None:
6815 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6816 case QRhiSampler::Nearest:
6817 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6818 case QRhiSampler::Linear:
6819 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6821 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6828 case QRhiSampler::Repeat:
6829 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6830 case QRhiSampler::ClampToEdge:
6831 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6832 case QRhiSampler::Mirror:
6833 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6835 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6842 case QRhiShaderStage::Vertex:
6843 return VK_SHADER_STAGE_VERTEX_BIT;
6844 case QRhiShaderStage::TessellationControl:
6845 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6846 case QRhiShaderStage::TessellationEvaluation:
6847 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6848 case QRhiShaderStage::Fragment:
6849 return VK_SHADER_STAGE_FRAGMENT_BIT;
6850 case QRhiShaderStage::Compute:
6851 return VK_SHADER_STAGE_COMPUTE_BIT;
6852 case QRhiShaderStage::Geometry:
6853 return VK_SHADER_STAGE_GEOMETRY_BIT;
6855 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6862 case QRhiVertexInputAttribute::Float4:
6863 return VK_FORMAT_R32G32B32A32_SFLOAT;
6864 case QRhiVertexInputAttribute::Float3:
6865 return VK_FORMAT_R32G32B32_SFLOAT;
6866 case QRhiVertexInputAttribute::Float2:
6867 return VK_FORMAT_R32G32_SFLOAT;
6868 case QRhiVertexInputAttribute::Float:
6869 return VK_FORMAT_R32_SFLOAT;
6870 case QRhiVertexInputAttribute::UNormByte4:
6871 return VK_FORMAT_R8G8B8A8_UNORM;
6872 case QRhiVertexInputAttribute::UNormByte2:
6873 return VK_FORMAT_R8G8_UNORM;
6874 case QRhiVertexInputAttribute::UNormByte:
6875 return VK_FORMAT_R8_UNORM;
6876 case QRhiVertexInputAttribute::UInt4:
6877 return VK_FORMAT_R32G32B32A32_UINT;
6878 case QRhiVertexInputAttribute::UInt3:
6879 return VK_FORMAT_R32G32B32_UINT;
6880 case QRhiVertexInputAttribute::UInt2:
6881 return VK_FORMAT_R32G32_UINT;
6882 case QRhiVertexInputAttribute::UInt:
6883 return VK_FORMAT_R32_UINT;
6884 case QRhiVertexInputAttribute::SInt4:
6885 return VK_FORMAT_R32G32B32A32_SINT;
6886 case QRhiVertexInputAttribute::SInt3:
6887 return VK_FORMAT_R32G32B32_SINT;
6888 case QRhiVertexInputAttribute::SInt2:
6889 return VK_FORMAT_R32G32_SINT;
6890 case QRhiVertexInputAttribute::SInt:
6891 return VK_FORMAT_R32_SINT;
6892 case QRhiVertexInputAttribute::Half4:
6893 return VK_FORMAT_R16G16B16A16_SFLOAT;
6894 case QRhiVertexInputAttribute::Half3:
6895 return VK_FORMAT_R16G16B16_SFLOAT;
6896 case QRhiVertexInputAttribute::Half2:
6897 return VK_FORMAT_R16G16_SFLOAT;
6898 case QRhiVertexInputAttribute::Half:
6899 return VK_FORMAT_R16_SFLOAT;
6900 case QRhiVertexInputAttribute::UShort4:
6901 return VK_FORMAT_R16G16B16A16_UINT;
6902 case QRhiVertexInputAttribute::UShort3:
6903 return VK_FORMAT_R16G16B16_UINT;
6904 case QRhiVertexInputAttribute::UShort2:
6905 return VK_FORMAT_R16G16_UINT;
6906 case QRhiVertexInputAttribute::UShort:
6907 return VK_FORMAT_R16_UINT;
6908 case QRhiVertexInputAttribute::SShort4:
6909 return VK_FORMAT_R16G16B16A16_SINT;
6910 case QRhiVertexInputAttribute::SShort3:
6911 return VK_FORMAT_R16G16B16_SINT;
6912 case QRhiVertexInputAttribute::SShort2:
6913 return VK_FORMAT_R16G16_SINT;
6914 case QRhiVertexInputAttribute::SShort:
6915 return VK_FORMAT_R16_SINT;
6917 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6924 case QRhiGraphicsPipeline::Triangles:
6925 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6926 case QRhiGraphicsPipeline::TriangleStrip:
6927 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6928 case QRhiGraphicsPipeline::TriangleFan:
6929 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6930 case QRhiGraphicsPipeline::Lines:
6931 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6932 case QRhiGraphicsPipeline::LineStrip:
6933 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6934 case QRhiGraphicsPipeline::Points:
6935 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6936 case QRhiGraphicsPipeline::Patches:
6937 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6939 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6946 case QRhiGraphicsPipeline::None:
6947 return VK_CULL_MODE_NONE;
6948 case QRhiGraphicsPipeline::Front:
6949 return VK_CULL_MODE_FRONT_BIT;
6950 case QRhiGraphicsPipeline::Back:
6951 return VK_CULL_MODE_BACK_BIT;
6953 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6960 case QRhiGraphicsPipeline::CCW:
6961 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6962 case QRhiGraphicsPipeline::CW:
6963 return VK_FRONT_FACE_CLOCKWISE;
6965 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6972 if (c.testFlag(QRhiGraphicsPipeline::R))
6973 f |= VK_COLOR_COMPONENT_R_BIT;
6974 if (c.testFlag(QRhiGraphicsPipeline::G))
6975 f |= VK_COLOR_COMPONENT_G_BIT;
6976 if (c.testFlag(QRhiGraphicsPipeline::B))
6977 f |= VK_COLOR_COMPONENT_B_BIT;
6978 if (c.testFlag(QRhiGraphicsPipeline::A))
6979 f |= VK_COLOR_COMPONENT_A_BIT;
6980 return VkColorComponentFlags(f);
6986 case QRhiGraphicsPipeline::Zero:
6987 return VK_BLEND_FACTOR_ZERO;
6988 case QRhiGraphicsPipeline::One:
6989 return VK_BLEND_FACTOR_ONE;
6990 case QRhiGraphicsPipeline::SrcColor:
6991 return VK_BLEND_FACTOR_SRC_COLOR;
6992 case QRhiGraphicsPipeline::OneMinusSrcColor:
6993 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6994 case QRhiGraphicsPipeline::DstColor:
6995 return VK_BLEND_FACTOR_DST_COLOR;
6996 case QRhiGraphicsPipeline::OneMinusDstColor:
6997 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6998 case QRhiGraphicsPipeline::SrcAlpha:
6999 return VK_BLEND_FACTOR_SRC_ALPHA;
7000 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7001 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
7002 case QRhiGraphicsPipeline::DstAlpha:
7003 return VK_BLEND_FACTOR_DST_ALPHA;
7004 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7005 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
7006 case QRhiGraphicsPipeline::ConstantColor:
7007 return VK_BLEND_FACTOR_CONSTANT_COLOR;
7008 case QRhiGraphicsPipeline::OneMinusConstantColor:
7009 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
7010 case QRhiGraphicsPipeline::ConstantAlpha:
7011 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
7012 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7013 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
7014 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7015 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
7016 case QRhiGraphicsPipeline::Src1Color:
7017 return VK_BLEND_FACTOR_SRC1_COLOR;
7018 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7019 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
7020 case QRhiGraphicsPipeline::Src1Alpha:
7021 return VK_BLEND_FACTOR_SRC1_ALPHA;
7022 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7023 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
7025 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
7032 case QRhiGraphicsPipeline::Add:
7033 return VK_BLEND_OP_ADD;
7034 case QRhiGraphicsPipeline::Subtract:
7035 return VK_BLEND_OP_SUBTRACT;
7036 case QRhiGraphicsPipeline::ReverseSubtract:
7037 return VK_BLEND_OP_REVERSE_SUBTRACT;
7038 case QRhiGraphicsPipeline::Min:
7039 return VK_BLEND_OP_MIN;
7040 case QRhiGraphicsPipeline::Max:
7041 return VK_BLEND_OP_MAX;
7043 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
7050 case QRhiGraphicsPipeline::Never:
7051 return VK_COMPARE_OP_NEVER;
7052 case QRhiGraphicsPipeline::Less:
7053 return VK_COMPARE_OP_LESS;
7054 case QRhiGraphicsPipeline::Equal:
7055 return VK_COMPARE_OP_EQUAL;
7056 case QRhiGraphicsPipeline::LessOrEqual:
7057 return VK_COMPARE_OP_LESS_OR_EQUAL;
7058 case QRhiGraphicsPipeline::Greater:
7059 return VK_COMPARE_OP_GREATER;
7060 case QRhiGraphicsPipeline::NotEqual:
7061 return VK_COMPARE_OP_NOT_EQUAL;
7062 case QRhiGraphicsPipeline::GreaterOrEqual:
7063 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7064 case QRhiGraphicsPipeline::Always:
7065 return VK_COMPARE_OP_ALWAYS;
7067 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
7074 case QRhiGraphicsPipeline::StencilZero:
7075 return VK_STENCIL_OP_ZERO;
7076 case QRhiGraphicsPipeline::Keep:
7077 return VK_STENCIL_OP_KEEP;
7078 case QRhiGraphicsPipeline::Replace:
7079 return VK_STENCIL_OP_REPLACE;
7080 case QRhiGraphicsPipeline::IncrementAndClamp:
7081 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
7082 case QRhiGraphicsPipeline::DecrementAndClamp:
7083 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
7084 case QRhiGraphicsPipeline::Invert:
7085 return VK_STENCIL_OP_INVERT;
7086 case QRhiGraphicsPipeline::IncrementAndWrap:
7087 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
7088 case QRhiGraphicsPipeline::DecrementAndWrap:
7089 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
7091 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
7098 case QRhiGraphicsPipeline::Fill:
7099 return VK_POLYGON_MODE_FILL;
7100 case QRhiGraphicsPipeline::Line:
7101 return VK_POLYGON_MODE_LINE;
7103 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
7109 dst->failOp = toVkStencilOp(src.failOp);
7110 dst->passOp = toVkStencilOp(src.passOp);
7111 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
7112 dst->compareOp = toVkCompareOp(src.compareOp);
7118 case QRhiShaderResourceBinding::UniformBuffer:
7119 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
7120 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
7122 case QRhiShaderResourceBinding::SampledTexture:
7123 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
7125 case QRhiShaderResourceBinding::Texture:
7126 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
7128 case QRhiShaderResourceBinding::Sampler:
7129 return VK_DESCRIPTOR_TYPE_SAMPLER;
7131 case QRhiShaderResourceBinding::ImageLoad:
7132 case QRhiShaderResourceBinding::ImageStore:
7133 case QRhiShaderResourceBinding::ImageLoadStore:
7134 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
7136 case QRhiShaderResourceBinding::BufferLoad:
7137 case QRhiShaderResourceBinding::BufferStore:
7138 case QRhiShaderResourceBinding::BufferLoadStore:
7139 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
7142 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
7149 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
7150 s |= VK_SHADER_STAGE_VERTEX_BIT;
7151 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
7152 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
7153 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
7154 s |= VK_SHADER_STAGE_COMPUTE_BIT;
7155 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
7156 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
7157 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
7158 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
7159 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
7160 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
7161 return VkShaderStageFlags(s);
7167 case QRhiSampler::Never:
7168 return VK_COMPARE_OP_NEVER;
7169 case QRhiSampler::Less:
7170 return VK_COMPARE_OP_LESS;
7171 case QRhiSampler::Equal:
7172 return VK_COMPARE_OP_EQUAL;
7173 case QRhiSampler::LessOrEqual:
7174 return VK_COMPARE_OP_LESS_OR_EQUAL;
7175 case QRhiSampler::Greater:
7176 return VK_COMPARE_OP_GREATER;
7177 case QRhiSampler::NotEqual:
7178 return VK_COMPARE_OP_NOT_EQUAL;
7179 case QRhiSampler::GreaterOrEqual:
7180 return VK_COMPARE_OP_GREATER_OR_EQUAL;
7181 case QRhiSampler::Always:
7182 return VK_COMPARE_OP_ALWAYS;
7184 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
7192 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
7212 e.buffer.buffers[i] = buffers[i];
7214 e.buffer.stagingBuffers[i] = stagingBuffers[i];
7217 buffers[i] = VK_NULL_HANDLE;
7219 stagingBuffers[i] = VK_NULL_HANDLE;
7221 pendingDynamicUpdates[i].clear();
7229 rhiD->releaseQueue.append(e);
7230 rhiD->unregisterResource(
this);
7239 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
7240 qWarning(
"StorageBuffer cannot be combined with Dynamic");
7244 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
7246 VkBufferCreateInfo bufferInfo = {};
7247 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
7248 bufferInfo.size = nonZeroSize;
7249 bufferInfo.usage = toVkBufferUsage(m_usage);
7251 VmaAllocationCreateInfo allocInfo = {};
7253 if (m_type == Dynamic) {
7258 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
7261 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
7263 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7264 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7268 VkResult err = VK_SUCCESS;
7270 buffers[i] = VK_NULL_HANDLE;
7272 usageState[i].access = usageState[i].stage = 0;
7273 if (i == 0 || m_type == Dynamic) {
7274 VmaAllocation allocation;
7275 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
7276 if (err != VK_SUCCESS)
7279 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
7280 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
7281 m_type == Dynamic ? i : -1);
7285 if (err != VK_SUCCESS) {
7286 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
7287 rhiD->printExtraErrorInfo(err);
7293 rhiD->registerResource(
this);
7299 if (m_type == Dynamic) {
7305 b.objects[i] = &buffers[i];
7310 return { { &buffers[0] }, 1 };
7320 Q_ASSERT(m_type == Dynamic);
7322 Q_ASSERT(rhiD->inFrame);
7323 const int slot = rhiD->currentFrameSlot;
7325 VmaAllocation a = toVmaAllocation(allocations[slot]);
7326 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
7327 if (err != VK_SUCCESS) {
7328 qWarning(
"Failed to map buffer: %d", err);
7331 return static_cast<
char *>(p);
7337 const int slot = rhiD->currentFrameSlot;
7338 VmaAllocation a = toVmaAllocation(allocations[slot]);
7339 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
7340 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
7344 int sampleCount, Flags flags,
7345 QRhiTexture::Format backingFormatHint)
7358 if (!memory && !backingTexture)
7365 e.renderBuffer.memory = memory;
7366 e.renderBuffer.image = image;
7367 e.renderBuffer.imageView = imageView;
7369 memory = VK_NULL_HANDLE;
7370 image = VK_NULL_HANDLE;
7371 imageView = VK_NULL_HANDLE;
7381 rhiD->releaseQueue.append(e);
7382 rhiD->unregisterResource(
this);
7388 if (memory || backingTexture)
7391 if (m_pixelSize.isEmpty())
7395 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7398 case QRhiRenderBuffer::Color:
7406 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
7414 vkformat = backingTexture->vkformat;
7417 case QRhiRenderBuffer::DepthStencil:
7418 vkformat = rhiD->optimalDepthStencilFormat();
7419 if (!rhiD->createTransientImage(vkformat,
7421 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
7422 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7431 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7440 rhiD->registerResource(
this);
7446 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7447 return m_backingFormatHint;
7449 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7453 int arraySize,
int sampleCount, Flags flags)
7457 stagingBuffers[i] = VK_NULL_HANDLE;
7460 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7461 perLevelImageViews[i] = VK_NULL_HANDLE;
7478 e.texture.image = owns ? image : VK_NULL_HANDLE;
7479 e.texture.imageView = imageView;
7483 e.texture.stagingBuffers[i] = stagingBuffers[i];
7486 stagingBuffers[i] = VK_NULL_HANDLE;
7490 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7491 e.texture.extraImageViews[i] = perLevelImageViews[i];
7492 perLevelImageViews[i] = VK_NULL_HANDLE;
7495 image = VK_NULL_HANDLE;
7496 imageView = VK_NULL_HANDLE;
7501 rhiD->releaseQueue.append(e);
7502 rhiD->unregisterResource(
this);
7512 vkformat = toVkTextureFormat(m_format, m_flags);
7513 if (m_writeViewFormat.format != UnknownFormat)
7514 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7516 viewFormat = vkformat;
7517 if (m_readViewFormat.format != UnknownFormat)
7518 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7520 viewFormatForSampling = vkformat;
7522 VkFormatProperties props;
7523 rhiD
->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7524 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7525 if (!canSampleOptimal) {
7526 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7530 const bool isCube = m_flags.testFlag(CubeMap);
7531 const bool isArray = m_flags.testFlag(TextureArray);
7532 const bool is3D = m_flags.testFlag(ThreeDimensional);
7533 const bool is1D = m_flags.testFlag(OneDimensional);
7534 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7536 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7537 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7539 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7540 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7541 if (mipLevelCount > maxLevels) {
7542 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7543 mipLevelCount = maxLevels;
7545 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7546 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7548 qWarning(
"Cubemap texture cannot be multisample");
7552 qWarning(
"3D texture cannot be multisample");
7556 qWarning(
"Multisample texture cannot have mipmaps");
7560 if (isCube && is3D) {
7561 qWarning(
"Texture cannot be both cube and 3D");
7564 if (isArray && is3D) {
7565 qWarning(
"Texture cannot be both array and 3D");
7568 if (isCube && is1D) {
7569 qWarning(
"Texture cannot be both cube and 1D");
7573 qWarning(
"Texture cannot be both 1D and 3D");
7576 if (m_depth > 1 && !is3D) {
7577 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7580 if (m_arraySize > 0 && !isArray) {
7581 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7584 if (m_arraySize < 1 && isArray) {
7585 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7589 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7590 usageState.access = 0;
7591 usageState.stage = 0;
7594 *adjustedSize = size;
7603 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7604 const bool isCube = m_flags.testFlag(CubeMap);
7605 const bool isArray = m_flags.testFlag(TextureArray);
7606 const bool is3D = m_flags.testFlag(ThreeDimensional);
7607 const bool is1D = m_flags.testFlag(OneDimensional);
7609 VkImageViewCreateInfo viewInfo = {};
7610 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7611 viewInfo.image = image;
7612 viewInfo.viewType = isCube
7613 ? VK_IMAGE_VIEW_TYPE_CUBE
7614 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7615 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7616 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7617 viewInfo.format = viewFormatForSampling;
7618 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7619 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7620 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7621 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7622 viewInfo.subresourceRange.aspectMask = aspectMask;
7625 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7626 viewInfo.subresourceRange.levelCount = mipLevelCount;
7627 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7628 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7629 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7631 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7634 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7635 if (err != VK_SUCCESS) {
7636 qWarning(
"Failed to create image view: %d", err);
7649 if (!prepareCreate(&size))
7653 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7654 const bool isDepth = isDepthTextureFormat(m_format);
7655 const bool isCube = m_flags.testFlag(CubeMap);
7656 const bool isArray = m_flags.testFlag(TextureArray);
7657 const bool is3D = m_flags.testFlag(ThreeDimensional);
7658 const bool is1D = m_flags.testFlag(OneDimensional);
7660 VkImageCreateInfo imageInfo = {};
7661 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7662 imageInfo.flags = 0;
7664 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7666 if (is3D && isRenderTarget) {
7672 if (!rhiD->caps.texture3DSliceAs2D)
7673 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7674#ifdef VK_VERSION_1_1
7675 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7677 imageInfo.flags |= 0x00000020;
7681 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7682 imageInfo.format = vkformat;
7683 imageInfo.extent.width = uint32_t(size.width());
7684 imageInfo.extent.height = uint32_t(size.height());
7685 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7686 imageInfo.mipLevels = mipLevelCount;
7687 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7688 imageInfo.samples = samples;
7689 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7690 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7692 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7693 if (isRenderTarget) {
7695 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7697 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7699 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7700 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7701 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7702 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7703 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7704 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7705#ifdef VK_KHR_fragment_shading_rate
7706 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7707 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7710 VmaAllocationCreateInfo allocInfo = {};
7711 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7713 VmaAllocation allocation;
7714 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7715 if (err != VK_SUCCESS) {
7716 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7717 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7718 int(imageInfo.format),
7719 imageInfo.mipLevels,
7720 imageInfo.arrayLayers,
7721 int(imageInfo.samples),
7723 rhiD->printExtraErrorInfo(err);
7727 rhiD->setAllocationName(allocation, m_objectName);
7732 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7735 rhiD->registerResource(
this);
7741 VkImage img = VkImage(src.object);
7745 if (!prepareCreate())
7753 usageState.layout = VkImageLayout(src.layout);
7757 rhiD->registerResource(
this);
7763 return {quint64(image), usageState.layout};
7768 usageState.layout = VkImageLayout(layout);
7773 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7774 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7775 return perLevelImageViews[level];
7777 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7778 const bool isCube = m_flags.testFlag(CubeMap);
7779 const bool isArray = m_flags.testFlag(TextureArray);
7780 const bool is3D = m_flags.testFlag(ThreeDimensional);
7781 const bool is1D = m_flags.testFlag(OneDimensional);
7783 VkImageViewCreateInfo viewInfo = {};
7784 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7785 viewInfo.image = image;
7786 viewInfo.viewType = isCube
7787 ? VK_IMAGE_VIEW_TYPE_CUBE
7788 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7789 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7790 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7791 viewInfo.format = viewFormat;
7792 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7793 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7794 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7795 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7796 viewInfo.subresourceRange.aspectMask = aspectMask;
7797 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7798 viewInfo.subresourceRange.levelCount = 1;
7799 viewInfo.subresourceRange.baseArrayLayer = 0;
7800 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7802 VkImageView v = VK_NULL_HANDLE;
7804 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7805 if (err != VK_SUCCESS) {
7806 qWarning(
"Failed to create image view: %d", err);
7807 return VK_NULL_HANDLE;
7810 perLevelImageViews[level] = v;
7815 AddressMode u, AddressMode v, AddressMode w)
7834 e.sampler.sampler = sampler;
7835 sampler = VK_NULL_HANDLE;
7839 rhiD->releaseQueue.append(e);
7840 rhiD->unregisterResource(
this);
7849 VkSamplerCreateInfo samplerInfo = {};
7850 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7851 samplerInfo.magFilter = toVkFilter(m_magFilter);
7852 samplerInfo.minFilter = toVkFilter(m_minFilter);
7853 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7854 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7855 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7856 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7857 samplerInfo.maxAnisotropy = 1.0f;
7858 samplerInfo.compareEnable = m_compareOp != Never;
7859 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7860 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7863 VkResult err = rhiD
->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7864 if (err != VK_SUCCESS) {
7865 qWarning(
"Failed to create sampler: %d", err);
7871 rhiD->registerResource(
this);
7878 serializedFormatData.reserve(64);
7892 rp = VK_NULL_HANDLE;
7900 e.renderPass.rp = rp;
7902 rp = VK_NULL_HANDLE;
7906 rhiD->releaseQueue.append(e);
7907 rhiD->unregisterResource(
this);
7913 return a.format == b.format
7914 && a.samples == b.samples
7915 && a.loadOp == b.loadOp
7916 && a.storeOp == b.storeOp
7917 && a.stencilLoadOp == b.stencilLoadOp
7918 && a.stencilStoreOp == b.stencilStoreOp
7919 && a.initialLayout == b.initialLayout
7920 && a.finalLayout == b.finalLayout;
7933 if (attDescs.size() != o->attDescs.size())
7935 if (colorRefs.size() != o->colorRefs.size())
7937 if (resolveRefs.size() != o->resolveRefs.size())
7943 if (multiViewCount != o->multiViewCount)
7948 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7949 const uint32_t attIdx = colorRefs[i].attachment;
7950 if (attIdx != o->colorRefs[i].attachment)
7952 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7957 const uint32_t attIdx = dsRef.attachment;
7958 if (attIdx != o->dsRef.attachment)
7960 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7964 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7965 const uint32_t attIdx = resolveRefs[i].attachment;
7966 if (attIdx != o->resolveRefs[i].attachment)
7968 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7973 const uint32_t attIdx = dsResolveRef.attachment;
7974 if (attIdx != o->dsResolveRef.attachment)
7976 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7981 const uint32_t attIdx = shadingRateRef.attachment;
7982 if (attIdx != o->shadingRateRef.attachment)
7984 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7995 serializedFormatData.clear();
7996 auto p =
std::back_inserter(serializedFormatData);
7998 *p++ = attDescs.size();
7999 *p++ = colorRefs.size();
8000 *p++ = resolveRefs.size();
8004 *p++ = multiViewCount;
8006 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
8007 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
8008 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
8009 *p++ = used ? a->format : 0;
8010 *p++ = used ? a->samples : 0;
8011 *p++ = used ? a->loadOp : 0;
8012 *p++ = used ? a->storeOp : 0;
8013 *p++ = used ? a->stencilLoadOp : 0;
8014 *p++ = used ? a->stencilStoreOp : 0;
8015 *p++ = used ? a->initialLayout : 0;
8016 *p++ = used ? a->finalLayout : 0;
8019 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
8020 const uint32_t attIdx = colorRefs[i].attachment;
8022 serializeAttachmentData(attIdx);
8026 const uint32_t attIdx = dsRef.attachment;
8028 serializeAttachmentData(attIdx);
8031 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
8032 const uint32_t attIdx = resolveRefs[i].attachment;
8034 serializeAttachmentData(attIdx);
8038 const uint32_t attIdx = dsResolveRef.attachment;
8040 serializeAttachmentData(attIdx);
8044 const uint32_t attIdx = shadingRateRef.attachment;
8046 serializeAttachmentData(attIdx);
8055 rpD->attDescs = attDescs;
8056 rpD->colorRefs = colorRefs;
8057 rpD->resolveRefs = resolveRefs;
8058 rpD->subpassDeps = subpassDeps;
8062 rpD->multiViewCount = multiViewCount;
8064 rpD->dsResolveRef = dsResolveRef;
8065 rpD->shadingRateRef = shadingRateRef;
8067 VkRenderPassCreateInfo rpInfo;
8068 VkSubpassDescription subpassDesc;
8069 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
8073 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
8078#ifdef VK_KHR_create_renderpass2
8079 if (rhiD->caps.renderPass2KHR) {
8081 VkRenderPassCreateInfo2KHR rpInfo2;
8082 RenderPass2SetupHelper rp2Helper(rhiD);
8083 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
8087 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
8088 if (err != VK_SUCCESS) {
8089 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
8096 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
8097 if (err != VK_SUCCESS) {
8098 qWarning(
"Failed to create renderpass: %d", err);
8105 rhiD->registerResource(rpD);
8111 return serializedFormatData;
8116 nativeHandlesStruct.renderPass = rp;
8117 return &nativeHandlesStruct;
8143 texture =
QRHI_RES(QVkTexture, src);
8175 return d.sampleCount;
8179 const QRhiTextureRenderTargetDescription &desc,
8184 rtv[att] = VK_NULL_HANDLE;
8185 resrtv[att] = VK_NULL_HANDLE;
8203 e.textureRenderTarget.fb = d.fb;
8204 d.fb = VK_NULL_HANDLE;
8207 e.textureRenderTarget.rtv[att] = rtv[att];
8208 e.textureRenderTarget.resrtv[att] = resrtv[att];
8209 rtv[att] = VK_NULL_HANDLE;
8210 resrtv[att] = VK_NULL_HANDLE;
8213 e.textureRenderTarget.dsv = dsv;
8214 dsv = VK_NULL_HANDLE;
8215 e.textureRenderTarget.resdsv = resdsv;
8216 resdsv = VK_NULL_HANDLE;
8218 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
8219 shadingRateMapView = VK_NULL_HANDLE;
8223 rhiD->releaseQueue.append(e);
8224 rhiD->unregisterResource(
this);
8234 if (!rhiD->createOffscreenRenderPass(rp,
8235 m_desc.cbeginColorAttachments(),
8236 m_desc.cendColorAttachments(),
8237 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
8238 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
8239 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
8240 m_desc.depthStencilBuffer(),
8241 m_desc.depthTexture(),
8242 m_desc.depthResolveTexture(),
8243 m_desc.depthLayer(),
8244 m_desc.shadingRateMap()))
8252 rhiD->registerResource(rp);
8261 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
8262 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
8263 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
8266 QVarLengthArray<VkImageView, 8> views;
8267 d.multiViewCount = 0;
8269 d.colorAttCount = 0;
8271 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8272 d.colorAttCount += 1;
8275 Q_ASSERT(texD || rbD);
8277 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
8278 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
8279 const bool isMultiView = it->multiViewCount() >= 2;
8280 if (isMultiView && d.multiViewCount == 0)
8281 d.multiViewCount = it->multiViewCount();
8282 VkImageViewCreateInfo viewInfo = {};
8283 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8284 viewInfo.image = texD->image;
8285 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
8286 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8287 : VK_IMAGE_VIEW_TYPE_2D);
8288 viewInfo.format = texD->viewFormat;
8289 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8290 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8291 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8292 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8293 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8294 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
8295 viewInfo.subresourceRange.levelCount = 1;
8296 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
8297 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
8298 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
8299 if (err != VK_SUCCESS) {
8300 qWarning(
"Failed to create render target image view: %d", err);
8303 views.append(rtv[attIndex]);
8304 if (attIndex == 0) {
8305 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
8306 d.sampleCount = texD->samples;
8311 if (attIndex == 0) {
8312 d.pixelSize = rbD->pixelSize();
8313 d.sampleCount = rbD->samples;
8319 if (hasDepthStencil) {
8320 if (m_desc.depthTexture()) {
8323 VkImageViewCreateInfo viewInfo = {};
8324 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8325 viewInfo.image = depthTexD->image;
8326 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
8327 viewInfo.format = depthTexD->viewFormat;
8328 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8329 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8330 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8331 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8332 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
8333 viewInfo.subresourceRange.levelCount = 1;
8334 if (m_desc.depthLayer() >= 0 && depthTexD->arraySize() >= 2) {
8335 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_desc.depthLayer());
8336 viewInfo.subresourceRange.layerCount = 1;
8339 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8340 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
8341 if (err != VK_SUCCESS) {
8342 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
8346 if (d.colorAttCount == 0) {
8347 d.pixelSize = depthTexD->pixelSize();
8348 d.sampleCount = depthTexD->samples;
8352 views.append(depthRbD->imageView);
8353 if (d.colorAttCount == 0) {
8354 d.pixelSize = depthRbD->pixelSize();
8355 d.sampleCount = depthRbD->samples;
8363 d.resolveAttCount = 0;
8365 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
8366 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
8367 if (it->resolveTexture()) {
8369 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8370 d.resolveAttCount += 1;
8372 VkImageViewCreateInfo viewInfo = {};
8373 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8374 viewInfo.image = resTexD->image;
8375 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8376 : VK_IMAGE_VIEW_TYPE_2D;
8377 viewInfo.format = resTexD->viewFormat;
8378 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8379 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8380 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8381 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8382 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8383 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
8384 viewInfo.subresourceRange.levelCount = 1;
8385 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
8386 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8387 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
8388 if (err != VK_SUCCESS) {
8389 qWarning(
"Failed to create render target resolve image view: %d", err);
8392 views.append(resrtv[attIndex]);
8396 if (m_desc.depthResolveTexture()) {
8398 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
8400 VkImageViewCreateInfo viewInfo = {};
8401 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8402 viewInfo.image = resTexD->image;
8403 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8404 : VK_IMAGE_VIEW_TYPE_2D;
8405 viewInfo.format = resTexD->viewFormat;
8406 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8407 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8408 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8409 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8410 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
8411 viewInfo.subresourceRange.baseMipLevel = 0;
8412 viewInfo.subresourceRange.levelCount = 1;
8413 viewInfo.subresourceRange.baseArrayLayer = 0;
8414 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8415 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
8416 if (err != VK_SUCCESS) {
8417 qWarning(
"Failed to create render target depth resolve image view: %d", err);
8420 views.append(resdsv);
8421 d.dsResolveAttCount = 1;
8423 d.dsResolveAttCount = 0;
8426 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
8428 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8430 VkImageViewCreateInfo viewInfo = {};
8431 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8432 viewInfo.image = texD->image;
8433 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8434 : VK_IMAGE_VIEW_TYPE_2D;
8435 viewInfo.format = texD->viewFormat;
8436 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8437 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8438 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8439 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8440 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8441 viewInfo.subresourceRange.baseMipLevel = 0;
8442 viewInfo.subresourceRange.levelCount = 1;
8443 viewInfo.subresourceRange.baseArrayLayer = 0;
8444 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8445 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8446 if (err != VK_SUCCESS) {
8447 qWarning(
"Failed to create render target shading rate map view: %d", err);
8450 views.append(shadingRateMapView);
8451 d.shadingRateAttCount = 1;
8453 d.shadingRateAttCount = 0;
8456 if (!m_renderPassDesc)
8457 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8459 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8460 Q_ASSERT(d.rp && d.rp->rp);
8462 VkFramebufferCreateInfo fbInfo = {};
8463 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8464 fbInfo.renderPass = d.rp->rp;
8465 fbInfo.attachmentCount = uint32_t(views.count());
8466 fbInfo.pAttachments = views.constData();
8467 fbInfo.width = uint32_t(d.pixelSize.width());
8468 fbInfo.height = uint32_t(d.pixelSize.height());
8471 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8472 if (err != VK_SUCCESS) {
8473 qWarning(
"Failed to create framebuffer: %d", err);
8477 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8480 rhiD->registerResource(
this);
8486 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8499 return d.sampleCount;
8517 sortedBindings.clear();
8518 sortedDynamicOffsetBindingNumbers.clear();
8524 e.shaderResourceBindings.poolIndex =
poolIndex;
8525 e.shaderResourceBindings.layout = layout;
8528 layout = VK_NULL_HANDLE;
8529 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8530 descSets[i] = VK_NULL_HANDLE;
8534 rhiD->releaseQueue.append(e);
8535 rhiD->unregisterResource(
this);
8545 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8548 rhiD->updateLayoutDesc(
this);
8550 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8551 descSets[i] = VK_NULL_HANDLE;
8553 sortedBindings.clear();
8554 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8555 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8557 sortedDynamicOffsetBindingNumbers.clear();
8558 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8559 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8560 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8561 if (b->u.ubuf.hasDynamicOffset)
8562 sortedDynamicOffsetBindingNumbers.append(b->binding);
8566 QVarLengthArray<VkDescriptorSetLayoutBinding, BINDING_PREALLOC> vkbindings;
8567 vkbindings.reserve(sortedBindings.size());
8568 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8569 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8570 VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back();
8571 vkbinding.binding = uint32_t(b->binding);
8572 vkbinding.descriptorType = toVkDescriptorType(b);
8573 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8574 vkbinding.descriptorCount = b->u.stex.count;
8576 vkbinding.descriptorCount = 1;
8577 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8580 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8581 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8582 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8583 layoutInfo.pBindings = vkbindings.constData();
8585 VkResult err = rhiD
->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8586 if (err != VK_SUCCESS) {
8587 qWarning(
"Failed to create descriptor set layout: %d", err);
8590 rhiD->setObjectName(uint64_t(layout), VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, m_objectName);
8592 VkDescriptorSetAllocateInfo allocInfo = {};
8593 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8596 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8597 layouts[i] = layout;
8598 allocInfo.pSetLayouts = layouts;
8599 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &
poolIndex))
8603 boundResourceData[i].resize(sortedBindings.size());
8604 for (BoundResourceData &bd : boundResourceData[i])
8605 memset(&bd, 0,
sizeof(BoundResourceData));
8609 rhiD->setObjectName(uint64_t(descSets[i]), VK_OBJECT_TYPE_DESCRIPTOR_SET, m_objectName, i);
8613 rhiD->registerResource(
this);
8619 sortedBindings.clear();
8620 std::copy(m_bindings.cbegin(), m_bindings.cend(),
std::back_inserter(sortedBindings));
8621 if (!flags.testFlag(BindingsAreSorted))
8622 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8624 sortedDynamicOffsetBindingNumbers.clear();
8625 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8626 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8627 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8628 if (b->u.ubuf.hasDynamicOffset)
8629 sortedDynamicOffsetBindingNumbers.append(b->binding);
8643 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8644 for (BoundResourceData &bd : boundResourceData[i])
8645 memset(&bd, 0,
sizeof(BoundResourceData));
8663 if (!pipeline && !layout)
8670 e.pipelineState.pipeline = pipeline;
8671 e.pipelineState.layout = layout;
8673 pipeline = VK_NULL_HANDLE;
8674 layout = VK_NULL_HANDLE;
8678 rhiD->releaseQueue.append(e);
8679 rhiD->unregisterResource(
this);
8685 if (pipeline || layout)
8689 rhiD->pipelineCreationStart();
8690 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8693 if (!rhiD->ensurePipelineCache())
8696 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8697 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8698 pipelineLayoutInfo.setLayoutCount = 1;
8700 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8701 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8702 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8703 if (err != VK_SUCCESS) {
8704 qWarning(
"Failed to create pipeline layout: %d", err);
8707 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
8708 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
8709 layout = VK_NULL_HANDLE;
8712 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8713 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8715 QVarLengthArray<VkShaderModule, 4> shaders;
8716 auto shaderModuleCleanup = qScopeGuard([rhiD, &shaders] {
8717 for (VkShaderModule shader : shaders)
8718 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8720 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8721 QVarLengthArray<QByteArray, 4> entryPointNames;
8722 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8723 const QShader bakedShader = shaderStage.shader();
8724 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8725 if (spirv.shader().isEmpty()) {
8726 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8729 VkShaderModule shader = rhiD->createShader(spirv.shader());
8731 shaders.append(shader);
8732 VkPipelineShaderStageCreateInfo shaderInfo = {};
8733 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8734 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8735 shaderInfo.module = shader;
8736 entryPointNames.append(spirv.entryPoint());
8737 shaderInfo.pName =
nullptr;
8738 shaderStageCreateInfos.append(shaderInfo);
8743 for (qsizetype i = 0, ie = shaders.count(); i != ie; ++i)
8744 shaderStageCreateInfos[i].pName = entryPointNames[i].constData();
8746 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8747 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8749 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8750#ifdef VK_EXT_vertex_attribute_divisor
8751 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8753 int bindingIndex = 0;
8754 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8755 it != itEnd; ++it, ++bindingIndex)
8757 VkVertexInputBindingDescription bindingInfo = {
8758 uint32_t(bindingIndex),
8760 it->classification() == QRhiVertexInputBinding::PerVertex
8761 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8763 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8764#ifdef VK_EXT_vertex_attribute_divisor
8765 if (rhiD->caps.vertexAttribDivisor) {
8766 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8770 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8771 "VK_EXT_vertex_attribute_divisor on the device and "
8772 "VK_KHR_get_physical_device_properties2 on the instance");
8775 vertexBindings.append(bindingInfo);
8777 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8778 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8781 VkVertexInputAttributeDescription attributeInfo = {
8782 uint32_t(it->location()),
8783 uint32_t(it->binding()),
8784 toVkAttributeFormat(it->format()),
8787 vertexAttributes.append(attributeInfo);
8789 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8790 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8791 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8792 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8793 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8794 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8795#ifdef VK_EXT_vertex_attribute_divisor
8796 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8797 if (!nonOneStepRates.isEmpty()) {
8798 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8799 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8800 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8801 vertexInputInfo.pNext = &divisorInfo;
8804 pipelineInfo.pVertexInputState = &vertexInputInfo;
8806 QVarLengthArray<VkDynamicState, 8> dynEnable;
8807 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8808 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8809 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8810 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8811 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8812 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8813#ifdef VK_KHR_fragment_shading_rate
8814 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8815 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8818 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8819 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8820 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8821 dynamicInfo.pDynamicStates = dynEnable.constData();
8822 pipelineInfo.pDynamicState = &dynamicInfo;
8824 VkPipelineViewportStateCreateInfo viewportInfo = {};
8825 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8826 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8827 pipelineInfo.pViewportState = &viewportInfo;
8829 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8830 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8831 inputAsmInfo.topology = toVkTopology(m_topology);
8832 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8833 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8835 VkPipelineTessellationStateCreateInfo tessInfo = {};
8836#ifdef VK_VERSION_1_1
8837 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8839 if (m_topology == Patches) {
8840 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8841 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8848#ifdef VK_VERSION_1_1
8849 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8850 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8851 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8852 tessInfo.pNext = &originInfo;
8854 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8857 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8860 pipelineInfo.pTessellationState = &tessInfo;
8863 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8864 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8865 if (m_depthClamp && rhiD->caps.depthClamp)
8866 rastInfo.depthClampEnable = m_depthClamp;
8867 rastInfo.cullMode = toVkCullMode(m_cullMode);
8868 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8869 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8870 rastInfo.depthBiasEnable =
true;
8871 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8872 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8874 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8875 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8876 pipelineInfo.pRasterizationState = &rastInfo;
8878 VkPipelineMultisampleStateCreateInfo msInfo = {};
8879 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8880 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8881 pipelineInfo.pMultisampleState = &msInfo;
8883 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8884 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8885 dsInfo.depthTestEnable = m_depthTest;
8886 dsInfo.depthWriteEnable = m_depthWrite;
8887 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8888 dsInfo.stencilTestEnable = m_stencilTest;
8889 if (m_stencilTest) {
8890 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8891 dsInfo.front.compareMask = m_stencilReadMask;
8892 dsInfo.front.writeMask = m_stencilWriteMask;
8893 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8894 dsInfo.back.compareMask = m_stencilReadMask;
8895 dsInfo.back.writeMask = m_stencilWriteMask;
8897 pipelineInfo.pDepthStencilState = &dsInfo;
8899 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8900 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8901 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8902 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8903 VkPipelineColorBlendAttachmentState blend = {};
8904 blend.blendEnable = b.enable;
8905 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8906 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8907 blend.colorBlendOp = toVkBlendOp(b.opColor);
8908 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8909 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8910 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8911 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8912 vktargetBlends.append(blend);
8914 if (vktargetBlends.isEmpty()) {
8915 VkPipelineColorBlendAttachmentState blend = {};
8916 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8917 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8918 vktargetBlends.append(blend);
8920 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8921 blendInfo.pAttachments = vktargetBlends.constData();
8922 pipelineInfo.pColorBlendState = &blendInfo;
8924 pipelineInfo.layout = layout;
8926 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8927 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8929 err = rhiD
->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8931 if (err != VK_SUCCESS) {
8932 qWarning(
"Failed to create graphics pipeline: %d", err);
8935 pipelineLayoutCleanup.dismiss();
8937 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8939 rhiD->pipelineCreationEnd();
8942 rhiD->registerResource(
this);
8958 if (!pipeline && !layout)
8965 e.pipelineState.pipeline = pipeline;
8966 e.pipelineState.layout = layout;
8968 pipeline = VK_NULL_HANDLE;
8969 layout = VK_NULL_HANDLE;
8973 rhiD->releaseQueue.append(e);
8974 rhiD->unregisterResource(
this);
8980 if (pipeline || layout)
8984 rhiD->pipelineCreationStart();
8985 if (!rhiD->ensurePipelineCache())
8988 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8989 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8990 pipelineLayoutInfo.setLayoutCount = 1;
8992 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8993 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8994 VkResult err = rhiD
->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8995 if (err != VK_SUCCESS) {
8996 qWarning(
"Failed to create pipeline layout: %d", err);
8999 auto pipelineLayoutCleanup = qScopeGuard([
this, rhiD] {
9000 rhiD
->df->vkDestroyPipelineLayout(rhiD->dev, layout,
nullptr);
9001 layout = VK_NULL_HANDLE;
9004 VkComputePipelineCreateInfo pipelineInfo = {};
9005 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9006 pipelineInfo.layout = layout;
9008 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
9009 qWarning(
"Compute pipeline requires a compute shader stage");
9012 const QShader bakedShader = m_shaderStage.shader();
9013 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
9014 if (spirv.shader().isEmpty()) {
9015 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
9018 if (bakedShader.stage() != QShader::ComputeStage) {
9019 qWarning() << bakedShader <<
"is not a compute shader";
9022 VkShaderModule shader = rhiD->createShader(spirv.shader());
9025 auto shaderModuleCleanup = qScopeGuard([rhiD, shader] {
9026 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
9028 VkPipelineShaderStageCreateInfo shaderInfo = {};
9029 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9030 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
9031 shaderInfo.module = shader;
9032 const QByteArray entryPointName = spirv.entryPoint();
9033 shaderInfo.pName = entryPointName.constData();
9034 pipelineInfo.stage = shaderInfo;
9036 err = rhiD
->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
9037 if (err != VK_SUCCESS) {
9038 qWarning(
"Failed to create graphics pipeline: %d", err);
9041 pipelineLayoutCleanup.dismiss();
9043 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
9045 rhiD->pipelineCreationEnd();
9048 rhiD->registerResource(
this);
9077 nativeHandlesStruct.commandBuffer = cb;
9079 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
9080 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
9082 nativeHandlesStruct.commandBuffer = cb;
9085 return &nativeHandlesStruct;
9103 if (sc == VK_NULL_HANDLE)
9108 rhiD->swapchains.remove(
this);
9114 frame.cmdBuf = VK_NULL_HANDLE;
9118 surface = lastConnectedSurface = VK_NULL_HANDLE;
9121 rhiD->unregisterResource(
this);
9136 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
9146 VkSurfaceCapabilitiesKHR surfaceCaps = {};
9148 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
9149 VkExtent2D bufferSize = surfaceCaps.currentExtent;
9150 if (bufferSize.width == uint32_t(-1)) {
9151 Q_ASSERT(bufferSize.height == uint32_t(-1));
9152 return m_window->size() * m_window->devicePixelRatio();
9154 return QSize(
int(bufferSize.width),
int(bufferSize.height));
9160 case QRhiSwapChain::HDRExtendedSrgbLinear:
9161 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9162 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
9163 case QRhiSwapChain::HDR10:
9164 return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32
9165 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
9166 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
9167 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
9168 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
9181 qWarning(
"Attempted to call isFormatSupported() without a window set");
9186 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9189 uint32_t formatCount = 0;
9190 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
9191 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
9193 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
9194 for (uint32_t i = 0; i < formatCount; ++i) {
9195 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
9207 QRHI_RES_RHI(QRhiVulkan);
9209 if (m_window && rhiD->adapterLuidValid)
9210 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
9224 if (!rhiD->createDefaultRenderPass(rp,
9225 m_depthStencil !=
nullptr,
9236 rhiD->registerResource(rp);
9243 case VK_FORMAT_R8_SRGB:
9244 case VK_FORMAT_R8G8_SRGB:
9245 case VK_FORMAT_R8G8B8_SRGB:
9246 case VK_FORMAT_B8G8R8_SRGB:
9247 case VK_FORMAT_R8G8B8A8_SRGB:
9248 case VK_FORMAT_B8G8R8A8_SRGB:
9249 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
9264 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
9266 qWarning(
"Failed to get surface for window");
9269 if (surface == surf)
9275 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
9276 qWarning(
"Presenting not supported on this window");
9280 quint32 formatCount = 0;
9281 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
9282 QList<VkSurfaceFormatKHR> formats(formatCount);
9283 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
9287 colorFormat = formats.constFirst().format;
9288 colorSpace = formats.constFirst().colorSpace;
9291 const bool srgbRequested = m_flags.testFlag(sRGB);
9292 bool foundBestFormat =
false;
9293 if (m_format == SDR) {
9294 for (
int i = 0; i <
int(formatCount); ++i) {
9296 if (srgbRequested) {
9297 ok = defaultSrgbColorFormat == formats[i].format;
9299 ok = defaultColorFormat == formats[i].format;
9302 foundBestFormat =
true;
9303 colorFormat = formats[i].format;
9304 colorSpace = formats[i].colorSpace;
9311 if (!foundBestFormat && (m_format != SDR || srgbRequested)) {
9312 for (
int i = 0; i <
int(formatCount); ++i) {
9314 if (m_format != SDR) {
9315 ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
9316 }
else if (srgbRequested) {
9317 ok = isSrgbFormat(formats[i].format);
9320 colorFormat = formats[i].format;
9321 colorSpace = formats[i].colorSpace;
9328 if (m_format != SDR) {
9329 VkSurfaceFormatKHR format{};
9330 format.format = colorFormat;
9331 format.colorSpace = colorSpace;
9332 if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) {
9333 qWarning(
"Failed to select a suitable VkFormat for HDR, using format %d as fallback",
9337 if (srgbRequested && !isSrgbFormat(colorFormat)) {
9338 qWarning(
"Failed to select a suitable VkFormat for sRGB, using format %d as fallback",
9343#if QT_CONFIG(wayland)
9348 const bool hasPassThrough =
9349 std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
9350 return fmt.format == colorFormat
9351 && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
9353 if (hasPassThrough) {
9354 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
9358 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
9360 quint32 presModeCount = 0;
9361 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
9362 supportedPresentationModes.resize(presModeCount);
9363 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
9364 supportedPresentationModes.data());
9372 const bool needsRegistration = !window || window != m_window;
9379 if (window && window != m_window)
9383 m_currentPixelSize = surfacePixelSize();
9384 pixelSize = m_currentPixelSize;
9387 qWarning(
"Failed to create new swapchain");
9391 if (needsRegistration || !rhiD->swapchains.contains(
this))
9392 rhiD->swapchains.insert(
this);
9394 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
9395 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
9396 m_depthStencil->sampleCount(), m_sampleCount);
9398 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
9399 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
9400 m_depthStencil->setPixelSize(pixelSize);
9401 if (!m_depthStencil->create())
9402 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
9403 pixelSize.width(), pixelSize.height());
9405 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
9406 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
9407 pixelSize.width(), pixelSize.height());
9411 if (!m_renderPassDesc)
9412 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
9414 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
9415 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9416 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
9418 rtWrapper.d.pixelSize = pixelSize;
9419 rtWrapper.d.dpr =
float(window->devicePixelRatio());
9420 rtWrapper.d.sampleCount = samples;
9421 rtWrapper.d.colorAttCount = 1;
9422 if (m_depthStencil) {
9423 rtWrapper.d.dsAttCount = 1;
9424 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9426 rtWrapper.d.dsAttCount = 0;
9429 rtWrapper.d.dsResolveAttCount = 0;
9430 if (samples > VK_SAMPLE_COUNT_1_BIT)
9431 rtWrapper.d.resolveAttCount = 1;
9433 rtWrapper.d.resolveAttCount = 0;
9435 if (shadingRateMapView)
9436 rtWrapper.d.shadingRateAttCount = 1;
9438 rtWrapper.d.shadingRateAttCount = 0;
9443 QVarLengthArray<VkImageView, 4> views;
9444 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9446 views.append(
ds->imageView);
9447 if (samples > VK_SAMPLE_COUNT_1_BIT)
9448 views.append(image.imageView);
9449 if (shadingRateMapView)
9450 views.append(shadingRateMapView);
9452 VkFramebufferCreateInfo fbInfo = {};
9453 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9454 fbInfo.renderPass = rtWrapper.d.rp->rp;
9455 fbInfo.attachmentCount = uint32_t(views.count());
9456 fbInfo.pAttachments = views.constData();
9457 fbInfo.width = uint32_t(pixelSize.width());
9458 fbInfo.height = uint32_t(pixelSize.height());
9461 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9462 if (err != VK_SUCCESS) {
9463 qWarning(
"Failed to create framebuffer: %d", err);
9469 rtWrapperRight.setRenderPassDescriptor(
9471 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
9472 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
9474 rtWrapperRight.d.pixelSize = pixelSize;
9475 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
9476 rtWrapperRight.d.sampleCount = samples;
9477 rtWrapperRight.d.colorAttCount = 1;
9478 if (m_depthStencil) {
9479 rtWrapperRight.d.dsAttCount = 1;
9480 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
9482 rtWrapperRight.d.dsAttCount = 0;
9485 rtWrapperRight.d.dsResolveAttCount = 0;
9486 if (samples > VK_SAMPLE_COUNT_1_BIT)
9487 rtWrapperRight.d.resolveAttCount = 1;
9489 rtWrapperRight.d.resolveAttCount = 0;
9494 QVarLengthArray<VkImageView, 4> views;
9495 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
9497 views.append(
ds->imageView);
9498 if (samples > VK_SAMPLE_COUNT_1_BIT)
9499 views.append(image.imageView);
9500 if (shadingRateMapView)
9501 views.append(shadingRateMapView);
9503 VkFramebufferCreateInfo fbInfo = {};
9504 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
9505 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
9506 fbInfo.attachmentCount = uint32_t(views.count());
9507 fbInfo.pAttachments = views.constData();
9508 fbInfo.width = uint32_t(pixelSize.width());
9509 fbInfo.height = uint32_t(pixelSize.height());
9512 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9513 if (err != VK_SUCCESS) {
9514 qWarning(
"Failed to create framebuffer: %d", err);
9522 if (needsRegistration)
9523 rhiD->registerResource(
this);
const char * constData() const
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker)
VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD=nullptr)
QRhiSwapChain * createSwapChain() override
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
int resourceLimit(QRhi::ResourceLimit limit) const override
bool isDeviceLost() const override
void prepareUploadSubres(QVkTexture *texD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, size_t *curOfs, void *mp, BufferImageCopyList *copyInfos)
void executeDeferredReleases(bool forced=false)
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex)
QRhi::FrameOpResult finish() override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples, VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count)
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void releaseCachedResources() override
QVkSwapChain * currentSwapChain
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams=nullptr)
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
QList< int > supportedSampleCounts() const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb)
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot, VkAccessFlags access, VkPipelineStageFlags stage)
QRhi::FrameOpResult waitCommandCompletion(int frameSlot)
void endExternal(QRhiCommandBuffer *cb) override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex)
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
void drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride) override
VkResult createDescriptorPool(VkDescriptorPool *pool)
void prepareNewFrame(QRhiCommandBuffer *cb)
void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, int startLayer, int layerCount, int startLevel, int levelCount)
QList< QSize > supportedShadingRates(int sampleCount) const override
void printExtraErrorInfo(VkResult err)
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb)
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, QVkTexture *texD, QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage)
bool releaseCachedResourcesCalledBeforeFrameStart
QRhiGraphicsPipeline * createGraphicsPipeline() override
QRhiComputePipeline * createComputePipeline() override
void setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot=-1)
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
const QRhiNativeHandles * nativeHandles(QRhiCommandBuffer *cb) override
bool recreateSwapChain(QRhiSwapChain *swapChain)
void printDeviceLossErrorInfo() const
bool ensurePipelineCache(const void *initialData=nullptr, size_t initialDataSize=0)
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD)
void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD, VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
VkShaderModule createShader(const QByteArray &spirv)
void enqueueTransitionPassResources(QVkCommandBuffer *cbD)
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
bool create(QRhi::Flags flags) override
QVulkanDeviceFunctions * df
void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot=-1)
bool isFeatureSupported(QRhi::Feature feature) const override
void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
bool isYUpInFramebuffer() const override
void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override
void debugMarkEnd(QRhiCommandBuffer *cb) override
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
void releaseSwapChainResources(QRhiSwapChain *swapChain)
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, int depthLayer, QRhiShadingRateMap *shadingRateMap)
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, QVkBuffer *bufD, int slot, QRhiPassResourceTracker::BufferAccess access, QRhiPassResourceTracker::BufferStage stage)
VkFormat optimalDepthStencilFormat()
QRhiStats statistics() override
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
void drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset, quint32 drawCount, quint32 stride) override
void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD)
void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
void setDefaultScissor(QVkCommandBuffer *cbD)
bool isYUpInNDC() const override
const QRhiNativeHandles * nativeHandles() override
QRhiShadingRateMap * createShadingRateMap() override
void setPipelineCacheData(const QByteArray &data) override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
QRhiShaderResourceBindings * createShaderResourceBindings() override
void finishActiveReadbacks(bool forced=false)
void ensureCommandPoolForNewFrame()
QByteArray pipelineCacheData() override
void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD)
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
bool isClipDepthZeroToOne() const override
void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
QMatrix4x4 clipSpaceCorrMatrix() const override
int ubufAlignment() const override
QRhiDriverInfo driverInfo() const override
void beginExternal(QRhiCommandBuffer *cb) override
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat, QRhiShadingRateMap *shadingRateMap)
QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence, VkSemaphore *waitSem, VkSemaphore *signalSem)
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount)
bool makeThreadLocalNativeContextCurrent() override
QRhiDriverInfo info() const override
Combined button and popup list for selecting options.
static VkPolygonMode toVkPolygonMode(QRhiGraphicsPipeline::PolygonMode mode)
static VkCullModeFlags toVkCullMode(QRhiGraphicsPipeline::CullMode c)
static bool accessIsWrite(VkAccessFlags access)
static VkCompareOp toVkTextureCompareOp(QRhiSampler::CompareOp op)
static QVulkanInstance * globalVulkanInstance
static VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
static QRhiTexture::Format swapchainReadbackTextureFormat(VkFormat format, QRhiTexture::Flags *flags)
static VkStencilOp toVkStencilOp(QRhiGraphicsPipeline::StencilOp op)
static bool qvk_debug_filter(QVulkanInstance::DebugMessageSeverityFlags severity, QVulkanInstance::DebugMessageTypeFlags type, const void *callbackData)
static QVkBuffer::UsageState toVkBufferUsageState(QRhiPassResourceTracker::UsageState usage)
static bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b)
static bool isSrgbFormat(VkFormat format)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::TextureStage stage)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::BufferAccess access)
static VkImageLayout toVkLayout(QRhiPassResourceTracker::TextureAccess access)
static VkFormat toVkAttributeFormat(QRhiVertexInputAttribute::Format format)
static QVkTexture::UsageState toVkTextureUsageState(QRhiPassResourceTracker::UsageState usage)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::BufferStage stage)
static QRhiDriverInfo::DeviceType toRhiDeviceType(VkPhysicalDeviceType type)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkBuffer::UsageState &bufUsage)
static VkColorComponentFlags toVkColorComponents(QRhiGraphicsPipeline::ColorMask c)
static VkFilter toVkFilter(QRhiSampler::Filter f)
static VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t)
static void qrhivk_releaseTexture(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df, void *allocator)
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::TextureAccess access)
static VmaAllocator toVmaAllocator(QVkAllocator a)
static VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
static constexpr bool isDepthTextureFormat(QRhiTexture::Format format)
static void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphicsPipeline::StencilOpState &src)
VkSampleCountFlagBits mask
static VkShaderStageFlags toVkShaderStageFlags(QRhiShaderResourceBinding::StageFlags stage)
static constexpr VkImageAspectFlags aspectMaskForTextureFormat(QRhiTexture::Format format)
static VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
static VkBlendFactor toVkBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
static void fillDriverInfo(QRhiDriverInfo *info, const VkPhysicalDeviceProperties &physDevProperties)
static VkBlendOp toVkBlendOp(QRhiGraphicsPipeline::BlendOp op)
static void qrhivk_releaseRenderBuffer(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static VkFrontFace toVkFrontFace(QRhiGraphicsPipeline::FrontFace f)
void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource, QRhiShaderResourceBinding::Type bindingType, int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
static VkFormat toVkTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
static VkCompareOp toVkCompareOp(QRhiGraphicsPipeline::CompareOp op)
static void fillRenderPassCreateInfo(VkRenderPassCreateInfo *rpInfo, VkSubpassDescription *subpassDesc, QVkRenderPassDescriptor *rpD)
static VkSamplerMipmapMode toVkMipmapMode(QRhiSampler::Filter f)
static bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, const VkSurfaceFormatKHR &s)
static void qrhivk_releaseSampler(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static constexpr bool isStencilTextureFormat(QRhiTexture::Format format)
static QVkRenderTargetData * maybeRenderTargetData(QVkCommandBuffer *cbD)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkTexture::UsageState &texUsage)
static VmaAllocation toVmaAllocation(QVkAlloc a)
static void addToChain(T *head, void *entry)
static VkShaderStageFlagBits toVkShaderStage(QRhiShaderStage::Type type)
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS
static const int QVK_DESC_SETS_PER_POOL
static const int QVK_FRAMES_IN_FLIGHT
bool prepare(VkRenderPassCreateInfo *rpInfo, int multiViewCount, bool multiViewCap)
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
QRhiBuffer::NativeBuffer nativeBuffer() override
bool create() override
Creates the corresponding native graphics resources.
char * beginFullDynamicBufferUpdateForCurrentFrame() override
@ TransitionPassResources
QVkCommandBuffer(QRhiImplementation *rhi)
const QRhiNativeHandles * nativeHandles()
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
int currentPassResTrackerIndex
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkComputePipeline(QRhiImplementation *rhi)
QVkGraphicsPipeline(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags, QRhiTexture::Format backingFormatHint)
QRhiTexture::Format backingFormat() const override
bool create() override
Creates the corresponding native graphics resources.
QVkTexture * backingTexture
const QRhiNativeHandles * nativeHandles() override
void updateSerializedFormat()
bool hasDepthStencilResolve
~QVkRenderPassDescriptor()
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVector< quint32 > serializedFormat() const override
QVkRenderPassDescriptor(QRhiImplementation *rhi)
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QVkRenderPassDescriptor * rp
static const int MAX_COLOR_ATTACHMENTS
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
void updateResources(UpdateFlags flags) override
QVkShaderResourceBindings(QRhiImplementation *rhi)
bool create() override
Creates the corresponding resource binding set.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
~QVkShaderResourceBindings()
bool createFrom(QRhiTexture *src) override
Sets up the shading rate map to use the texture src as the image containing the per-tile shading rate...
QVkShadingRateMap(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QSize pixelSize() const override
int sampleCount() const override
float devicePixelRatio() const override
~QVkSwapChainRenderTarget()
QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
@ ScImageUseTransferSource
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QRhiRenderTarget * currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override
bool isFormatSupported(Format f) override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
QVkSwapChain(QRhiImplementation *rhi)
QSize surfacePixelSize() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderTarget * currentFrameRenderTarget() override
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::limitsType
QRhiCommandBuffer * currentFrameCommandBuffer() override
QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
~QVkTextureRenderTarget()
float devicePixelRatio() const override
bool create() override
Creates the corresponding native graphics resources.
int sampleCount() const override
QSize pixelSize() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
VkImageView perLevelImageViewForLoadStore(int level)
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
void setNativeLayout(int layout) override
With some graphics APIs, such as Vulkan, integrating custom rendering code that uses the graphics API...
QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
NativeTexture nativeTexture() override
bool prepareCreate(QSize *adjustedSize=nullptr)