5#include <qpa/qplatformvulkaninstance.h>
7#define VMA_IMPLEMENTATION
8#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
9#define VMA_STATIC_VULKAN_FUNCTIONS 0
10#define VMA_RECORDING_ENABLED 0
11#define VMA_DEDICATED_ALLOCATION 0
13Q_STATIC_LOGGING_CATEGORY(QRHI_LOG_VMA,
"qt.rhi.vma")
15#define VMA_ASSERT(expr) Q_ASSERT(expr)
17#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1
18#define VMA_DEBUG_LOG(str) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), (str))
19#define VMA_DEBUG_LOG_FORMAT(format, ...) QT_PREPEND_NAMESPACE(qDebug)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, __VA_ARGS__)
21template<
typename... Args>
22static void debugVmaLeak(
const char *format, Args&&... args)
26 static bool leakCheck =
true;
29 static bool leakCheck = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)(
"QT_RHI_LEAK_CHECK");
32 QT_PREPEND_NAMESPACE(qWarning)(QT_PREPEND_NAMESPACE(QRHI_LOG_VMA), format, std::forward<Args>(args)...);
34#define VMA_LEAK_LOG_FORMAT(format, ...) debugVmaLeak(format, __VA_ARGS__)
36QT_WARNING_DISABLE_GCC(
"-Wsuggest-override")
37QT_WARNING_DISABLE_GCC(
"-Wundef")
38QT_WARNING_DISABLE_CLANG(
"-Wundef")
39#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1100
40QT_WARNING_DISABLE_CLANG(
"-Wdeprecated-copy")
42#include "vk_mem_alloc.h"
46#include <QVulkanFunctions>
47#include <QtGui/qwindow.h>
48#include <private/qvulkandefaultinstance_p.h>
54
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
85
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
195
196
197
198
199
202
203
204
205
208
209
210
211
212
216
217
218
219
220
221
222
223
224
225
228
229
230
231
234
235
236
237
238
241
242
243
244
247
248
249
250
253
254
255
256
257
260
261
262
263
264
267
268
269
270
271
275
276
277
278
279
280
281
282
283
284
285
286
287
288
291
292
293
294
298
299
300
301
302
303
304
305
308
309
310
311
315
316
317
318
319
320
321
324
325
326
327
328
329
332
333
334
335
336
337
340
341
342
343
344
345
348
349
350
351
352
353
356
357
358
359
360
361
364
365
366
367
368
369
372inline Int aligned(Int v, Int byteAlign)
374 return (v + byteAlign - 1) & ~(byteAlign - 1);
379static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetInstanceProcAddr(VkInstance,
const char *pName)
381 return globalVulkanInstance->getInstanceProcAddr(pName);
384static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL wrap_vkGetDeviceProcAddr(VkDevice device,
const char *pName)
386 return globalVulkanInstance->functions()->vkGetDeviceProcAddr(device, pName);
391 return reinterpret_cast<VmaAllocation>(a);
396 return reinterpret_cast<VmaAllocator>(a);
400
401
402
403
404
405
406QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
409 QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2")
414
415
416
417
418QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
421 QByteArrayLiteral(
"VK_KHR_swapchain"),
422 QByteArrayLiteral(
"VK_EXT_vertex_attribute_divisor"),
423 QByteArrayLiteral(
"VK_KHR_create_renderpass2"),
424 QByteArrayLiteral(
"VK_KHR_depth_stencil_resolve"),
425 QByteArrayLiteral(
"VK_KHR_fragment_shading_rate")
438 qWarning(
"QRhi for Vulkan attempted to be initialized without a QVulkanInstance; using QVulkanDefaultInstance.");
439 inst = QVulkanDefaultInstance::instance();
443 requestedDeviceExtensions = params->deviceExtensions;
446 physDev = importParams->physDev;
447 dev = importParams->dev;
448 if (dev && physDev) {
450 gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
451 gfxQueueIdx = importParams->gfxQueueIdx;
453 if (importParams->vmemAllocator) {
462 QVulkanInstance::DebugMessageTypeFlags type,
463 const void *callbackData)
467#ifdef VK_EXT_debug_utils
468 const VkDebugUtilsMessengerCallbackDataEXT *d =
static_cast<
const VkDebugUtilsMessengerCallbackDataEXT *>(callbackData);
472 if (strstr(d->pMessage,
"Mapping an image with layout")
473 && strstr(d->pMessage,
"can result in undefined behavior if this memory is used by the device"))
484 if (strstr(d->pMessage,
"VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
487 Q_UNUSED(callbackData);
495 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
496 return QRhiDriverInfo::UnknownDevice;
497 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
498 return QRhiDriverInfo::IntegratedDevice;
499 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
500 return QRhiDriverInfo::DiscreteDevice;
501 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
502 return QRhiDriverInfo::VirtualDevice;
503 case VK_PHYSICAL_DEVICE_TYPE_CPU:
504 return QRhiDriverInfo::CpuDevice;
506 return QRhiDriverInfo::UnknownDevice;
510static inline void fillDriverInfo(QRhiDriverInfo *info,
const VkPhysicalDeviceProperties &physDevProperties)
512 info->deviceName = QByteArray(physDevProperties.deviceName);
513 info->deviceId = physDevProperties.deviceID;
514 info->vendorId = physDevProperties.vendorID;
515 info->deviceType = toRhiDeviceType(physDevProperties.deviceType);
521 VkBaseOutStructure *s =
reinterpret_cast<VkBaseOutStructure *>(head);
523 VkBaseOutStructure *next =
reinterpret_cast<VkBaseOutStructure *>(s->pNext);
529 s->pNext =
reinterpret_cast<VkBaseOutStructure *>(entry);
535 if (!inst->isValid()) {
536 qWarning(
"Vulkan instance is not valid");
541 qCDebug(QRHI_LOG_INFO,
"Initializing QRhi Vulkan backend %p with flags %d",
this,
int(rhiFlags));
543 globalVulkanInstance = inst;
544 f = inst->functions();
545 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
546 qCDebug(QRHI_LOG_INFO,
"Enabled instance extensions:");
547 for (
const char *ext : inst->extensions())
548 qCDebug(QRHI_LOG_INFO,
" %s", ext);
552 caps.debugUtils = inst->extensions().contains(QByteArrayLiteral(
"VK_EXT_debug_utils"));
554 QList<VkQueueFamilyProperties> queueFamilyProps;
555 auto queryQueueFamilyProps = [
this, &queueFamilyProps] {
556 uint32_t queueCount = 0;
557 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
558 queueFamilyProps.resize(
int(queueCount));
559 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
564 uint32_t physDevCount = 0;
565 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
567 qWarning(
"No physical devices");
570 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
571 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
572 if (err != VK_SUCCESS || !physDevCount) {
573 qWarning(
"Failed to enumerate physical devices: %d", err);
577 int physDevIndex = -1;
578 int requestedPhysDevIndex = -1;
579 if (qEnvironmentVariableIsSet(
"QT_VK_PHYSICAL_DEVICE_INDEX"))
580 requestedPhysDevIndex = qEnvironmentVariableIntValue(
"QT_VK_PHYSICAL_DEVICE_INDEX");
582 if (requestedPhysDevIndex < 0 && requestedRhiAdapter) {
583 VkPhysicalDevice requestedPhysDev =
static_cast<QVulkanAdapter *>(requestedRhiAdapter)->physDev;
584 for (
int i = 0; i <
int(physDevCount); ++i) {
585 if (physDevs[i] == requestedPhysDev) {
586 requestedPhysDevIndex = i;
592 if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
593 for (
int i = 0; i <
int(physDevCount); ++i) {
594 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
595 if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
596 requestedPhysDevIndex = i;
602 for (
int i = 0; i <
int(physDevCount); ++i) {
603 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
604 qCDebug(QRHI_LOG_INFO,
"Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
606 physDevProperties.deviceName,
607 VK_VERSION_MAJOR(physDevProperties.driverVersion),
608 VK_VERSION_MINOR(physDevProperties.driverVersion),
609 VK_VERSION_PATCH(physDevProperties.driverVersion),
610 VK_VERSION_MAJOR(physDevProperties.apiVersion),
611 VK_VERSION_MINOR(physDevProperties.apiVersion),
612 VK_VERSION_PATCH(physDevProperties.apiVersion),
613 physDevProperties.vendorID,
614 physDevProperties.deviceID,
615 physDevProperties.deviceType);
616 if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex ==
int(i))) {
618 qCDebug(QRHI_LOG_INFO,
" using this physical device");
622 if (physDevIndex < 0) {
623 qWarning(
"No matching physical device");
626 physDev = physDevs[physDevIndex];
627 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
629 f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
630 qCDebug(QRHI_LOG_INFO,
"Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
631 physDevProperties.deviceName,
632 VK_VERSION_MAJOR(physDevProperties.driverVersion),
633 VK_VERSION_MINOR(physDevProperties.driverVersion),
634 VK_VERSION_PATCH(physDevProperties.driverVersion),
635 VK_VERSION_MAJOR(physDevProperties.apiVersion),
636 VK_VERSION_MINOR(physDevProperties.apiVersion),
637 VK_VERSION_PATCH(physDevProperties.apiVersion),
638 physDevProperties.vendorID,
639 physDevProperties.deviceID,
640 physDevProperties.deviceType);
643 caps.apiVersion = inst->apiVersion();
649 const QVersionNumber physDevApiVersion(VK_VERSION_MAJOR(physDevProperties.apiVersion),
650 VK_VERSION_MINOR(physDevProperties.apiVersion));
651 if (physDevApiVersion < caps.apiVersion) {
652 qCDebug(QRHI_LOG_INFO) <<
"Instance has api version" << caps.apiVersion
653 <<
"whereas the chosen physical device has" << physDevApiVersion
654 <<
"- restricting to the latter";
655 caps.apiVersion = physDevApiVersion;
658 fillDriverInfo(&driverInfoStruct, physDevProperties);
660 QVulkanInfoVector<QVulkanExtension> devExts;
661 uint32_t devExtCount = 0;
662 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount,
nullptr);
664 QList<VkExtensionProperties> extProps(devExtCount);
665 f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &devExtCount, extProps.data());
666 for (
const VkExtensionProperties &p : std::as_const(extProps))
667 devExts.append({ p.extensionName, p.specVersion });
669 qCDebug(QRHI_LOG_INFO,
"%d device extensions available",
int(devExts.size()));
671 bool featuresQueried =
false;
673 VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
674 physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
677#ifdef VK_KHR_fragment_shading_rate
678 VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures = {};
679 fragmentShadingRateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
680 if (devExts.contains(
"VK_KHR_fragment_shading_rate"))
681 addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
687 if (!featuresQueried) {
689 if (caps.apiVersion >= QVersionNumber(1, 2)) {
690 physDevFeatures11IfApi12OrNewer = {};
691 physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
692 physDevFeatures12 = {};
693 physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
695 physDevFeatures13 = {};
696 physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
698 addToChain(&physDevFeaturesChainable, &physDevFeatures11IfApi12OrNewer);
699 physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
701 if (caps.apiVersion >= QVersionNumber(1, 3))
702 physDevFeatures12.pNext = &physDevFeatures13;
704 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
705 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
706 featuresQueried =
true;
713 if (!featuresQueried) {
721 if (caps.apiVersion == QVersionNumber(1, 1)) {
722 multiviewFeaturesIfApi11 = {};
723 multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
724 addToChain(&physDevFeaturesChainable, &multiviewFeaturesIfApi11);
725 f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
726 memcpy(&physDevFeatures, &physDevFeaturesChainable.features,
sizeof(VkPhysicalDeviceFeatures));
727 featuresQueried =
true;
732 if (!featuresQueried) {
735 f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
736 featuresQueried =
true;
744 std::optional<uint32_t> gfxQueueFamilyIdxOpt;
745 std::optional<uint32_t> computelessGfxQueueCandidateIdxOpt;
746 queryQueueFamilyProps();
747 const uint32_t queueFamilyCount = uint32_t(queueFamilyProps.size());
748 for (uint32_t i = 0; i < queueFamilyCount; ++i) {
749 qCDebug(QRHI_LOG_INFO,
"queue family %u: flags=0x%x count=%u",
750 i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
751 if (!gfxQueueFamilyIdxOpt.has_value()
752 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
753 && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
755 if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
756 gfxQueueFamilyIdxOpt = i;
757 else if (!computelessGfxQueueCandidateIdxOpt.has_value())
758 computelessGfxQueueCandidateIdxOpt = i;
761 if (gfxQueueFamilyIdxOpt.has_value()) {
762 gfxQueueFamilyIdx = gfxQueueFamilyIdxOpt.value();
764 if (computelessGfxQueueCandidateIdxOpt.has_value()) {
765 gfxQueueFamilyIdx = computelessGfxQueueCandidateIdxOpt.value();
767 qWarning(
"No graphics (or no graphics+present) queue family found");
772 VkDeviceQueueCreateInfo queueInfo = {};
773 const float prio[] = { 0 };
774 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
775 queueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
776 queueInfo.queueCount = 1;
777 queueInfo.pQueuePriorities = prio;
779 QList<
const char *> devLayers;
780 if (inst->layers().contains(
"VK_LAYER_KHRONOS_validation"))
781 devLayers.append(
"VK_LAYER_KHRONOS_validation");
783 QList<
const char *> requestedDevExts;
784 requestedDevExts.append(
"VK_KHR_swapchain");
786 const bool hasPhysDevProp2 = inst->extensions().contains(QByteArrayLiteral(
"VK_KHR_get_physical_device_properties2"));
788 if (devExts.contains(QByteArrayLiteral(
"VK_KHR_portability_subset"))) {
789 if (hasPhysDevProp2) {
790 requestedDevExts.append(
"VK_KHR_portability_subset");
792 qWarning(
"VK_KHR_portability_subset should be enabled on the device "
793 "but the instance does not have VK_KHR_get_physical_device_properties2 enabled. "
798#ifdef VK_EXT_vertex_attribute_divisor
799 if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
800 if (hasPhysDevProp2) {
801 requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
802 caps.vertexAttribDivisor =
true;
807#ifdef VK_KHR_create_renderpass2
808 if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
809 requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
810 caps.renderPass2KHR =
true;
814#ifdef VK_KHR_depth_stencil_resolve
815 if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
816 requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
817 caps.depthStencilResolveKHR =
true;
821#ifdef VK_KHR_fragment_shading_rate
822 if (devExts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME))
823 requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
826 for (
const QByteArray &ext : requestedDeviceExtensions) {
827 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
828 if (devExts.contains(ext)) {
829 requestedDevExts.append(ext.constData());
831 qWarning(
"Device extension %s requested in QRhiVulkanInitParams is not supported",
837 QByteArrayList envExtList = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS").split(
';');
838 for (
const QByteArray &ext : envExtList) {
839 if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
840 if (devExts.contains(ext)) {
841 requestedDevExts.append(ext.constData());
843 qWarning(
"Device extension %s requested in QT_VULKAN_DEVICE_EXTENSIONS is not supported",
849 if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
850 qCDebug(QRHI_LOG_INFO,
"Enabling device extensions:");
851 for (
const char *ext : requestedDevExts)
852 qCDebug(QRHI_LOG_INFO,
" %s", ext);
855 VkDeviceCreateInfo devInfo = {};
856 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
857 devInfo.queueCreateInfoCount = 1;
858 devInfo.pQueueCreateInfos = &queueInfo;
859 devInfo.enabledLayerCount = uint32_t(devLayers.size());
860 devInfo.ppEnabledLayerNames = devLayers.constData();
861 devInfo.enabledExtensionCount = uint32_t(requestedDevExts.size());
862 devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
878 physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
881 physDevFeatures13.robustImageAccess = VK_FALSE;
885 if (caps.apiVersion >= QVersionNumber(1, 1)) {
892 devInfo.pNext = &physDevFeaturesChainable;
896 physDevFeatures.robustBufferAccess = VK_FALSE;
897 devInfo.pEnabledFeatures = &physDevFeatures;
900 VkResult err = f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
901 if (err != VK_SUCCESS) {
902 qWarning(
"Failed to create device: %d", err);
906 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
911 caps.vertexAttribDivisor =
true;
912 caps.renderPass2KHR =
true;
913 caps.depthStencilResolveKHR =
true;
916 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
917 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
918 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
919 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
920 vkGetPhysicalDeviceSurfacePresentModesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
921 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfacePresentModesKHR"));
923 df = inst->deviceFunctions(dev);
925 VkCommandPoolCreateInfo poolInfo = {};
926 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
927 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
929 VkResult err = df->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool[i]);
930 if (err != VK_SUCCESS) {
931 qWarning(
"Failed to create command pool: %d", err);
936 qCDebug(QRHI_LOG_INFO,
"Using queue family index %u and queue index %u",
937 gfxQueueFamilyIdx, gfxQueueIdx);
939 df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, gfxQueueIdx, &gfxQueue);
941 if (queueFamilyProps.isEmpty())
942 queryQueueFamilyProps();
944 caps.compute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
945 timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
947 ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
950 texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
952 caps.wideLines = physDevFeatures.wideLines;
954 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
956 caps.tessellation = physDevFeatures.tessellationShader;
957 caps.geometryShader = physDevFeatures.geometryShader;
959 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
962 if (caps.apiVersion >= QVersionNumber(1, 2))
963 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
967 if (caps.apiVersion == QVersionNumber(1, 1))
968 caps.multiView = multiviewFeaturesIfApi11.multiview;
971#ifdef VK_KHR_fragment_shading_rate
972 fragmentShadingRates.clear();
973 if (caps.apiVersion >= QVersionNumber(1, 1)) {
974 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
975 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
976 if (caps.imageBasedShadingRate) {
977 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
978 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
979 VkPhysicalDeviceProperties2 props2 = {};
980 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
981 props2.pNext = &shadingRateProps;
982 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
983 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
986 if (caps.perDrawShadingRate) {
987 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
988 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
989 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
990 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
992 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
993 fragmentShadingRates.resize(count);
994 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
996 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
998 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1000 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1001 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1010#ifdef VK_KHR_create_renderpass2
1011 if (caps.renderPass2KHR) {
1012 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1013 if (!vkCreateRenderPass2KHR)
1014 caps.renderPass2KHR =
false;
1020 adapterLuidValid =
false;
1022#ifdef VK_VERSION_1_2
1023 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1024 VkPhysicalDeviceVulkan11Properties v11props = {};
1025 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1026 VkPhysicalDeviceProperties2 props2 = {};
1027 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1028 props2.pNext = &v11props;
1029 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1030 if (v11props.deviceLUIDValid) {
1031 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1032 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1033 adapterLuidValid =
true;
1034 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1035 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1036 adapterLuid.LowPart, adapterLuid.HighPart);
1043 VmaVulkanFunctions funcs = {};
1044 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1045 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1047 VmaAllocatorCreateInfo allocatorInfo = {};
1050 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1051 allocatorInfo.physicalDevice = physDev;
1052 allocatorInfo.device = dev;
1053 allocatorInfo.pVulkanFunctions = &funcs;
1054 allocatorInfo.instance = inst->vkInstance();
1062#ifdef VK_VERSION_1_4
1063 if (caps.apiVersion >= QVersionNumber(1, 4))
1064 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1067#ifdef VK_VERSION_1_3
1068 if (caps.apiVersion >= QVersionNumber(1, 3))
1069 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1072#ifdef VK_VERSION_1_2
1073 if (caps.apiVersion >= QVersionNumber(1, 2))
1074 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1077#ifdef VK_VERSION_1_1
1078 if (caps.apiVersion >= QVersionNumber(1, 1))
1079 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1082#ifdef VK_VERSION_1_0
1083 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1086 VmaAllocator vmaallocator;
1087 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1088 if (err != VK_SUCCESS) {
1089 qWarning(
"Failed to create allocator: %d", err);
1095 inst->installDebugOutputFilter(qvk_debug_filter);
1097 VkDescriptorPool pool;
1098 VkResult err = createDescriptorPool(&pool);
1099 if (err == VK_SUCCESS)
1100 descriptorPools.append(pool);
1102 qWarning(
"Failed to create initial descriptor pool: %d", err);
1104 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1105 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1106 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1108 err = df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1109 if (err != VK_SUCCESS) {
1110 qWarning(
"Failed to create timestamp query pool: %d", err);
1113 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1114 timestampQueryPoolMap.fill(
false);
1116#ifdef VK_EXT_debug_utils
1117 if (caps.debugUtils) {
1118 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1119 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1120 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1121 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1127 nativeHandlesStruct.physDev = physDev;
1128 nativeHandlesStruct.dev = dev;
1129 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1130 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1131 nativeHandlesStruct.gfxQueue = gfxQueue;
1132 nativeHandlesStruct.vmemAllocator = allocator;
1133 nativeHandlesStruct.inst = inst;
1144 df->vkDeviceWaitIdle(dev);
1151 dxgiHdrInfo =
nullptr;
1155 df->vkDestroyFence(dev, ofr.cmdFence,
nullptr);
1156 ofr.cmdFence = VK_NULL_HANDLE;
1159 if (pipelineCache) {
1160 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1161 pipelineCache = VK_NULL_HANDLE;
1164 for (
const DescriptorPoolData &pool : descriptorPools)
1165 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1167 descriptorPools.clear();
1169 if (timestampQueryPool) {
1170 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1171 timestampQueryPool = VK_NULL_HANDLE;
1175 vmaDestroyAllocator(toVmaAllocator(allocator));
1181 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1182 cmdPool[i] = VK_NULL_HANDLE;
1184 freeSecondaryCbs[i].clear();
1185 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1188 if (!importedDevice && dev) {
1189 df->vkDestroyDevice(dev,
nullptr);
1190 inst->resetDeviceFunctions(dev);
1191 dev = VK_NULL_HANDLE;
1201QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1203 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1204 if (nativeHandles) {
1205 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1206 requestedPhysDev = h->physDev;
1209 QRhi::AdapterList list;
1210 QVulkanFunctions *f = inst->functions();
1211 uint32_t physDevCount = 0;
1212 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1216 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1217 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1218 if (err != VK_SUCCESS || !physDevCount)
1221 VkPhysicalDeviceProperties physDevProperties = {};
1222 for (uint32_t i = 0; i < physDevCount; ++i) {
1223 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1226 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1227 QVulkanAdapter *a =
new QVulkanAdapter;
1228 a->physDev = physDevs[i];
1229 fillDriverInfo(&a->adapterInfo, physDevProperties);
1243 VkDescriptorPoolSize descPoolSizes[] = {
1244 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1245 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1246 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1247 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1248 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1250 VkDescriptorPoolCreateInfo descPoolInfo = {};
1251 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1255 descPoolInfo.flags = 0;
1257 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1258 descPoolInfo.pPoolSizes = descPoolSizes;
1259 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1264 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1265 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1266 VkResult r = df->vkAllocateDescriptorSets(dev, allocInfo, result);
1267 if (r == VK_SUCCESS)
1268 descriptorPools[poolIndex].refCount += 1;
1272 int lastPoolIdx = descriptorPools.size() - 1;
1273 for (
int i = lastPoolIdx; i >= 0; --i) {
1274 if (descriptorPools[i].refCount == 0) {
1275 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1276 descriptorPools[i].allocedDescSets = 0;
1278 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1279 VkResult err = tryAllocate(i);
1280 if (err == VK_SUCCESS) {
1281 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1282 *resultPoolIndex = i;
1288 VkDescriptorPool newPool;
1289 VkResult poolErr = createDescriptorPool(&newPool);
1290 if (poolErr == VK_SUCCESS) {
1291 descriptorPools.append(newPool);
1292 lastPoolIdx = descriptorPools.size() - 1;
1293 VkResult err = tryAllocate(lastPoolIdx);
1294 if (err != VK_SUCCESS) {
1295 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1298 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1299 *resultPoolIndex = lastPoolIdx;
1302 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1309 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1311 case QRhiTexture::RGBA8:
1312 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1313 case QRhiTexture::BGRA8:
1314 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1315 case QRhiTexture::R8:
1316 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1317 case QRhiTexture::RG8:
1318 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1319 case QRhiTexture::R16:
1320 return VK_FORMAT_R16_UNORM;
1321 case QRhiTexture::RG16:
1322 return VK_FORMAT_R16G16_UNORM;
1323 case QRhiTexture::RED_OR_ALPHA8:
1324 return VK_FORMAT_R8_UNORM;
1326 case QRhiTexture::RGBA16F:
1327 return VK_FORMAT_R16G16B16A16_SFLOAT;
1328 case QRhiTexture::RGBA32F:
1329 return VK_FORMAT_R32G32B32A32_SFLOAT;
1330 case QRhiTexture::R16F:
1331 return VK_FORMAT_R16_SFLOAT;
1332 case QRhiTexture::R32F:
1333 return VK_FORMAT_R32_SFLOAT;
1335 case QRhiTexture::RGB10A2:
1337 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1339 case QRhiTexture::R8SI:
1340 return VK_FORMAT_R8_SINT;
1341 case QRhiTexture::R32SI:
1342 return VK_FORMAT_R32_SINT;
1343 case QRhiTexture::RG32SI:
1344 return VK_FORMAT_R32G32_SINT;
1345 case QRhiTexture::RGBA32SI:
1346 return VK_FORMAT_R32G32B32A32_SINT;
1348 case QRhiTexture::R8UI:
1349 return VK_FORMAT_R8_UINT;
1350 case QRhiTexture::R32UI:
1351 return VK_FORMAT_R32_UINT;
1352 case QRhiTexture::RG32UI:
1353 return VK_FORMAT_R32G32_UINT;
1354 case QRhiTexture::RGBA32UI:
1355 return VK_FORMAT_R32G32B32A32_UINT;
1357 case QRhiTexture::D16:
1358 return VK_FORMAT_D16_UNORM;
1359 case QRhiTexture::D24:
1360 return VK_FORMAT_X8_D24_UNORM_PACK32;
1361 case QRhiTexture::D24S8:
1362 return VK_FORMAT_D24_UNORM_S8_UINT;
1363 case QRhiTexture::D32F:
1364 return VK_FORMAT_D32_SFLOAT;
1365 case QRhiTexture::D32FS8:
1366 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1368 case QRhiTexture::BC1:
1369 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1370 case QRhiTexture::BC2:
1371 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1372 case QRhiTexture::BC3:
1373 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1374 case QRhiTexture::BC4:
1375 return VK_FORMAT_BC4_UNORM_BLOCK;
1376 case QRhiTexture::BC5:
1377 return VK_FORMAT_BC5_UNORM_BLOCK;
1378 case QRhiTexture::BC6H:
1379 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1380 case QRhiTexture::BC7:
1381 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1383 case QRhiTexture::ETC2_RGB8:
1384 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1385 case QRhiTexture::ETC2_RGB8A1:
1386 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1387 case QRhiTexture::ETC2_RGBA8:
1388 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1390 case QRhiTexture::ASTC_4x4:
1391 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1392 case QRhiTexture::ASTC_5x4:
1393 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1394 case QRhiTexture::ASTC_5x5:
1395 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1396 case QRhiTexture::ASTC_6x5:
1397 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1398 case QRhiTexture::ASTC_6x6:
1399 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1400 case QRhiTexture::ASTC_8x5:
1401 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1402 case QRhiTexture::ASTC_8x6:
1403 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1404 case QRhiTexture::ASTC_8x8:
1405 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1406 case QRhiTexture::ASTC_10x5:
1407 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1408 case QRhiTexture::ASTC_10x6:
1409 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1410 case QRhiTexture::ASTC_10x8:
1411 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1412 case QRhiTexture::ASTC_10x10:
1413 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1414 case QRhiTexture::ASTC_12x10:
1415 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1416 case QRhiTexture::ASTC_12x12:
1417 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1420 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1427 case VK_FORMAT_R8G8B8A8_UNORM:
1428 return QRhiTexture::RGBA8;
1429 case VK_FORMAT_R8G8B8A8_SRGB:
1431 (*flags) |= QRhiTexture::sRGB;
1432 return QRhiTexture::RGBA8;
1433 case VK_FORMAT_B8G8R8A8_UNORM:
1434 return QRhiTexture::BGRA8;
1435 case VK_FORMAT_B8G8R8A8_SRGB:
1437 (*flags) |= QRhiTexture::sRGB;
1438 return QRhiTexture::BGRA8;
1439 case VK_FORMAT_R16G16B16A16_SFLOAT:
1440 return QRhiTexture::RGBA16F;
1441 case VK_FORMAT_R32G32B32A32_SFLOAT:
1442 return QRhiTexture::RGBA32F;
1443 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1444 return QRhiTexture::RGB10A2;
1446 qWarning(
"VkFormat %d cannot be read back", format);
1449 return QRhiTexture::UnknownFormat;
1455 case QRhiTexture::Format::D16:
1456 case QRhiTexture::Format::D24:
1457 case QRhiTexture::Format::D24S8:
1458 case QRhiTexture::Format::D32F:
1459 case QRhiTexture::Format::D32FS8:
1470 case QRhiTexture::Format::D24S8:
1471 case QRhiTexture::Format::D32FS8:
1481 if (isDepthTextureFormat(format)) {
1482 if (isStencilTextureFormat(format))
1483 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1485 return VK_IMAGE_ASPECT_DEPTH_BIT;
1487 return VK_IMAGE_ASPECT_COLOR_BIT;
1498 VkPhysicalDeviceMemoryProperties physDevMemProps;
1499 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1501 VkMemoryRequirements memReq;
1502 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1503 uint32_t memTypeIndex = uint32_t(-1);
1505 if (memReq.memoryTypeBits) {
1507 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1508 bool foundDevLocal =
false;
1509 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1510 if (memReq.memoryTypeBits & (1 << i)) {
1511 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1512 if (!foundDevLocal) {
1513 foundDevLocal =
true;
1516 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1525 return memTypeIndex;
1529 const QSize &pixelSize,
1530 VkImageUsageFlags usage,
1531 VkImageAspectFlags aspectMask,
1532 VkSampleCountFlagBits samples,
1533 VkDeviceMemory *mem,
1538 VkMemoryRequirements memReq;
1541 for (
int i = 0; i < count; ++i) {
1542 VkImageCreateInfo imgInfo = {};
1543 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1544 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1545 imgInfo.format = format;
1546 imgInfo.extent.width = uint32_t(pixelSize.width());
1547 imgInfo.extent.height = uint32_t(pixelSize.height());
1548 imgInfo.extent.depth = 1;
1549 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1550 imgInfo.samples = samples;
1551 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1552 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1553 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1555 err = df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1556 if (err != VK_SUCCESS) {
1557 qWarning(
"Failed to create image: %d", err);
1564 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1567 VkMemoryAllocateInfo memInfo = {};
1568 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1569 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1571 uint32_t startIndex = 0;
1573 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1574 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1575 qWarning(
"No suitable memory type found");
1578 startIndex = memInfo.memoryTypeIndex + 1;
1579 err = df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1580 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1581 qWarning(
"Failed to allocate image memory: %d", err);
1584 }
while (err != VK_SUCCESS);
1586 VkDeviceSize ofs = 0;
1587 for (
int i = 0; i < count; ++i) {
1588 err = df->vkBindImageMemory(dev, images[i], *mem, ofs);
1589 if (err != VK_SUCCESS) {
1590 qWarning(
"Failed to bind image memory: %d", err);
1593 ofs += aligned(memReq.size, memReq.alignment);
1595 VkImageViewCreateInfo imgViewInfo = {};
1596 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1597 imgViewInfo.image = images[i];
1598 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1599 imgViewInfo.format = format;
1600 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1601 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1602 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1603 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1604 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1605 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1607 err = df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1608 if (err != VK_SUCCESS) {
1609 qWarning(
"Failed to create image view: %d", err);
1619 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1620 return optimalDsFormat;
1622 const VkFormat dsFormatCandidates[] = {
1623 VK_FORMAT_D24_UNORM_S8_UINT,
1624 VK_FORMAT_D32_SFLOAT_S8_UINT,
1625 VK_FORMAT_D16_UNORM_S8_UINT
1627 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1628 int dsFormatIdx = 0;
1629 while (dsFormatIdx < dsFormatCandidateCount) {
1630 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1631 VkFormatProperties fmtProp;
1632 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1633 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1637 if (dsFormatIdx == dsFormatCandidateCount)
1638 qWarning(
"Failed to find an optimal depth-stencil format");
1640 return optimalDsFormat;
1645 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1647 if (multiViewCount < 2)
1649 if (!multiViewCap) {
1650 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1653#ifdef VK_VERSION_1_1
1654 uint32_t allViewsMask = 0;
1655 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1656 allViewsMask |= (1 << i);
1657 multiViewMask = allViewsMask;
1658 multiViewCorrelationMask = allViewsMask;
1659 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1660 multiViewInfo.subpassCount = 1;
1661 multiViewInfo.pViewMasks = &multiViewMask;
1662 multiViewInfo.correlationMaskCount = 1;
1663 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1664 rpInfo->pNext = &multiViewInfo;
1669#ifdef VK_VERSION_1_1
1676#ifdef VK_KHR_create_renderpass2
1680struct RenderPass2SetupHelper
1682 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1684 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1688 if (multiViewCount >= 2) {
1689 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1690 viewMask |= (1 << i);
1693 attDescs2.resize(rpInfo->attachmentCount);
1694 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1695 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1696 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1698 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1699 att2.flags = att.flags;
1700 att2.format = att.format;
1701 att2.samples = att.samples;
1702 att2.loadOp = att.loadOp;
1703 att2.storeOp = att.storeOp;
1704 att2.stencilLoadOp = att.stencilLoadOp;
1705 att2.stencilStoreOp = att.stencilStoreOp;
1706 att2.initialLayout = att.initialLayout;
1707 att2.finalLayout = att.finalLayout;
1712 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1713 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1714 subpass2.flags = subpassDesc.flags;
1715 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1716 if (multiViewCount >= 2)
1717 subpass2.viewMask = viewMask;
1720 qsizetype startIndex = attRefs2.count();
1721 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1722 attRefs2.append({});
1723 VkAttachmentReference2KHR &attref2(attRefs2.last());
1724 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1725 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1726 attref2.attachment = attref.attachment;
1727 attref2.layout = attref.layout;
1728 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1730 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1731 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1734 if (subpassDesc.pResolveAttachments) {
1735 startIndex = attRefs2.count();
1736 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1737 attRefs2.append({});
1738 VkAttachmentReference2KHR &attref2(attRefs2.last());
1739 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1740 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1741 attref2.attachment = attref.attachment;
1742 attref2.layout = attref.layout;
1743 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1745 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1749 if (subpassDesc.pDepthStencilAttachment) {
1750 startIndex = attRefs2.count();
1751 attRefs2.append({});
1752 VkAttachmentReference2KHR &attref2(attRefs2.last());
1753 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1754 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1755 attref2.attachment = attref.attachment;
1756 attref2.layout = attref.layout;
1757 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1758 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1762#ifdef VK_KHR_depth_stencil_resolve
1764 if (rpD->hasDepthStencilResolve) {
1765 startIndex = attRefs2.count();
1766 attRefs2.append({});
1767 VkAttachmentReference2KHR &attref2(attRefs2.last());
1768 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1769 attref2.attachment = rpD->dsResolveRef.attachment;
1770 attref2.layout = rpD->dsResolveRef.layout;
1771 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1772 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1773 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1774 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1775 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1776 addToChain(&subpass2, &dsResolveDesc);
1780#ifdef VK_KHR_fragment_shading_rate
1781 shadingRateAttInfo = {};
1782 if (rpD->hasShadingRateMap) {
1783 startIndex = attRefs2.count();
1784 attRefs2.append({});
1785 VkAttachmentReference2KHR &attref2(attRefs2.last());
1786 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1787 attref2.attachment = rpD->shadingRateRef.attachment;
1788 attref2.layout = rpD->shadingRateRef.layout;
1789 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1790 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1791 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1792 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1793 addToChain(&subpass2, &shadingRateAttInfo);
1799 subpassDeps2.clear();
1800 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1801 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1802 subpassDeps2.append({});
1803 VkSubpassDependency2 &dep2(subpassDeps2.last());
1804 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1805 dep2.srcSubpass = dep.srcSubpass;
1806 dep2.dstSubpass = dep.dstSubpass;
1807 dep2.srcStageMask = dep.srcStageMask;
1808 dep2.dstStageMask = dep.dstStageMask;
1809 dep2.srcAccessMask = dep.srcAccessMask;
1810 dep2.dstAccessMask = dep.dstAccessMask;
1811 dep2.dependencyFlags = dep.dependencyFlags;
1814 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1815 rpInfo2->pNext =
nullptr;
1816 rpInfo2->flags = rpInfo->flags;
1817 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1818 rpInfo2->pAttachments = attDescs2.constData();
1819 rpInfo2->subpassCount = 1;
1820 rpInfo2->pSubpasses = &subpass2;
1821 rpInfo2->dependencyCount = subpassDeps2.count();
1822 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1823 if (multiViewCount >= 2) {
1824 rpInfo2->correlatedViewMaskCount = 1;
1825 rpInfo2->pCorrelatedViewMasks = &viewMask;
1831 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1832 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1833 VkSubpassDescription2KHR subpass2;
1834 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1835#ifdef VK_KHR_depth_stencil_resolve
1836 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1838#ifdef VK_KHR_fragment_shading_rate
1839 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1846 VkSubpassDescription *subpassDesc,
1849 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1850 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1851 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1852 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1853 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1854 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1856 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1857 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1858 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1859 rpInfo->pAttachments = rpD->attDescs.constData();
1860 rpInfo->subpassCount = 1;
1861 rpInfo->pSubpasses = subpassDesc;
1862 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1863 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1867 bool hasDepthStencil,
1868 VkSampleCountFlagBits samples,
1869 VkFormat colorFormat,
1870 QRhiShadingRateMap *shadingRateMap)
1874 VkAttachmentDescription attDesc = {};
1875 attDesc.format = colorFormat;
1876 attDesc.samples = samples;
1877 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1878 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1879 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1880 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1881 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1882 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1883 rpD->attDescs.append(attDesc);
1885 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1890 rpD->multiViewCount = 0;
1892 if (hasDepthStencil) {
1896 attDesc.format = optimalDepthStencilFormat();
1897 attDesc.samples = samples;
1898 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1899 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1900 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1901 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1902 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1903 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1904 rpD->attDescs.append(attDesc);
1906 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1911 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1913 attDesc.format = colorFormat;
1914 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1915 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1916 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1917 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1918 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1919 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1920 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1921 rpD->attDescs.append(attDesc);
1923 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1926 rpD->dsResolveRef = {};
1928 rpD->shadingRateRef = {};
1929#ifdef VK_KHR_fragment_shading_rate
1930 if (shadingRateMap) {
1932 attDesc.format = VK_FORMAT_R8_UINT;
1933 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1934 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1935 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1936 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1937 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1938 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1939 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1940 rpD->attDescs.append(attDesc);
1942 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
1947 VkSubpassDependency subpassDep = {};
1948 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1949 subpassDep.dstSubpass = 0;
1950 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1951 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1952 subpassDep.srcAccessMask = 0;
1953 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1954 rpD->subpassDeps.append(subpassDep);
1955 if (hasDepthStencil) {
1956 memset(&subpassDep, 0,
sizeof(subpassDep));
1957 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1958 subpassDep.dstSubpass = 0;
1959 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1960 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1961 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1962 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1963 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1964 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
1965 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1966 rpD->subpassDeps.append(subpassDep);
1969 VkRenderPassCreateInfo rpInfo;
1970 VkSubpassDescription subpassDesc;
1971 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
1973#ifdef VK_KHR_create_renderpass2
1974 if (caps.renderPass2KHR) {
1976 VkRenderPassCreateInfo2KHR rpInfo2;
1977 RenderPass2SetupHelper rp2Helper(
this);
1978 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
1980 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
1981 if (err != VK_SUCCESS) {
1982 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
1989 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
1990 VkResult err = df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
1991 if (err != VK_SUCCESS) {
1992 qWarning(
"Failed to create renderpass: %d", err);
2001 const QRhiColorAttachment *colorAttachmentsBegin,
2002 const QRhiColorAttachment *colorAttachmentsEnd,
2006 QRhiRenderBuffer *depthStencilBuffer,
2007 QRhiTexture *depthTexture,
2008 QRhiTexture *depthResolveTexture,
2009 QRhiShadingRateMap *shadingRateMap)
2013 int multiViewCount = 0;
2014 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2017 Q_ASSERT(texD || rbD);
2018 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2019 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2021 VkAttachmentDescription attDesc = {};
2022 attDesc.format = vkformat;
2023 attDesc.samples = samples;
2024 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2025 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2026 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2027 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2029 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2030 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2031 rpD->attDescs.append(attDesc);
2033 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2034 rpD->colorRefs.append(ref);
2036 if (it->multiViewCount() >= 2) {
2037 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2038 qWarning(
"Inconsistent multiViewCount in color attachment set");
2040 multiViewCount = it->multiViewCount();
2041 }
else if (multiViewCount > 0) {
2042 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2045 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2046 rpD->multiViewCount = uint32_t(multiViewCount);
2050 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2051 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2052 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2053 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2054 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2055 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2056 VkAttachmentDescription attDesc = {};
2057 attDesc.format = dsFormat;
2058 attDesc.samples = samples;
2059 attDesc.loadOp = loadOp;
2060 attDesc.storeOp = storeOp;
2061 attDesc.stencilLoadOp = loadOp;
2062 attDesc.stencilStoreOp = storeOp;
2063 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2064 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2065 rpD->attDescs.append(attDesc);
2066 if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
2067 multiViewCount = depthTexture->arraySize();
2068 rpD->multiViewCount = multiViewCount;
2070 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2075 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2076 if (it->resolveTexture()) {
2078 const VkFormat dstFormat = rtexD->vkformat;
2079 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2080 qWarning(
"Resolving into a multisample texture is not supported");
2084 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2085 if (srcFormat != dstFormat) {
2089 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2090 int(srcFormat),
int(dstFormat));
2093 VkAttachmentDescription attDesc = {};
2094 attDesc.format = rtexD->viewFormat;
2095 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2096 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2097 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2098 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2099 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2100 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2101 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2102 rpD->attDescs.append(attDesc);
2104 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2105 rpD->resolveRefs.append(ref);
2107 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2108 rpD->resolveRefs.append(ref);
2111 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2116 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2117 qWarning(
"Resolving into a multisample depth texture is not supported");
2120 if (texD->vkformat != rtexD->vkformat) {
2121 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2122 int(texD->vkformat),
int(rtexD->vkformat));
2125 VkAttachmentDescription attDesc = {};
2126 attDesc.format = rtexD->viewFormat;
2127 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2128 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2129 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2130 attDesc.stencilLoadOp = attDesc.loadOp;
2131 attDesc.stencilStoreOp = attDesc.storeOp;
2132 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2133 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2134 rpD->attDescs.append(attDesc);
2135 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2137 rpD->dsResolveRef = {};
2141 rpD->shadingRateRef = {};
2142#ifdef VK_KHR_fragment_shading_rate
2143 if (shadingRateMap) {
2144 VkAttachmentDescription attDesc = {};
2145 attDesc.format = VK_FORMAT_R8_UINT;
2146 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2147 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2148 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2149 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2150 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2151 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2152 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2153 rpD->attDescs.append(attDesc);
2154 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2163 VkRenderPassCreateInfo rpInfo;
2164 VkSubpassDescription subpassDesc;
2165 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2168 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2171#ifdef VK_KHR_create_renderpass2
2172 if (caps.renderPass2KHR) {
2174 VkRenderPassCreateInfo2KHR rpInfo2;
2175 RenderPass2SetupHelper rp2Helper(
this);
2176 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2179 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2180 if (err != VK_SUCCESS) {
2181 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2188 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2189 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2192 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2193 VkResult err = df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2194 if (err != VK_SUCCESS) {
2195 qWarning(
"Failed to create renderpass: %d", err);
2206 if (swapChainD->pixelSize.isEmpty()) {
2207 qWarning(
"Surface size is 0, cannot create swapchain");
2211 df->vkDeviceWaitIdle(dev);
2213 if (!vkCreateSwapchainKHR) {
2214 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2215 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2216 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2217 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2218 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2219 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2220 qWarning(
"Swapchain functions not available");
2225 VkSurfaceCapabilitiesKHR surfaceCaps;
2226 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2227 quint32 reqBufferCount;
2228 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2229 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2231 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2233 VkSurfaceTransformFlagBitsKHR preTransform =
2234 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2235 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2236 : surfaceCaps.currentTransform;
2262 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2263 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2264 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2265 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2267 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2268 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2269 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2270 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2271 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2272 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2273 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2274 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2275 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2276 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2279 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2280 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2281 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2282 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2284 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2285 && surfaceCaps.maxImageArrayLayers > 1;
2288 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2289 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2293 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2294 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2295 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2296 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2304 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2306 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2307 reuseExisting ?
"recycled" :
"new",
2308 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2310 VkSwapchainCreateInfoKHR swapChainInfo = {};
2311 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2312 swapChainInfo.surface = swapChainD->surface;
2313 swapChainInfo.minImageCount = reqBufferCount;
2314 swapChainInfo.imageFormat = swapChainD->colorFormat;
2315 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2316 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2317 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2318 swapChainInfo.imageUsage = usage;
2319 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2320 swapChainInfo.preTransform = preTransform;
2321 swapChainInfo.compositeAlpha = compositeAlpha;
2322 swapChainInfo.presentMode = presentMode;
2323 swapChainInfo.clipped =
true;
2324 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2326 VkSwapchainKHR newSwapChain;
2327 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2328 if (err != VK_SUCCESS) {
2329 qWarning(
"Failed to create swapchain: %d", err);
2336 swapChainD->sc = newSwapChain;
2337 swapChainD->lastConnectedSurface = swapChainD->surface;
2339 quint32 actualSwapChainBufferCount = 0;
2340 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2341 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2342 qWarning(
"Failed to get swapchain images: %d", err);
2346 if (actualSwapChainBufferCount != reqBufferCount)
2347 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2350 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2351 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2352 if (err != VK_SUCCESS) {
2353 qWarning(
"Failed to get swapchain images: %d", err);
2357 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2358 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2359 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2360 if (!createTransientImage(swapChainD->colorFormat,
2361 swapChainD->pixelSize,
2362 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2363 VK_IMAGE_ASPECT_COLOR_BIT,
2364 swapChainD->samples,
2365 &swapChainD->msaaImageMem,
2368 swapChainD->bufferCount))
2370 qWarning(
"Failed to create transient image for MSAA color buffer");
2375 VkFenceCreateInfo fenceInfo = {};
2376 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2377 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2380 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2384 image.image = swapChainImages[i];
2385 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2386 image.msaaImage = msaaImages[i];
2387 image.msaaImageView = msaaViews[i];
2390 VkImageViewCreateInfo imgViewInfo = {};
2391 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2392 imgViewInfo.image = swapChainImages[i];
2393 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2394 imgViewInfo.format = swapChainD->colorFormat;
2395 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2396 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2397 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2398 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2399 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2400 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2401 err = df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2402 if (err != VK_SUCCESS) {
2403 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2409 VkSemaphoreCreateInfo semInfo = {};
2410 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2411 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2416 image.image = swapChainImages[i];
2417 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2418 image.msaaImage = msaaImages[i];
2419 image.msaaImageView = msaaViews[i];
2422 VkImageViewCreateInfo imgViewInfo = {};
2423 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2424 imgViewInfo.image = swapChainImages[i];
2425 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2426 imgViewInfo.format = swapChainD->colorFormat;
2427 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2428 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2429 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2430 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2431 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2432 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2433 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2434 err = df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2435 if (err != VK_SUCCESS) {
2436 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2440 VkSemaphoreCreateInfo semInfo = {};
2441 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2442 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2448 swapChainD->currentImageIndex = 0;
2450 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2452 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2453 VkImageViewCreateInfo viewInfo = {};
2454 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2455 viewInfo.image = texD->image;
2456 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2457 viewInfo.format = texD->viewFormat;
2458 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2459 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2460 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2461 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2462 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2463 viewInfo.subresourceRange.baseMipLevel = 0;
2464 viewInfo.subresourceRange.levelCount = 1;
2465 viewInfo.subresourceRange.baseArrayLayer = 0;
2466 viewInfo.subresourceRange.layerCount = 1;
2467 VkResult err = df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2468 if (err != VK_SUCCESS) {
2469 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2474 VkSemaphoreCreateInfo semInfo = {};
2475 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2483 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2485 err = df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2486 if (err != VK_SUCCESS) {
2487 qWarning(
"Failed to create command buffer fence: %d", err);
2493 swapChainD->currentFrameSlot = 0;
2502 if (swapChainD->sc == VK_NULL_HANDLE)
2506 df->vkDeviceWaitIdle(dev);
2510 if (frame.cmdFence) {
2511 if (!deviceLost && frame.cmdFenceWaitable)
2512 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2513 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2514 frame.cmdFence = VK_NULL_HANDLE;
2517 if (frame.imageSem) {
2518 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2519 frame.imageSem = VK_NULL_HANDLE;
2526 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2527 image.fb = VK_NULL_HANDLE;
2529 if (image.imageView) {
2530 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2531 image.imageView = VK_NULL_HANDLE;
2533 if (image.msaaImageView) {
2534 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2535 image.msaaImageView = VK_NULL_HANDLE;
2537 if (image.msaaImage) {
2538 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2539 image.msaaImage = VK_NULL_HANDLE;
2541 if (image.drawSem) {
2542 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2543 image.drawSem = VK_NULL_HANDLE;
2547 if (swapChainD->msaaImageMem) {
2548 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2549 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2552 if (swapChainD->shadingRateMapView) {
2553 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2554 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2557 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2558 swapChainD->sc = VK_NULL_HANDLE;
2565 VkCommandPoolResetFlags flags = 0;
2570 if (releaseCachedResourcesCalledBeforeFrameStart)
2571 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2574 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2580 for (quint64 i = 0; i < timestampValidBits; i += 8)
2581 mask |= 0xFFULL << i;
2582 const quint64 ts0 = timestamp[0] & mask;
2583 const quint64 ts1 = timestamp[1] & mask;
2584 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2585 if (!qFuzzyIsNull(nsecsPerTick)) {
2586 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2587 const double elapsedSec = elapsedMs / 1000.0;
2598 const int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2601 inst->handle()->beginFrame(swapChainD->window);
2611 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2612 if (waitResult != QRhi::FrameOpSuccess)
2617 uint32_t imageIndex = 0;
2618 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2619 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2621 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2622 swapChainD->currentImageIndex = imageIndex;
2625 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2626 return QRhi::FrameOpSwapChainOutOfDate;
2628 if (err == VK_ERROR_DEVICE_LOST) {
2629 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2631 return QRhi::FrameOpDeviceLost;
2633 qWarning(
"Failed to acquire next swapchain image: %d", err);
2634 return QRhi::FrameOpError;
2638 currentFrameSlot =
int(swapChainD->currentFrameSlot);
2641 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2647 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2648 if (cbres != QRhi::FrameOpSuccess)
2651 swapChainD->cbWrapper.cb = frame.cmdBuf;
2654 swapChainD->rtWrapper.d.fb = image.fb;
2658 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2659 swapChainD->rtWrapperRight.d.fb = image.fb;
2666 quint64 timestamp[2] = { 0, 0 };
2667 VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame.timestampQueryIndex), 2,
2668 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2669 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2670 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2672 if (err == VK_SUCCESS) {
2674 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2676 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2678 qWarning(
"Failed to query timestamp: %d", err);
2683 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2684 int timestampQueryIdx = -1;
2685 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2686 if (!timestampQueryPoolMap.testBit(i)) {
2687 timestampQueryPoolMap.setBit(i);
2688 timestampQueryIdx = i * 2;
2692 if (timestampQueryIdx >= 0) {
2693 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2695 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2696 timestampQueryPool, uint32_t(timestampQueryIdx));
2701 return QRhi::FrameOpSuccess;
2709 auto cleanup = qScopeGuard([
this, swapChainD] {
2710 inst->handle()->endFrame(swapChainD->window);
2715 int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2720 VkImageMemoryBarrier presTrans = {};
2721 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2722 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2723 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2724 presTrans.image = image.image;
2725 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2726 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2730 presTrans.srcAccessMask = 0;
2731 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2732 df->vkCmdPipelineBarrier(frame.cmdBuf,
2733 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2734 0, 0,
nullptr, 0,
nullptr,
2738 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2739 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2740 df->vkCmdPipelineBarrier(frame.cmdBuf,
2741 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2742 0, 0,
nullptr, 0,
nullptr,
2750 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2751 timestampQueryPool, uint32_t(frame.timestampQueryIndex + 1));
2756 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2757 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2759 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2760 needsPresent ? &image.drawSem :
nullptr);
2761 if (submitres != QRhi::FrameOpSuccess)
2769 VkPresentInfoKHR presInfo = {};
2770 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2771 presInfo.swapchainCount = 1;
2772 presInfo.pSwapchains = &swapChainD->sc;
2773 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2774 waitSemaphoresForPresent.append(image.drawSem);
2775 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2776 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2780 inst->presentAboutToBeQueued(swapChainD->window);
2782 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2783 waitSemaphoresForPresent.clear();
2784 if (err != VK_SUCCESS) {
2785 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2786 return QRhi::FrameOpSwapChainOutOfDate;
2787 }
else if (err != VK_SUBOPTIMAL_KHR) {
2788 if (err == VK_ERROR_DEVICE_LOST) {
2789 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2791 return QRhi::FrameOpDeviceLost;
2793 qWarning(
"Failed to present: %d", err);
2794 return QRhi::FrameOpError;
2800 inst->presentQueued(swapChainD->window);
2810 return QRhi::FrameOpSuccess;
2829 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2839 VkCommandBufferAllocateInfo cmdBufInfo = {};
2840 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2841 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2842 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2843 cmdBufInfo.commandBufferCount = 1;
2845 VkResult err = df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2846 if (err != VK_SUCCESS) {
2847 if (err == VK_ERROR_DEVICE_LOST) {
2848 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2850 return QRhi::FrameOpDeviceLost;
2852 qWarning(
"Failed to allocate frame command buffer: %d", err);
2853 return QRhi::FrameOpError;
2857 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2858 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2860 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2861 if (err != VK_SUCCESS) {
2862 if (err == VK_ERROR_DEVICE_LOST) {
2863 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2865 return QRhi::FrameOpDeviceLost;
2867 qWarning(
"Failed to begin frame command buffer: %d", err);
2868 return QRhi::FrameOpError;
2871 return QRhi::FrameOpSuccess;
2875 VkSemaphore *waitSem, VkSemaphore *signalSem)
2877 VkResult err =
df->vkEndCommandBuffer(cb);
2878 if (err != VK_SUCCESS) {
2879 if (err == VK_ERROR_DEVICE_LOST) {
2880 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2882 return QRhi::FrameOpDeviceLost;
2884 qWarning(
"Failed to end frame command buffer: %d", err);
2885 return QRhi::FrameOpError;
2888 VkSubmitInfo submitInfo = {};
2889 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2890 submitInfo.commandBufferCount = 1;
2891 submitInfo.pCommandBuffers = &cb;
2894 waitSemaphoresForQueueSubmit.append(*waitSem);
2896 signalSemaphoresForQueueSubmit.append(*signalSem);
2898 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2899 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2900 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2901 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2902 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2904 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
2905 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
2906 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
2909 err = df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
2911 waitSemaphoresForQueueSubmit.clear();
2912 signalSemaphoresForQueueSubmit.clear();
2914 if (err != VK_SUCCESS) {
2915 if (err == VK_ERROR_DEVICE_LOST) {
2916 qWarning(
"Device loss detected in vkQueueSubmit()");
2918 return QRhi::FrameOpDeviceLost;
2920 qWarning(
"Failed to submit to graphics queue: %d", err);
2921 return QRhi::FrameOpError;
2924 return QRhi::FrameOpSuccess;
2929 for (QVkSwapChain *sc : std::as_const(swapchains)) {
2930 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
2931 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
2932 if (frame.cmdFenceWaitable) {
2933 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2935 if (err != VK_SUCCESS) {
2936 if (err == VK_ERROR_DEVICE_LOST) {
2937 qWarning(
"Device loss detected in vkWaitForFences()");
2939 return QRhi::FrameOpDeviceLost;
2941 qWarning(
"Failed to wait for fence: %d", err);
2942 return QRhi::FrameOpError;
2945 df->vkResetFences(dev, 1, &frame.cmdFence);
2946 frame.cmdFenceWaitable =
false;
2950 return QRhi::FrameOpSuccess;
2964 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
2966 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
2967 if (waitResult != QRhi::FrameOpSuccess)
2973 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
2974 if (cbres != QRhi::FrameOpSuccess)
2980 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
2981 int timestampQueryIdx = -1;
2982 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2983 if (!timestampQueryPoolMap.testBit(i)) {
2984 timestampQueryPoolMap.setBit(i);
2985 timestampQueryIdx = i * 2;
2989 if (timestampQueryIdx >= 0) {
2990 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2992 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2993 timestampQueryPool, uint32_t(timestampQueryIdx));
2994 ofr.timestampQueryIndex = timestampQueryIdx;
2999 return QRhi::FrameOpSuccess;
3005 Q_ASSERT(ofr.active);
3012 if (ofr.timestampQueryIndex >= 0) {
3013 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3014 timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
3017 if (!ofr.cmdFence) {
3018 VkFenceCreateInfo fenceInfo = {};
3019 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3020 VkResult err = df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence);
3021 if (err != VK_SUCCESS) {
3022 qWarning(
"Failed to create command buffer fence: %d", err);
3023 return QRhi::FrameOpError;
3027 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence,
nullptr,
nullptr);
3028 if (submitres != QRhi::FrameOpSuccess)
3032 df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
3033 df->vkResetFences(dev, 1, &ofr.cmdFence);
3040 if (ofr.timestampQueryIndex >= 0) {
3041 quint64 timestamp[2] = { 0, 0 };
3042 VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
3043 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3044 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3045 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
3046 ofr.timestampQueryIndex = -1;
3047 if (err == VK_SUCCESS) {
3049 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3053 qWarning(
"Failed to query timestamp: %d", err);
3057 return QRhi::FrameOpSuccess;
3079 swapChainD->cbWrapper.resetCommands();
3080 cb = swapChainD->cbWrapper.cb;
3082 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3083 if (submitres != QRhi::FrameOpSuccess)
3087 df->vkQueueWaitIdle(gfxQueue);
3094 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3097 startPrimaryCommandBuffer(&frame.cmdBuf);
3098 swapChainD->cbWrapper.cb = frame.cmdBuf;
3105 return QRhi::FrameOpSuccess;
3112 u
.access =
int(bufUsage.access);
3113 u
.stage =
int(bufUsage.stage);
3121 u
.access =
int(texUsage.access);
3122 u
.stage =
int(texUsage.stage);
3128 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3131 rtD->lastActiveFrameSlot = currentFrameSlot;
3132 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3134 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3142 texD->lastActiveFrameSlot = currentFrameSlot;
3147 rbD->lastActiveFrameSlot = currentFrameSlot;
3153 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3156 if (rtD->m_desc.depthStencilBuffer()) {
3158 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3165 rbD->lastActiveFrameSlot = currentFrameSlot;
3167 if (rtD->m_desc.depthTexture()) {
3172 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3174 if (rtD->m_desc.depthResolveTexture()) {
3179 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3181 if (rtD->m_desc.shadingRateMap()) {
3186 texD->lastActiveFrameSlot = currentFrameSlot;
3200 VkCommandBuffer secondaryCb;
3202 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3203 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3204 freeSecondaryCbs[currentFrameSlot].removeLast();
3206 VkCommandBufferAllocateInfo cmdBufInfo = {};
3207 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3208 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3209 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3210 cmdBufInfo.commandBufferCount = 1;
3212 VkResult err = df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3213 if (err != VK_SUCCESS) {
3214 qWarning(
"Failed to create secondary command buffer: %d", err);
3215 return VK_NULL_HANDLE;
3219 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3220 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3221 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3222 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3223 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3224 cmdBufInheritInfo.subpass = 0;
3226 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3227 cmdBufInheritInfo.framebuffer = rtD->fb;
3229 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3231 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3232 if (err != VK_SUCCESS) {
3233 qWarning(
"Failed to begin secondary command buffer: %d", err);
3234 return VK_NULL_HANDLE;
3242 VkResult err =
df->vkEndCommandBuffer(cb);
3243 if (err != VK_SUCCESS)
3244 qWarning(
"Failed to end secondary command buffer: %d", err);
3248 cmd.args.executeSecondary.cb = cb;
3252 e.lastActiveFrameSlot = currentFrameSlot;
3253 e.secondaryCommandBuffer.cb = cb;
3254 releaseQueue.append(e);
3258 QRhiRenderTarget *rt,
3259 const QColor &colorClearValue,
3260 const QRhiDepthStencilClearValue &depthStencilClearValue,
3261 QRhiResourceUpdateBatch *resourceUpdates,
3262 QRhiCommandBuffer::BeginPassFlags flags)
3267 if (resourceUpdates)
3277 switch (rt->resourceType()) {
3278 case QRhiResource::SwapChainRenderTarget:
3280 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3290 texD->lastActiveFrameSlot = currentFrameSlot;
3293 case QRhiResource::TextureRenderTarget:
3306 cbD->passUsesSecondaryCb = flags.testFlag(QRhiCommandBuffer::ExternalContent);
3307 cbD->currentTarget = rt;
3312 VkRenderPassBeginInfo rpBeginInfo = {};
3313 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3314 rpBeginInfo.renderPass = rtD
->rp->rp;
3315 rpBeginInfo.framebuffer = rtD->fb;
3316 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3317 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3319 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3322 cv.color = { {
float(colorClearValue.redF()),
float(colorClearValue.greenF()),
float(colorClearValue.blueF()),
3323 float(colorClearValue.alphaF()) } };
3328 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3333 cv.color = { {
float(colorClearValue.redF()),
float(colorClearValue.greenF()),
float(colorClearValue.blueF()),
3334 float(colorClearValue.alphaF()) } };
3339 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3344 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3347 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3351 cmd.args.beginRenderPass.desc = rpBeginInfo;
3352 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3354 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3356 if (cbD->passUsesSecondaryCb)
3357 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3362 rateCmd.args.setShadingRate.w = 1;
3363 rateCmd.args.setShadingRate.h = 1;
3375 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3376 cbD->activeSecondaryCbStack.removeLast();
3377 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3384 cbD->currentTarget =
nullptr;
3386 if (resourceUpdates)
3391 QRhiResourceUpdateBatch *resourceUpdates,
3392 QRhiCommandBuffer::BeginPassFlags flags)
3397 if (resourceUpdates)
3403 cbD->passUsesSecondaryCb = flags.testFlag(QRhiCommandBuffer::ExternalContent);
3405 cbD->computePassState.reset();
3407 if (cbD->passUsesSecondaryCb)
3408 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3419 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3420 cbD->activeSecondaryCbStack.removeLast();
3421 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3426 if (resourceUpdates)
3433 Q_ASSERT(psD->pipeline);
3437 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3439 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3443 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3444 cmd.args.bindPipeline.pipeline = psD->pipeline;
3447 cbD->currentGraphicsPipeline =
nullptr;
3448 cbD->currentComputePipeline = ps;
3449 cbD->currentPipelineGeneration = psD->generation;
3452 psD->lastActiveFrameSlot = currentFrameSlot;
3457 QRhiShaderResourceBinding::Type bindingType,
3458 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3460 VkAccessFlags access = 0;
3461 if (bindingType == loadTypeVal) {
3462 access = VK_ACCESS_SHADER_READ_BIT;
3464 access = VK_ACCESS_SHADER_WRITE_BIT;
3465 if (bindingType == loadStoreTypeVal)
3466 access |= VK_ACCESS_SHADER_READ_BIT;
3468 auto it = writtenResources->find(resource);
3469 if (it != writtenResources->end())
3470 it->first |= access;
3471 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3472 writtenResources->insert(resource, { access,
true });
3482 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3483 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3484 if (cbD->currentComputeSrb) {
3488 for (
auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
3489 accessAndIsNewFlag = { 0,
false };
3492 const int bindingCount = srbD->m_bindings.size();
3493 for (
int i = 0; i < bindingCount; ++i) {
3494 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings.at(i));
3496 case QRhiShaderResourceBinding::ImageLoad:
3497 case QRhiShaderResourceBinding::ImageStore:
3498 case QRhiShaderResourceBinding::ImageLoadStore:
3499 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3502 QRhiShaderResourceBinding::ImageLoad,
3503 QRhiShaderResourceBinding::ImageStore,
3504 QRhiShaderResourceBinding::ImageLoadStore);
3506 case QRhiShaderResourceBinding::BufferLoad:
3507 case QRhiShaderResourceBinding::BufferStore:
3508 case QRhiShaderResourceBinding::BufferLoadStore:
3509 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3512 QRhiShaderResourceBinding::BufferLoad,
3513 QRhiShaderResourceBinding::BufferStore,
3514 QRhiShaderResourceBinding::BufferLoadStore);
3521 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3522 const int accessInThisDispatch = it->first;
3523 const bool isNewInThisDispatch = it->second;
3524 if (accessInThisDispatch && !isNewInThisDispatch) {
3525 if (it.key()->resourceType() == QRhiResource::Texture) {
3527 VkImageMemoryBarrier barrier = {};
3528 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3529 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3531 barrier.subresourceRange.baseMipLevel = 0;
3532 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3533 barrier.subresourceRange.baseArrayLayer = 0;
3534 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3535 barrier.oldLayout = texD->usageState.layout;
3536 barrier.newLayout = texD->usageState.layout;
3537 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3538 barrier.dstAccessMask = accessInThisDispatch;
3539 barrier.image = texD->image;
3540 imageBarriers.append(barrier);
3543 VkBufferMemoryBarrier barrier = {};
3544 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3545 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3546 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3547 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3548 barrier.dstAccessMask = accessInThisDispatch;
3549 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3550 barrier.size = VK_WHOLE_SIZE;
3551 bufferBarriers.append(barrier);
3557 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3558 it = cbD->computePassState.writtenResources.erase(it);
3565 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3566 if (!imageBarriers.isEmpty()) {
3567 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3570 imageBarriers.size(), imageBarriers.constData());
3572 if (!bufferBarriers.isEmpty()) {
3573 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3575 bufferBarriers.size(), bufferBarriers.constData(),
3578 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3580 if (!imageBarriers.isEmpty()) {
3583 cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3584 cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3585 cmd.args.imageBarrier.count = imageBarriers.size();
3586 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3587 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3589 if (!bufferBarriers.isEmpty()) {
3592 cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3593 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3594 cmd.args.bufferBarrier.count = bufferBarriers.size();
3595 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3596 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3600 cmd.args.dispatch.x = x;
3601 cmd.args.dispatch.y = y;
3602 cmd.args.dispatch.z = z;
3608 VkShaderModuleCreateInfo shaderInfo = {};
3609 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3610 shaderInfo.codeSize = size_t(spirv.size());
3611 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3612 VkShaderModule shaderModule;
3613 VkResult err = df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3614 if (err != VK_SUCCESS) {
3615 qWarning(
"Failed to create shader module: %d", err);
3616 return VK_NULL_HANDLE;
3618 return shaderModule;
3626 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3627 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3628 pipelineCacheInfo.initialDataSize = initialDataSize;
3629 pipelineCacheInfo.pInitialData = initialData;
3630 VkResult err = df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3631 if (err != VK_SUCCESS) {
3632 qWarning(
"Failed to create pipeline cache: %d", err);
3642 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3643 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3644 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3645 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3646 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3648 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3649 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3652 VkWriteDescriptorSet writeInfo = {};
3653 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3654 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3655 writeInfo.dstBinding = uint32_t(b->binding);
3656 writeInfo.descriptorCount = 1;
3658 int bufferInfoIndex = -1;
3659 int imageInfoIndex = -1;
3662 case QRhiShaderResourceBinding::UniformBuffer:
3664 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3665 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3666 QRhiBuffer *buf = b->u.ubuf.buf;
3668 bd.ubuf.id = bufD->m_id;
3669 bd.ubuf.generation = bufD->generation;
3670 VkDescriptorBufferInfo bufInfo;
3671 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3672 bufInfo.offset = b->u.ubuf.offset;
3673 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3675 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3676 bufferInfoIndex = bufferInfos.size();
3677 bufferInfos.append(bufInfo);
3680 case QRhiShaderResourceBinding::SampledTexture:
3682 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3683 writeInfo.descriptorCount = data->count;
3684 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3685 ArrayOfImageDesc imageInfo(data->count);
3686 for (
int elem = 0; elem < data->count; ++elem) {
3689 bd.stex.d[elem].texId = texD->m_id;
3690 bd.stex.d[elem].texGeneration = texD->generation;
3691 bd.stex.d[elem].samplerId = samplerD->m_id;
3692 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3693 imageInfo[elem].sampler = samplerD->sampler;
3694 imageInfo[elem].imageView = texD->imageView;
3695 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3697 bd.stex.count = data->count;
3698 imageInfoIndex = imageInfos.size();
3699 imageInfos.append(imageInfo);
3702 case QRhiShaderResourceBinding::Texture:
3704 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3705 writeInfo.descriptorCount = data->count;
3706 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3707 ArrayOfImageDesc imageInfo(data->count);
3708 for (
int elem = 0; elem < data->count; ++elem) {
3710 bd.stex.d[elem].texId = texD->m_id;
3711 bd.stex.d[elem].texGeneration = texD->generation;
3712 bd.stex.d[elem].samplerId = 0;
3713 bd.stex.d[elem].samplerGeneration = 0;
3714 imageInfo[elem].sampler = VK_NULL_HANDLE;
3715 imageInfo[elem].imageView = texD->imageView;
3716 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3718 bd.stex.count = data->count;
3719 imageInfoIndex = imageInfos.size();
3720 imageInfos.append(imageInfo);
3723 case QRhiShaderResourceBinding::Sampler:
3726 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3727 bd.stex.d[0].texId = 0;
3728 bd.stex.d[0].texGeneration = 0;
3729 bd.stex.d[0].samplerId = samplerD->m_id;
3730 bd.stex.d[0].samplerGeneration = samplerD->generation;
3731 ArrayOfImageDesc imageInfo(1);
3732 imageInfo[0].sampler = samplerD->sampler;
3733 imageInfo[0].imageView = VK_NULL_HANDLE;
3734 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3735 imageInfoIndex = imageInfos.size();
3736 imageInfos.append(imageInfo);
3739 case QRhiShaderResourceBinding::ImageLoad:
3740 case QRhiShaderResourceBinding::ImageStore:
3741 case QRhiShaderResourceBinding::ImageLoadStore:
3744 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3746 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3747 bd.simage.id = texD->m_id;
3748 bd.simage.generation = texD->generation;
3749 ArrayOfImageDesc imageInfo(1);
3750 imageInfo[0].sampler = VK_NULL_HANDLE;
3751 imageInfo[0].imageView = view;
3752 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3753 imageInfoIndex = imageInfos.size();
3754 imageInfos.append(imageInfo);
3758 case QRhiShaderResourceBinding::BufferLoad:
3759 case QRhiShaderResourceBinding::BufferStore:
3760 case QRhiShaderResourceBinding::BufferLoadStore:
3763 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3764 bd.sbuf.id = bufD->m_id;
3765 bd.sbuf.generation = bufD->generation;
3766 VkDescriptorBufferInfo bufInfo;
3767 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3768 bufInfo.offset = b->u.sbuf.offset;
3769 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3770 bufferInfoIndex = bufferInfos.size();
3771 bufferInfos.append(bufInfo);
3778 writeInfos.append(writeInfo);
3779 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3782 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3783 const int bufferInfoIndex = infoIndices[i].first;
3784 const int imageInfoIndex = infoIndices[i].second;
3785 if (bufferInfoIndex >= 0)
3786 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3787 else if (imageInfoIndex >= 0)
3788 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3791 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3796 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3797 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3798 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3799 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3800 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3801 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3805 VkAccessFlags access, VkPipelineStageFlags stage)
3808 Q_ASSERT(access && stage);
3816 if (s.access == access && s.stage == stage) {
3819 if (!accessIsWrite(access))
3823 VkBufferMemoryBarrier bufMemBarrier = {};
3824 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3825 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3826 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3827 bufMemBarrier.srcAccessMask = s.access;
3828 bufMemBarrier.dstAccessMask = access;
3829 bufMemBarrier.buffer = bufD->buffers[slot];
3830 bufMemBarrier.size = VK_WHOLE_SIZE;
3834 cmd.args.bufferBarrier.srcStageMask = s.stage;
3835 cmd.args.bufferBarrier.dstStageMask = stage;
3836 cmd.args.bufferBarrier.count = 1;
3837 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3838 cbD->pools.bufferBarrier.append(bufMemBarrier);
3845 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3848 Q_ASSERT(layout && access && stage);
3850 if (s.access == access && s.stage == stage && s.layout == layout) {
3851 if (!accessIsWrite(access))
3855 VkImageMemoryBarrier barrier = {};
3856 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3857 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3858 barrier.subresourceRange.baseMipLevel = 0;
3859 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3860 barrier.subresourceRange.baseArrayLayer = 0;
3861 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3862 barrier.oldLayout = s.layout;
3863 barrier.newLayout = layout;
3864 barrier.srcAccessMask = s.access;
3865 barrier.dstAccessMask = access;
3866 barrier.image = texD->image;
3868 VkPipelineStageFlags srcStage = s.stage;
3871 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3875 cmd.args.imageBarrier.srcStageMask = srcStage;
3876 cmd.args.imageBarrier.dstStageMask = stage;
3877 cmd.args.imageBarrier.count = 1;
3878 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3879 cbD->pools.imageBarrier.append(barrier);
3890 VkImageMemoryBarrier barrier = {};
3891 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3892 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
3893 barrier.subresourceRange.baseMipLevel = 0;
3894 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3895 barrier.subresourceRange.baseArrayLayer = 0;
3896 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3897 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3898 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
3899 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3900 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
3901 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3902 barrier.image = rbD->image;
3904 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
3905 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
3909 cmd.args.imageBarrier.srcStageMask = stages;
3910 cmd.args.imageBarrier.dstStageMask = stages;
3911 cmd.args.imageBarrier.count = 1;
3912 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3913 cbD->pools.imageBarrier.append(barrier);
3917 VkImageLayout oldLayout, VkImageLayout newLayout,
3918 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
3919 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
3920 int startLayer,
int layerCount,
3921 int startLevel,
int levelCount)
3924 VkImageMemoryBarrier barrier = {};
3925 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3926 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3927 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
3928 barrier.subresourceRange.levelCount = uint32_t(levelCount);
3929 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
3930 barrier.subresourceRange.layerCount = uint32_t(layerCount);
3931 barrier.oldLayout = oldLayout;
3932 barrier.newLayout = newLayout;
3933 barrier.srcAccessMask = srcAccess;
3934 barrier.dstAccessMask = dstAccess;
3935 barrier.image = image;
3939 cmd.args.imageBarrier.srcStageMask = srcStage;
3940 cmd.args.imageBarrier.dstStageMask = dstStage;
3941 cmd.args.imageBarrier.count = 1;
3942 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3943 cbD->pools.imageBarrier.append(barrier);
3948 VkDeviceSize size = 0;
3949 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
3950 subresDesc.data().size() : subresDesc.image().sizeInBytes();
3951 if (imageSizeBytes > 0)
3952 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
3957 const QRhiTextureSubresourceUploadDescription &subresDesc,
3958 size_t *curOfs,
void *mp,
3959 BufferImageCopyList *copyInfos)
3961 qsizetype copySizeBytes = 0;
3962 qsizetype imageSizeBytes = 0;
3963 const void *src =
nullptr;
3964 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3965 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
3967 VkBufferImageCopy copyInfo = {};
3968 copyInfo.bufferOffset = *curOfs;
3969 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3970 copyInfo.imageSubresource.mipLevel = uint32_t(level);
3971 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
3972 copyInfo.imageSubresource.layerCount = 1;
3973 copyInfo.imageExtent.depth = 1;
3975 copyInfo.imageOffset.z = uint32_t(layer);
3977 copyInfo.imageOffset.y = uint32_t(layer);
3979 const QByteArray rawData = subresDesc.data();
3980 const QPoint dp = subresDesc.destinationTopLeft();
3981 QImage image = subresDesc.image();
3982 if (!image.isNull()) {
3983 copySizeBytes = imageSizeBytes = image.sizeInBytes();
3984 QSize size = image.size();
3985 src = image.constBits();
3988 int bpc = qMax(1, image.depth() / 8);
3990 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
3991 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
3992 const int sx = subresDesc.sourceTopLeft().x();
3993 const int sy = subresDesc.sourceTopLeft().y();
3994 if (!subresDesc.sourceSize().isEmpty())
3995 size = subresDesc.sourceSize();
3997 if (size.width() == image.width()) {
4000 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4001 copySizeBytes = size.height() * image.bytesPerLine();
4003 image = image.copy(sx, sy, size.width(), size.height());
4004 src = image.constBits();
4007 copySizeBytes = image.sizeInBytes();
4008 bpc = qMax(1, image.depth() / 8);
4009 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4012 copyInfo.imageOffset.x = dp.x();
4013 copyInfo.imageOffset.y = dp.y();
4014 copyInfo.imageExtent.width = uint32_t(size.width());
4015 copyInfo.imageExtent.height = uint32_t(size.height());
4016 copyInfos->append(copyInfo);
4017 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4018 copySizeBytes = imageSizeBytes = rawData.size();
4019 src = rawData.constData();
4020 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4021 const int subresw = size.width();
4022 const int subresh = size.height();
4023 if (!subresDesc.sourceSize().isEmpty())
4024 size = subresDesc.sourceSize();
4025 const int w = size.width();
4026 const int h = size.height();
4028 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4030 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4031 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4034 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4035 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4036 copyInfos->append(copyInfo);
4037 }
else if (!rawData.isEmpty()) {
4038 copySizeBytes = imageSizeBytes = rawData.size();
4039 src = rawData.constData();
4040 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4041 if (subresDesc.dataStride()) {
4042 quint32 bytesPerPixel = 0;
4043 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4045 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4047 if (!subresDesc.sourceSize().isEmpty())
4048 size = subresDesc.sourceSize();
4049 copyInfo.imageOffset.x = dp.x();
4050 copyInfo.imageOffset.y = dp.y();
4051 copyInfo.imageExtent.width = uint32_t(size.width());
4052 copyInfo.imageExtent.height = uint32_t(size.height());
4053 copyInfos->append(copyInfo);
4055 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4059 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4060 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4066 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4067 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4078 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4080 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4081 bufD->pendingDynamicUpdates[i].clear();
4082 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4086 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4087 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4089 if (!bufD->stagingBuffers[currentFrameSlot]) {
4090 VkBufferCreateInfo bufferInfo = {};
4091 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4094 bufferInfo.size = bufD->m_size;
4095 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4097 VmaAllocationCreateInfo allocInfo = {};
4098 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4100 VmaAllocation allocation;
4101 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4102 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4103 if (err == VK_SUCCESS) {
4104 bufD->stagingAllocations[currentFrameSlot] = allocation;
4105 setAllocationName(allocation, bufD->name());
4107 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4108 printExtraErrorInfo(err);
4113 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u.data.constData(),
4114 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4115 u.offset, u.data.size());
4116 if (err != VK_SUCCESS) {
4117 qWarning(
"Failed to copy memory to buffer: %d", err);
4121 trackedBufferBarrier(cbD, bufD, 0,
4122 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4124 VkBufferCopy copyInfo = {};
4125 copyInfo.srcOffset = u.offset;
4126 copyInfo.dstOffset = u.offset;
4127 copyInfo.size = u
.data.size();
4131 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4132 cmd.args.copyBuffer.dst = bufD->buffers[0];
4133 cmd.args.copyBuffer.desc = copyInfo;
4142 bufD->lastActiveFrameSlot = currentFrameSlot;
4144 if (bufD->m_type == QRhiBuffer::Immutable) {
4147 e.lastActiveFrameSlot = currentFrameSlot;
4148 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4149 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4150 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4151 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4152 releaseQueue.append(e);
4156 if (bufD->m_type == QRhiBuffer::Dynamic) {
4157 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
4158 u.result->data.resizeForOverwrite(u.readSize);
4159 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4160 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4161 u.offset, u.result->data.data(), u.readSize);
4162 if (err != VK_SUCCESS) {
4163 qWarning(
"Failed to copy memory from buffer: %d", err);
4164 u.result->data.clear();
4166 if (u.result->completed)
4167 u.result->completed();
4176 readback.activeFrameSlot = currentFrameSlot;
4177 readback.result = u.result;
4178 readback.byteSize = u.readSize;
4180 VkBufferCreateInfo bufferInfo = {};
4181 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4182 bufferInfo.size = readback.byteSize;
4183 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4185 VmaAllocationCreateInfo allocInfo = {};
4186 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4188 VmaAllocation allocation;
4189 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4190 if (err == VK_SUCCESS) {
4192 setAllocationName(allocation, bufD->name());
4194 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4195 printExtraErrorInfo(err);
4199 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4201 VkBufferCopy copyInfo = {};
4202 copyInfo.srcOffset = u.offset;
4203 copyInfo.size = u.readSize;
4207 cmd.args.copyBuffer.src = bufD->buffers[0];
4208 cmd.args.copyBuffer.dst = readback.stagingBuf;
4209 cmd.args.copyBuffer.desc = copyInfo;
4211 bufD->lastActiveFrameSlot = currentFrameSlot;
4213 activeBufferReadbacks.append(readback);
4223 VkDeviceSize stagingSize = 0;
4224 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4225 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4226 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4227 stagingSize += subresUploadByteSize(subresDesc);
4231 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4232 VkBufferCreateInfo bufferInfo = {};
4233 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4234 bufferInfo.size = stagingSize;
4235 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4237 VmaAllocationCreateInfo allocInfo = {};
4238 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4240 VmaAllocation allocation;
4241 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4242 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4243 if (err != VK_SUCCESS) {
4244 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4245 printExtraErrorInfo(err);
4248 utexD->stagingAllocations[currentFrameSlot] = allocation;
4249 setAllocationName(allocation, utexD->name());
4251 BufferImageCopyList copyInfos;
4254 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4255 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4256 if (err != VK_SUCCESS) {
4257 qWarning(
"Failed to map image data: %d", err);
4261 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4262 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4263 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4266 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4267 prepareUploadSubres(utexD, layer, level,
4268 subresDesc, &curOfs, mp, ©Infos);
4272 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4273 vmaUnmapMemory(toVmaAllocator(allocator), a);
4275 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4276 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4280 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4281 cmd.args.copyBufferToImage.dst = utexD->image;
4282 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4283 cmd.args.copyBufferToImage.count = copyInfos.size();
4284 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4285 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4290 e.lastActiveFrameSlot = currentFrameSlot;
4291 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4292 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4293 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4294 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4295 releaseQueue.append(e);
4300 utexD->lastActiveFrameSlot = currentFrameSlot;
4304 qWarning(
"Texture copy with matching source and destination is not supported");
4309 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4310 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4312 VkImageCopy region = {};
4313 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4314 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4315 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4316 region.srcSubresource.layerCount = 1;
4318 region.srcOffset.x = u.desc.sourceTopLeft().x();
4319 region.srcOffset.y = u.desc.sourceTopLeft().y();
4321 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4323 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4324 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4325 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4326 region.dstSubresource.layerCount = 1;
4328 region.dstOffset.x = u.desc.destinationTopLeft().x();
4329 region.dstOffset.y = u.desc.destinationTopLeft().y();
4331 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4333 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4334 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4335 region.extent.width = uint32_t(copySize.width());
4336 region.extent.height = uint32_t(copySize.height());
4337 region.extent.depth = 1;
4339 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4340 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4341 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4342 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4346 cmd.args.copyImage.src = srcD->image;
4347 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4348 cmd.args.copyImage.dst = dstD->image;
4349 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4350 cmd.args.copyImage.desc = region;
4352 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4355 readback.activeFrameSlot = currentFrameSlot;
4356 readback.desc = u.rb;
4357 readback.result = u.result;
4363 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4364 qWarning(
"Multisample texture cannot be read back");
4367 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4368 if (u.rb.rect().isValid())
4369 readback.rect = u.rb.rect();
4371 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4372 readback.format = texD->m_format;
4373 texD->lastActiveFrameSlot = currentFrameSlot;
4378 qWarning(
"Swapchain does not support readback");
4381 if (u.rb.rect().isValid())
4382 readback.rect = u.rb.rect();
4384 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4385 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4386 if (readback.format == QRhiTexture::UnknownFormat)
4392 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4395 VkBufferCreateInfo bufferInfo = {};
4396 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4397 bufferInfo.size = readback.byteSize;
4398 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4400 VmaAllocationCreateInfo allocInfo = {};
4401 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4403 VmaAllocation allocation;
4404 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4405 if (err == VK_SUCCESS) {
4407 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4409 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4410 printExtraErrorInfo(err);
4415 VkBufferImageCopy copyDesc = {};
4416 copyDesc.bufferOffset = 0;
4417 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4418 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4419 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4420 copyDesc.imageSubresource.layerCount = 1;
4421 copyDesc.imageOffset.x = readback.rect.x();
4422 copyDesc.imageOffset.y = readback.rect.y();
4424 copyDesc.imageOffset.z = u.rb.layer();
4425 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4426 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4427 copyDesc.imageExtent.depth = 1;
4430 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4431 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4434 cmd.args.copyImageToBuffer.src = texD->image;
4435 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4436 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4437 cmd.args.copyImageToBuffer.desc = copyDesc;
4441 VkImage image = imageRes.image;
4444 qWarning(
"Attempted to read back undefined swapchain image content, "
4445 "results are undefined. (do a render pass first)");
4447 subresourceBarrier(cbD, image,
4448 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4449 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4450 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4458 cmd.args.copyImageToBuffer.src = image;
4459 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4460 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4461 cmd.args.copyImageToBuffer.desc = copyDesc;
4464 activeTextureReadbacks.append(readback);
4467 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4468 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4469 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4470 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4472 VkImageLayout origLayout = utexD->usageState.layout;
4473 VkAccessFlags origAccess = utexD->usageState.access;
4474 VkPipelineStageFlags origStage = utexD->usageState.stage;
4476 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4478 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4479 int w = utexD->m_pixelSize.width();
4480 int h = utexD->m_pixelSize.height();
4481 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4482 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4484 subresourceBarrier(cbD, utexD->image,
4485 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4486 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4487 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4491 subresourceBarrier(cbD, utexD->image,
4492 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4493 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4494 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4499 subresourceBarrier(cbD, utexD->image,
4500 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4501 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4502 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4506 VkImageBlit region = {};
4507 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4508 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4509 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4510 region.srcSubresource.layerCount = 1;
4512 region.srcOffsets[1].x = qMax(1, w);
4513 region.srcOffsets[1].y = qMax(1, h);
4514 region.srcOffsets[1].z = qMax(1, depth);
4516 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4517 region.dstSubresource.mipLevel = uint32_t(level);
4518 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4519 region.dstSubresource.layerCount = 1;
4521 region.dstOffsets[1].x = qMax(1, w >> 1);
4522 region.dstOffsets[1].y = qMax(1, h >> 1);
4523 region.dstOffsets[1].z = qMax(1, depth >> 1);
4527 cmd.args.blitImage.src = utexD->image;
4528 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4529 cmd.args.blitImage.dst = utexD->image;
4530 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4531 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4532 cmd.args.blitImage.desc = region;
4539 if (utexD->mipLevelCount > 1) {
4540 subresourceBarrier(cbD, utexD->image,
4541 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4542 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4543 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4545 0,
int(utexD->mipLevelCount) - 1);
4546 subresourceBarrier(cbD, utexD->image,
4547 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4548 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4549 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4551 int(utexD->mipLevelCount) - 1, 1);
4554 utexD->lastActiveFrameSlot = currentFrameSlot;
4563 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4566 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4568 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4572 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4573 if (err != VK_SUCCESS) {
4574 qWarning(
"Failed to map buffer: %d", err);
4577 quint32 changeBegin = UINT32_MAX;
4578 quint32 changeEnd = 0;
4579 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4580 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4581 if (u.offset < changeBegin)
4582 changeBegin = u.offset;
4583 if (u.offset + u.data.size() > changeEnd)
4584 changeEnd = u.offset + u.data.size();
4586 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4587 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4588 vmaUnmapMemory(toVmaAllocator(allocator), a);
4590 bufD->pendingDynamicUpdates[slot].clear();
4596 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4597 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4603 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4604 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4605 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4610 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4611 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4612 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
4613 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4614 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4615 if (e.texture.extraImageViews[i])
4616 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4622 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4627 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4629 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4631 case QRhiVulkan::DeferredReleaseEntry::Pipeline:
4632 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4633 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4635 case QRhiVulkan::DeferredReleaseEntry::ShaderResourceBindings:
4636 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4637 if (e.shaderResourceBindings.poolIndex >= 0) {
4638 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4639 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4645 case QRhiVulkan::DeferredReleaseEntry::RenderBuffer:
4646 qrhivk_releaseRenderBuffer(e, dev, df);
4648 case QRhiVulkan::DeferredReleaseEntry::Texture:
4649 qrhivk_releaseTexture(e, dev, df, allocator);
4651 case QRhiVulkan::DeferredReleaseEntry::Sampler:
4652 qrhivk_releaseSampler(e, dev, df);
4654 case QRhiVulkan::DeferredReleaseEntry::TextureRenderTarget:
4655 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4657 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4658 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4660 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4661 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4662 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4664 case QRhiVulkan::DeferredReleaseEntry::RenderPass:
4665 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4667 case QRhiVulkan::DeferredReleaseEntry::StagingBuffer:
4668 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4670 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4671 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4677 releaseQueue.removeAt(i);
4684 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4686 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4688 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4689 readback.result->format = readback.format;
4690 readback.result->pixelSize = readback.rect.size();
4691 readback.result->data.resizeForOverwrite(readback.byteSize);
4692 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4693 toVmaAllocation(readback.stagingAlloc),
4694 0, readback.result->data.data(), readback.byteSize);
4695 if (err != VK_SUCCESS) {
4696 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4697 readback.result->data.clear();
4700 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4702 if (readback.result->completed)
4703 completedCallbacks.append(readback.result->completed);
4705 activeTextureReadbacks.remove(i);
4709 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4711 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4712 readback.result->data.resizeForOverwrite(readback.byteSize);
4713 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4714 toVmaAllocation(readback.stagingAlloc),
4715 0, readback.result->data.data(), readback.byteSize);
4716 if (err != VK_SUCCESS) {
4717 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4718 readback.result->data.clear();
4721 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4723 if (readback.result->completed)
4724 completedCallbacks.append(readback.result->completed);
4726 activeBufferReadbacks.remove(i);
4730 for (
auto f : completedCallbacks)
4737} qvk_sampleCounts[] = {
4739 { VK_SAMPLE_COUNT_1_BIT, 1 },
4740 { VK_SAMPLE_COUNT_2_BIT, 2 },
4741 { VK_SAMPLE_COUNT_4_BIT, 4 },
4742 { VK_SAMPLE_COUNT_8_BIT, 8 },
4743 { VK_SAMPLE_COUNT_16_BIT, 16 },
4744 { VK_SAMPLE_COUNT_32_BIT, 32 },
4745 { VK_SAMPLE_COUNT_64_BIT, 64 }
4750 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4751 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4752 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4753 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4756 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4757 if ((color & qvk_sampleCount.mask)
4758 && (depth & qvk_sampleCount.mask)
4759 && (stencil & qvk_sampleCount.mask))
4761 result.append(qvk_sampleCount.count);
4770 const int s = effectiveSampleCount(sampleCount);
4772 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4773 if (qvk_sampleCount.count == s)
4774 return qvk_sampleCount.mask;
4777 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4782 QList<QSize> result;
4783#ifdef VK_KHR_fragment_shading_rate
4784 sampleCount = qMax(1, sampleCount);
4785 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4786 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4787 if (qvk_sampleCount.count == sampleCount) {
4788 mask = qvk_sampleCount.mask;
4792 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4793 if (s.sampleCounts & mask)
4794 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4797 Q_UNUSED(sampleCount);
4798 result.append(QSize(1, 1));
4805 cbD->passResTrackers.emplace_back();
4810 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
4817 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
4821 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
4822 1, &cmd.args.copyBuffer.desc);
4825 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
4826 cmd.args.copyBufferToImage.dstLayout,
4827 uint32_t(cmd.args.copyBufferToImage.count),
4828 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
4831 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
4832 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
4833 1, &cmd.args.copyImage.desc);
4836 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
4837 cmd.args.copyImageToBuffer.dst,
4838 1, &cmd.args.copyImageToBuffer.desc);
4841 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
4842 0, 0,
nullptr, 0,
nullptr,
4843 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
4846 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
4848 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
4852 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
4853 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
4854 1, &cmd.args.blitImage.desc,
4855 cmd.args.blitImage.filter);
4858 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
4859 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
4860 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
4861 : VK_SUBPASS_CONTENTS_INLINE);
4864 df->vkCmdEndRenderPass(cbD->cb);
4867 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
4871 const uint32_t *offsets =
nullptr;
4872 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
4873 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
4874 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
4875 cmd.args.bindDescriptorSet.pipelineLayout,
4876 0, 1, &cmd.args.bindDescriptorSet.descSet,
4877 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
4882 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
4883 uint32_t(cmd.args.bindVertexBuffer.count),
4884 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
4885 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
4888 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
4889 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
4892 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
4895 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
4898 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
4900 case QVkCommandBuffer::Command::SetStencilRef:
4901 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
4904 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
4905 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
4908 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
4909 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
4910 cmd.args.drawIndexed.firstInstance);
4913#ifdef VK_EXT_debug_utils
4914 cmd.args.debugMarkerBegin.label.pLabelName =
4915 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
4916 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
4920#ifdef VK_EXT_debug_utils
4921 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
4925#ifdef VK_EXT_debug_utils
4926 cmd.args.debugMarkerInsert.label.pLabelName =
4927 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
4928 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
4935 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
4938 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
4942#ifdef VK_KHR_fragment_shading_rate
4943 VkFragmentShadingRateCombinerOpKHR op[2] = {
4944 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
4945 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
4947 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
4948 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
4961 case QRhiPassResourceTracker::BufVertexInput:
4962 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
4963 case QRhiPassResourceTracker::BufIndexRead:
4964 return VK_ACCESS_INDEX_READ_BIT;
4965 case QRhiPassResourceTracker::BufUniformRead:
4966 return VK_ACCESS_UNIFORM_READ_BIT;
4967 case QRhiPassResourceTracker::BufStorageLoad:
4968 return VK_ACCESS_SHADER_READ_BIT;
4969 case QRhiPassResourceTracker::BufStorageStore:
4970 return VK_ACCESS_SHADER_WRITE_BIT;
4971 case QRhiPassResourceTracker::BufStorageLoadStore:
4972 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
4983 case QRhiPassResourceTracker::BufVertexInputStage:
4984 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
4985 case QRhiPassResourceTracker::BufVertexStage:
4986 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
4987 case QRhiPassResourceTracker::BufTCStage:
4988 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
4989 case QRhiPassResourceTracker::BufTEStage:
4990 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
4991 case QRhiPassResourceTracker::BufFragmentStage:
4992 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
4993 case QRhiPassResourceTracker::BufComputeStage:
4994 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4995 case QRhiPassResourceTracker::BufGeometryStage:
4996 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5007 u.access = VkAccessFlags(usage
.access);
5008 u.stage = VkPipelineStageFlags(usage
.stage);
5015 case QRhiPassResourceTracker::TexSample:
5016 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5017 case QRhiPassResourceTracker::TexColorOutput:
5018 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5019 case QRhiPassResourceTracker::TexDepthOutput:
5020 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5021 case QRhiPassResourceTracker::TexStorageLoad:
5022 case QRhiPassResourceTracker::TexStorageStore:
5023 case QRhiPassResourceTracker::TexStorageLoadStore:
5024 return VK_IMAGE_LAYOUT_GENERAL;
5025 case QRhiPassResourceTracker::TexShadingRate:
5026#ifdef VK_KHR_fragment_shading_rate
5027 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5029 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5035 return VK_IMAGE_LAYOUT_GENERAL;
5041 case QRhiPassResourceTracker::TexSample:
5042 return VK_ACCESS_SHADER_READ_BIT;
5043 case QRhiPassResourceTracker::TexColorOutput:
5044 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5045 case QRhiPassResourceTracker::TexDepthOutput:
5046 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5047 case QRhiPassResourceTracker::TexStorageLoad:
5048 return VK_ACCESS_SHADER_READ_BIT;
5049 case QRhiPassResourceTracker::TexStorageStore:
5050 return VK_ACCESS_SHADER_WRITE_BIT;
5051 case QRhiPassResourceTracker::TexStorageLoadStore:
5052 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5065 case QRhiPassResourceTracker::TexVertexStage:
5066 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5067 case QRhiPassResourceTracker::TexTCStage:
5068 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5069 case QRhiPassResourceTracker::TexTEStage:
5070 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5071 case QRhiPassResourceTracker::TexFragmentStage:
5072 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5073 case QRhiPassResourceTracker::TexColorOutputStage:
5074 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5075 case QRhiPassResourceTracker::TexDepthOutputStage:
5076 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5077 case QRhiPassResourceTracker::TexComputeStage:
5078 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5079 case QRhiPassResourceTracker::TexGeometryStage:
5080 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5091 u.layout = VkImageLayout(usage
.layout);
5092 u.access = VkAccessFlags(usage
.access);
5093 u.stage = VkPipelineStageFlags(usage
.stage);
5104 const VkAccessFlags newAccess = toVkAccess(access);
5105 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5106 if (u.access == newAccess && u.stage == newStage) {
5107 if (!accessIsWrite(access))
5111 u.access = newAccess;
5121 const VkAccessFlags newAccess = toVkAccess(access);
5122 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5123 const VkImageLayout newLayout = toVkLayout(access);
5124 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5125 if (!accessIsWrite(access))
5129 u.layout = newLayout;
5130 u.access = newAccess;
5139 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5140 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5141 VkAccessFlags access = toVkAccess(trackedB.access);
5142 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5143 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5146 if (s.access == access && s.stage == stage) {
5147 if (!accessIsWrite(access))
5150 VkBufferMemoryBarrier bufMemBarrier = {};
5151 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5152 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5153 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5154 bufMemBarrier.srcAccessMask = s.access;
5155 bufMemBarrier.dstAccessMask = access;
5156 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5157 bufMemBarrier.size = VK_WHOLE_SIZE;
5158 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5164 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5165 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5166 VkImageLayout layout = toVkLayout(trackedT.access);
5167 VkAccessFlags access = toVkAccess(trackedT.access);
5168 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5169 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5170 if (s.access == access && s.stage == stage && s.layout == layout) {
5171 if (!accessIsWrite(access))
5174 VkImageMemoryBarrier barrier = {};
5175 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5176 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5177 barrier.subresourceRange.baseMipLevel = 0;
5178 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5179 barrier.subresourceRange.baseArrayLayer = 0;
5180 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5181 barrier.oldLayout = s.layout;
5182 barrier.newLayout = layout;
5183 barrier.srcAccessMask = s.access;
5184 barrier.dstAccessMask = access;
5185 barrier.image = texD->image;
5186 VkPipelineStageFlags srcStage = s.stage;
5189 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5190 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5199 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5200 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5201 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5203 qWarning(
"Physical device surface queries not available");
5207 return new QVkSwapChain(
this);
5210QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5212 return new QVkBuffer(
this, type, usage, size);
5217 return int(ubufAlign);
5239 static QMatrix4x4 m;
5240 if (m.isIdentity()) {
5242 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5243 0.0f, -1.0f, 0.0f, 0.0f,
5244 0.0f, 0.0f, 0.5f, 0.5f,
5245 0.0f, 0.0f, 0.0f, 1.0f);
5255 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5256 if (!physDevFeatures.textureCompressionBC)
5260 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5261 if (!physDevFeatures.textureCompressionETC2)
5265 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5266 if (!physDevFeatures.textureCompressionASTC_LDR)
5270 VkFormat vkformat = toVkTextureFormat(format, flags);
5271 VkFormatProperties props;
5272 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5273 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5279 case QRhi::MultisampleTexture:
5281 case QRhi::MultisampleRenderBuffer:
5283 case QRhi::DebugMarkers:
5284 return caps.debugUtils;
5285 case QRhi::Timestamps:
5286 return timestampValidBits != 0;
5287 case QRhi::Instancing:
5289 case QRhi::CustomInstanceStepRate:
5290 return caps.vertexAttribDivisor;
5291 case QRhi::PrimitiveRestart:
5293 case QRhi::NonDynamicUniformBuffers:
5295 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5297 case QRhi::NPOTTextureRepeat:
5299 case QRhi::RedOrAlpha8IsRed:
5301 case QRhi::ElementIndexUint:
5304 return caps.compute;
5305 case QRhi::WideLines:
5306 return caps.wideLines;
5307 case QRhi::VertexShaderPointSize:
5309 case QRhi::BaseVertex:
5311 case QRhi::BaseInstance:
5313 case QRhi::TriangleFanTopology:
5315 case QRhi::ReadBackNonUniformBuffer:
5317 case QRhi::ReadBackNonBaseMipLevel:
5319 case QRhi::TexelFetch:
5321 case QRhi::RenderToNonBaseMipLevel:
5323 case QRhi::IntAttributes:
5325 case QRhi::ScreenSpaceDerivatives:
5327 case QRhi::ReadBackAnyTextureFormat:
5329 case QRhi::PipelineCacheDataLoadSave:
5331 case QRhi::ImageDataStride:
5333 case QRhi::RenderBufferImport:
5335 case QRhi::ThreeDimensionalTextures:
5337 case QRhi::RenderTo3DTextureSlice:
5338 return caps.texture3DSliceAs2D;
5339 case QRhi::TextureArrays:
5341 case QRhi::Tessellation:
5342 return caps.tessellation;
5343 case QRhi::GeometryShader:
5344 return caps.geometryShader;
5345 case QRhi::TextureArrayRange:
5347 case QRhi::NonFillPolygonMode:
5348 return caps.nonFillPolygonMode;
5349 case QRhi::OneDimensionalTextures:
5351 case QRhi::OneDimensionalTextureMipmaps:
5353 case QRhi::HalfAttributes:
5355 case QRhi::RenderToOneDimensionalTexture:
5357 case QRhi::ThreeDimensionalTextureMipmaps:
5359 case QRhi::MultiView:
5360 return caps.multiView;
5361 case QRhi::TextureViewFormat:
5363 case QRhi::ResolveDepthStencil:
5364 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5365 case QRhi::VariableRateShading:
5366 return caps.renderPass2KHR && caps.perDrawShadingRate;
5367 case QRhi::VariableRateShadingMap:
5368 case QRhi::VariableRateShadingMapWithTexture:
5369 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5370 case QRhi::PerRenderTargetBlending:
5371 case QRhi::SampleVariables:
5373 case QRhi::InstanceIndexIncludesBaseInstance:
5376 Q_UNREACHABLE_RETURN(
false);
5383 case QRhi::TextureSizeMin:
5385 case QRhi::TextureSizeMax:
5386 return int(physDevProperties.limits.maxImageDimension2D);
5387 case QRhi::MaxColorAttachments:
5388 return int(physDevProperties.limits.maxColorAttachments);
5389 case QRhi::FramesInFlight:
5391 case QRhi::MaxAsyncReadbackFrames:
5393 case QRhi::MaxThreadGroupsPerDimension:
5394 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5395 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5396 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5397 case QRhi::MaxThreadsPerThreadGroup:
5398 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5399 case QRhi::MaxThreadGroupX:
5400 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5401 case QRhi::MaxThreadGroupY:
5402 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5403 case QRhi::MaxThreadGroupZ:
5404 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5405 case QRhi::TextureArraySizeMax:
5406 return int(physDevProperties.limits.maxImageArrayLayers);
5407 case QRhi::MaxUniformBufferRange:
5408 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5409 case QRhi::MaxVertexInputs:
5410 return physDevProperties.limits.maxVertexInputAttributes;
5411 case QRhi::MaxVertexOutputs:
5412 return physDevProperties.limits.maxVertexOutputComponents / 4;
5413 case QRhi::ShadingRateImageTileSize:
5414 return caps.imageBasedShadingRateTileSize;
5416 Q_UNREACHABLE_RETURN(0);
5422 return &nativeHandlesStruct;
5427 return driverInfoStruct;
5433 result.totalPipelineCreationTime = totalPipelineCreationTime();
5435 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5436 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5438 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5439 for (uint32_t i = 0; i < count; ++i) {
5440 const VmaStatistics &stats(budgets[i].statistics);
5441 result.blockCount += stats.blockCount;
5442 result.allocCount += stats.allocationCount;
5443 result.usedBytes += stats.allocationBytes;
5444 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5458 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5462 waitSemaphoresForQueueSubmit.clear();
5463 if (sp->waitSemaphoreCount)
5464 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5466 signalSemaphoresForQueueSubmit.clear();
5467 if (sp->signalSemaphoreCount)
5468 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5470 waitSemaphoresForPresent.clear();
5471 if (sp->presentWaitSemaphoreCount)
5472 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5502 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5505 size_t dataSize = 0;
5506 VkResult err = df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5507 if (err != VK_SUCCESS) {
5508 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5509 return QByteArray();
5512 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5513 data.resize(dataOffset + dataSize);
5514 err = df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5515 if (err != VK_SUCCESS) {
5516 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5517 return QByteArray();
5521 header.rhiId = pipelineCacheRhiId();
5522 header.arch = quint32(
sizeof(
void*));
5523 header.driverVersion = physDevProperties.driverVersion;
5524 header.vendorId = physDevProperties.vendorID;
5525 header.deviceId = physDevProperties.deviceID;
5526 header.dataSize = quint32(dataSize);
5527 header.uuidSize = VK_UUID_SIZE;
5528 header.reserved = 0;
5529 memcpy(data.data(), &header, headerSize);
5530 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5541 if (data.size() < qsizetype(headerSize)) {
5542 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5546 memcpy(&header, data.constData(), headerSize);
5548 const quint32 rhiId = pipelineCacheRhiId();
5549 if (header.rhiId != rhiId) {
5550 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5551 rhiId, header.rhiId);
5554 const quint32 arch = quint32(
sizeof(
void*));
5555 if (header.arch != arch) {
5556 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5560 if (header.driverVersion != physDevProperties.driverVersion) {
5561 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5562 physDevProperties.driverVersion, header.driverVersion);
5565 if (header.vendorId != physDevProperties.vendorID) {
5566 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5567 physDevProperties.vendorID, header.vendorId);
5570 if (header.deviceId != physDevProperties.deviceID) {
5571 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5572 physDevProperties.deviceID, header.deviceId);
5575 if (header.uuidSize != VK_UUID_SIZE) {
5576 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5577 quint32(VK_UUID_SIZE), header.uuidSize);
5581 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5582 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5585 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5586 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5590 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5591 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5592 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5596 if (pipelineCache) {
5597 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5598 pipelineCache = VK_NULL_HANDLE;
5601 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5602 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5603 int(header.dataSize));
5605 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5609QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5610 int sampleCount, QRhiRenderBuffer::Flags flags,
5611 QRhiTexture::Format backingFormatHint)
5613 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5617 const QSize &pixelSize,
int depth,
int arraySize,
5618 int sampleCount, QRhiTexture::Flags flags)
5620 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5624 QRhiSampler::Filter mipmapMode,
5625 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5627 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5632 return new QVkShadingRateMap(
this);
5636 QRhiTextureRenderTarget::Flags flags)
5643 return new QVkGraphicsPipeline(
this);
5648 return new QVkComputePipeline(
this);
5653 return new QVkShaderResourceBindings(
this);
5659 Q_ASSERT(psD->pipeline);
5663 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5665 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5669 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5670 cmd.args.bindPipeline.pipeline = psD->pipeline;
5673 cbD->currentGraphicsPipeline = ps;
5674 cbD->currentComputePipeline =
nullptr;
5675 cbD->currentPipelineGeneration = psD->generation;
5678 psD->lastActiveFrameSlot = currentFrameSlot;
5682 int dynamicOffsetCount,
5683 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5693 srb = gfxPsD->m_shaderResourceBindings;
5695 srb = compPsD->m_shaderResourceBindings;
5699 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5700 bool rewriteDescSet =
false;
5704 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5705 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5708 case QRhiShaderResourceBinding::UniformBuffer:
5711 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5713 if (bufD->m_type == QRhiBuffer::Dynamic)
5714 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
5716 bufD->lastActiveFrameSlot = currentFrameSlot;
5717 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5718 QRhiPassResourceTracker::BufUniformRead,
5719 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5725 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5726 rewriteDescSet =
true;
5727 bd.ubuf.id = bufD->m_id;
5728 bd.ubuf.generation = bufD->generation;
5732 case QRhiShaderResourceBinding::SampledTexture:
5733 case QRhiShaderResourceBinding::Texture:
5734 case QRhiShaderResourceBinding::Sampler:
5736 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5737 if (bd.stex.count != data->count) {
5738 bd.stex.count = data->count;
5739 rewriteDescSet =
true;
5741 for (
int elem = 0; elem < data->count; ++elem) {
5747 Q_ASSERT(texD || samplerD);
5749 texD->lastActiveFrameSlot = currentFrameSlot;
5755 samplerD->lastActiveFrameSlot = currentFrameSlot;
5756 const quint64 texId = texD ? texD->m_id : 0;
5757 const uint texGen = texD ? texD->generation : 0;
5758 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
5759 const uint samplerGen = samplerD ? samplerD->generation : 0;
5760 if (texGen != bd.stex.d[elem].texGeneration
5761 || texId != bd.stex.d[elem].texId
5762 || samplerGen != bd.stex.d[elem].samplerGeneration
5763 || samplerId != bd.stex.d[elem].samplerId)
5765 rewriteDescSet =
true;
5766 bd.stex.d[elem].texId = texId;
5767 bd.stex.d[elem].texGeneration = texGen;
5768 bd.stex.d[elem].samplerId = samplerId;
5769 bd.stex.d[elem].samplerGeneration = samplerGen;
5774 case QRhiShaderResourceBinding::ImageLoad:
5775 case QRhiShaderResourceBinding::ImageStore:
5776 case QRhiShaderResourceBinding::ImageLoadStore:
5779 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
5780 texD->lastActiveFrameSlot = currentFrameSlot;
5782 if (b->type == QRhiShaderResourceBinding::ImageLoad)
5784 else if (b->type == QRhiShaderResourceBinding::ImageStore)
5792 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
5793 rewriteDescSet =
true;
5794 bd.simage.id = texD->m_id;
5795 bd.simage.generation = texD->generation;
5799 case QRhiShaderResourceBinding::BufferLoad:
5800 case QRhiShaderResourceBinding::BufferStore:
5801 case QRhiShaderResourceBinding::BufferLoadStore:
5804 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
5806 if (bufD->m_type == QRhiBuffer::Dynamic)
5807 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
5809 bufD->lastActiveFrameSlot = currentFrameSlot;
5811 if (b->type == QRhiShaderResourceBinding::BufferLoad)
5813 else if (b->type == QRhiShaderResourceBinding::BufferStore)
5817 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5819 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5821 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
5822 rewriteDescSet =
true;
5823 bd.sbuf.id = bufD->m_id;
5824 bd.sbuf.generation = bufD->generation;
5836 updateShaderResourceBindings(srb);
5840 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot || srbD->hasDynamicOffset;
5842 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
5844 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
5845 QVarLengthArray<uint32_t, 4> dynOfs;
5851 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
5852 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
5853 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
5854 uint32_t offset = 0;
5855 for (
int i = 0; i < dynamicOffsetCount; ++i) {
5856 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
5857 if (bindingOffsetPair.first == b->binding) {
5858 offset = bindingOffsetPair.second;
5862 dynOfs.append(offset);
5868 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
5869 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
5870 gfxPsD ? gfxPsD->layout : compPsD->layout,
5871 0, 1, &srbD->descSets[currentFrameSlot],
5872 uint32_t(dynOfs.size()),
5873 dynOfs.size() ? dynOfs.constData() :
nullptr);
5877 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
5878 : VK_PIPELINE_BIND_POINT_COMPUTE;
5879 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
5880 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
5881 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
5882 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
5883 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
5887 cbD->currentGraphicsSrb = srb;
5888 cbD->currentComputeSrb =
nullptr;
5890 cbD->currentGraphicsSrb =
nullptr;
5891 cbD->currentComputeSrb = srb;
5893 cbD->currentSrbGeneration = srbD->generation;
5894 cbD->currentDescSetSlot = currentFrameSlot;
5897 srbD->lastActiveFrameSlot = currentFrameSlot;
5901 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
5902 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
5908 bool needsBindVBuf =
false;
5909 for (
int i = 0; i < bindingCount; ++i) {
5910 const int inputSlot = startBinding + i;
5912 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
5913 bufD->lastActiveFrameSlot = currentFrameSlot;
5914 if (bufD->m_type == QRhiBuffer::Dynamic)
5915 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
5917 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
5918 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
5919 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
5921 needsBindVBuf =
true;
5922 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
5923 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
5927 if (needsBindVBuf) {
5928 QVarLengthArray<VkBuffer, 4> bufs;
5929 QVarLengthArray<VkDeviceSize, 4> ofs;
5930 for (
int i = 0; i < bindingCount; ++i) {
5932 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
5933 bufs.append(bufD->buffers[slot]);
5934 ofs.append(bindings[i].second);
5941 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
5942 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
5946 cmd.args.bindVertexBuffer.startBinding = startBinding;
5947 cmd.args.bindVertexBuffer.count = bufs.size();
5948 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
5949 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
5950 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
5951 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
5957 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
5958 ibufD->lastActiveFrameSlot = currentFrameSlot;
5959 if (ibufD->m_type == QRhiBuffer::Dynamic)
5960 executeBufferHostWritesForSlot(ibufD, currentFrameSlot);
5962 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
5963 const VkBuffer vkindexbuf = ibufD->buffers[slot];
5964 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
5965 : VK_INDEX_TYPE_UINT32;
5967 if (cbD->currentIndexBuffer != vkindexbuf
5968 || cbD->currentIndexOffset != indexOffset
5969 || cbD->currentIndexFormat != type)
5971 cbD->currentIndexBuffer = vkindexbuf;
5972 cbD->currentIndexOffset = indexOffset;
5973 cbD->currentIndexFormat = type;
5976 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
5980 cmd.args.bindIndexBuffer.buf = vkindexbuf;
5981 cmd.args.bindIndexBuffer.ofs = indexOffset;
5982 cmd.args.bindIndexBuffer.type = type;
5996 const QSize outputSize = cbD->currentTarget->pixelSize();
6000 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6004 VkViewport *vp = &cmd.args.setViewport.viewport;
6009 vp->minDepth = viewport.minDepth();
6010 vp->maxDepth = viewport.maxDepth();
6013 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6014 cbD->commands.unget();
6019 if (cbD->currentGraphicsPipeline
6020 && !
QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
6023 VkRect2D *s = &cmd.args.setScissor.scissor;
6024 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
6025 s->offset.x = int32_t(x);
6026 s->offset.y = int32_t(y);
6027 s->extent.width = uint32_t(w);
6028 s->extent.height = uint32_t(h);
6030 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6031 cbD->commands.unget();
6042 Q_ASSERT(!cbD->currentGraphicsPipeline
6043 ||
QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)
6044 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6045 const QSize outputSize = cbD->currentTarget->pixelSize();
6049 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6053 VkRect2D *s = &cmd.args.setScissor.scissor;
6056 s->extent.width = uint32_t(w);
6057 s->extent.height = uint32_t(h);
6060 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6061 cbD->commands.unget();
6073 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6074 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6078 cmd.args.setBlendConstants.c[0] = c.redF();
6079 cmd.args.setBlendConstants.c[1] = c.greenF();
6080 cmd.args.setBlendConstants.c[2] = c.blueF();
6081 cmd.args.setBlendConstants.c[3] = c.alphaF();
6091 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6095 cmd.args.setStencilRef.ref = refValue;
6101#ifdef VK_KHR_fragment_shading_rate
6102 if (!vkCmdSetFragmentShadingRateKHR)
6105 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6106 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6107 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6109 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6110 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6111 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6113 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6114 if (cbD->passUsesSecondaryCb) {
6115 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6117 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6118 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6119 cmd.args.setShadingRate.w = size.width;
6120 cmd.args.setShadingRate.h = size.height;
6122 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6123 cbD->hasShadingRateSet =
true;
6126 Q_UNUSED(coarsePixelSize);
6131 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6137 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6141 cmd.args.draw.vertexCount = vertexCount;
6142 cmd.args.draw.instanceCount = instanceCount;
6143 cmd.args.draw.firstVertex = firstVertex;
6144 cmd.args.draw.firstInstance = firstInstance;
6149 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6155 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6156 firstIndex, vertexOffset, firstInstance);
6160 cmd.args.drawIndexed.indexCount = indexCount;
6161 cmd.args.drawIndexed.instanceCount = instanceCount;
6162 cmd.args.drawIndexed.firstIndex = firstIndex;
6163 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6164 cmd.args.drawIndexed.firstInstance = firstInstance;
6170#ifdef VK_EXT_debug_utils
6171 if (!debugMarkers || !caps.debugUtils)
6174 VkDebugUtilsLabelEXT label = {};
6175 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6177 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6178 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6179 label.pLabelName = name.constData();
6180 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6182 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6183 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6184 cmd.args.debugMarkerBegin.label = label;
6185 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6186 cbD->pools.debugMarkerData.append(name);
6196#ifdef VK_EXT_debug_utils
6197 if (!debugMarkers || !caps.debugUtils)
6200 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6201 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6202 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6204 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6205 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6214#ifdef VK_EXT_debug_utils
6215 if (!debugMarkers || !caps.debugUtils)
6218 VkDebugUtilsLabelEXT label = {};
6219 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6221 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6222 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6223 label.pLabelName = msg.constData();
6224 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6226 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6227 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6228 cmd.args.debugMarkerInsert.label = label;
6229 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6230 cbD->pools.debugMarkerData.append(msg);
6240 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6245 Q_ASSERT(cbD->currentTarget);
6248 switch (cbD->currentTarget->resourceType()) {
6249 case QRhiResource::SwapChainRenderTarget:
6252 case QRhiResource::TextureRenderTarget:
6284 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6285 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6289 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6290 cbD->activeSecondaryCbStack.removeLast();
6291 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6293 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6295 cbD->activeSecondaryCbStack.append(extCb);
6307 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6308 cbD->activeSecondaryCbStack.removeLast();
6309 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6310 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6324 if (!debugMarkers || name.isEmpty())
6327 QByteArray decoratedName = name;
6329 decoratedName +=
'/';
6330 decoratedName += QByteArray::number(slot);
6332 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6337#ifdef VK_EXT_debug_utils
6338 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6341 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6342 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6343 nameInfo.objectType = type;
6344 nameInfo.objectHandle = object;
6345 QByteArray decoratedName = name;
6347 decoratedName +=
'/';
6348 decoratedName += QByteArray::number(slot);
6350 nameInfo.pObjectName = decoratedName.constData();
6351 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6363 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6364 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6365 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6366 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6367 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6368 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6369 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6370 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6371 return VkBufferUsageFlagBits(u);
6377 case QRhiSampler::Nearest:
6378 return VK_FILTER_NEAREST;
6379 case QRhiSampler::Linear:
6380 return VK_FILTER_LINEAR;
6382 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6389 case QRhiSampler::None:
6390 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6391 case QRhiSampler::Nearest:
6392 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6393 case QRhiSampler::Linear:
6394 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6396 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6403 case QRhiSampler::Repeat:
6404 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6405 case QRhiSampler::ClampToEdge:
6406 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6407 case QRhiSampler::Mirror:
6408 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6410 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6417 case QRhiShaderStage::Vertex:
6418 return VK_SHADER_STAGE_VERTEX_BIT;
6419 case QRhiShaderStage::TessellationControl:
6420 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6421 case QRhiShaderStage::TessellationEvaluation:
6422 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6423 case QRhiShaderStage::Fragment:
6424 return VK_SHADER_STAGE_FRAGMENT_BIT;
6425 case QRhiShaderStage::Compute:
6426 return VK_SHADER_STAGE_COMPUTE_BIT;
6427 case QRhiShaderStage::Geometry:
6428 return VK_SHADER_STAGE_GEOMETRY_BIT;
6430 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6437 case QRhiVertexInputAttribute::Float4:
6438 return VK_FORMAT_R32G32B32A32_SFLOAT;
6439 case QRhiVertexInputAttribute::Float3:
6440 return VK_FORMAT_R32G32B32_SFLOAT;
6441 case QRhiVertexInputAttribute::Float2:
6442 return VK_FORMAT_R32G32_SFLOAT;
6443 case QRhiVertexInputAttribute::Float:
6444 return VK_FORMAT_R32_SFLOAT;
6445 case QRhiVertexInputAttribute::UNormByte4:
6446 return VK_FORMAT_R8G8B8A8_UNORM;
6447 case QRhiVertexInputAttribute::UNormByte2:
6448 return VK_FORMAT_R8G8_UNORM;
6449 case QRhiVertexInputAttribute::UNormByte:
6450 return VK_FORMAT_R8_UNORM;
6451 case QRhiVertexInputAttribute::UInt4:
6452 return VK_FORMAT_R32G32B32A32_UINT;
6453 case QRhiVertexInputAttribute::UInt3:
6454 return VK_FORMAT_R32G32B32_UINT;
6455 case QRhiVertexInputAttribute::UInt2:
6456 return VK_FORMAT_R32G32_UINT;
6457 case QRhiVertexInputAttribute::UInt:
6458 return VK_FORMAT_R32_UINT;
6459 case QRhiVertexInputAttribute::SInt4:
6460 return VK_FORMAT_R32G32B32A32_SINT;
6461 case QRhiVertexInputAttribute::SInt3:
6462 return VK_FORMAT_R32G32B32_SINT;
6463 case QRhiVertexInputAttribute::SInt2:
6464 return VK_FORMAT_R32G32_SINT;
6465 case QRhiVertexInputAttribute::SInt:
6466 return VK_FORMAT_R32_SINT;
6467 case QRhiVertexInputAttribute::Half4:
6468 return VK_FORMAT_R16G16B16A16_SFLOAT;
6469 case QRhiVertexInputAttribute::Half3:
6470 return VK_FORMAT_R16G16B16_SFLOAT;
6471 case QRhiVertexInputAttribute::Half2:
6472 return VK_FORMAT_R16G16_SFLOAT;
6473 case QRhiVertexInputAttribute::Half:
6474 return VK_FORMAT_R16_SFLOAT;
6475 case QRhiVertexInputAttribute::UShort4:
6476 return VK_FORMAT_R16G16B16A16_UINT;
6477 case QRhiVertexInputAttribute::UShort3:
6478 return VK_FORMAT_R16G16B16_UINT;
6479 case QRhiVertexInputAttribute::UShort2:
6480 return VK_FORMAT_R16G16_UINT;
6481 case QRhiVertexInputAttribute::UShort:
6482 return VK_FORMAT_R16_UINT;
6483 case QRhiVertexInputAttribute::SShort4:
6484 return VK_FORMAT_R16G16B16A16_SINT;
6485 case QRhiVertexInputAttribute::SShort3:
6486 return VK_FORMAT_R16G16B16_SINT;
6487 case QRhiVertexInputAttribute::SShort2:
6488 return VK_FORMAT_R16G16_SINT;
6489 case QRhiVertexInputAttribute::SShort:
6490 return VK_FORMAT_R16_SINT;
6492 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6499 case QRhiGraphicsPipeline::Triangles:
6500 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6501 case QRhiGraphicsPipeline::TriangleStrip:
6502 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6503 case QRhiGraphicsPipeline::TriangleFan:
6504 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6505 case QRhiGraphicsPipeline::Lines:
6506 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6507 case QRhiGraphicsPipeline::LineStrip:
6508 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6509 case QRhiGraphicsPipeline::Points:
6510 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6511 case QRhiGraphicsPipeline::Patches:
6512 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6514 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6521 case QRhiGraphicsPipeline::None:
6522 return VK_CULL_MODE_NONE;
6523 case QRhiGraphicsPipeline::Front:
6524 return VK_CULL_MODE_FRONT_BIT;
6525 case QRhiGraphicsPipeline::Back:
6526 return VK_CULL_MODE_BACK_BIT;
6528 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6535 case QRhiGraphicsPipeline::CCW:
6536 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6537 case QRhiGraphicsPipeline::CW:
6538 return VK_FRONT_FACE_CLOCKWISE;
6540 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6547 if (c.testFlag(QRhiGraphicsPipeline::R))
6548 f |= VK_COLOR_COMPONENT_R_BIT;
6549 if (c.testFlag(QRhiGraphicsPipeline::G))
6550 f |= VK_COLOR_COMPONENT_G_BIT;
6551 if (c.testFlag(QRhiGraphicsPipeline::B))
6552 f |= VK_COLOR_COMPONENT_B_BIT;
6553 if (c.testFlag(QRhiGraphicsPipeline::A))
6554 f |= VK_COLOR_COMPONENT_A_BIT;
6555 return VkColorComponentFlags(f);
6561 case QRhiGraphicsPipeline::Zero:
6562 return VK_BLEND_FACTOR_ZERO;
6563 case QRhiGraphicsPipeline::One:
6564 return VK_BLEND_FACTOR_ONE;
6565 case QRhiGraphicsPipeline::SrcColor:
6566 return VK_BLEND_FACTOR_SRC_COLOR;
6567 case QRhiGraphicsPipeline::OneMinusSrcColor:
6568 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6569 case QRhiGraphicsPipeline::DstColor:
6570 return VK_BLEND_FACTOR_DST_COLOR;
6571 case QRhiGraphicsPipeline::OneMinusDstColor:
6572 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6573 case QRhiGraphicsPipeline::SrcAlpha:
6574 return VK_BLEND_FACTOR_SRC_ALPHA;
6575 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6576 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6577 case QRhiGraphicsPipeline::DstAlpha:
6578 return VK_BLEND_FACTOR_DST_ALPHA;
6579 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6580 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
6581 case QRhiGraphicsPipeline::ConstantColor:
6582 return VK_BLEND_FACTOR_CONSTANT_COLOR;
6583 case QRhiGraphicsPipeline::OneMinusConstantColor:
6584 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
6585 case QRhiGraphicsPipeline::ConstantAlpha:
6586 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
6587 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6588 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
6589 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6590 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
6591 case QRhiGraphicsPipeline::Src1Color:
6592 return VK_BLEND_FACTOR_SRC1_COLOR;
6593 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6594 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
6595 case QRhiGraphicsPipeline::Src1Alpha:
6596 return VK_BLEND_FACTOR_SRC1_ALPHA;
6597 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6598 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
6600 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
6607 case QRhiGraphicsPipeline::Add:
6608 return VK_BLEND_OP_ADD;
6609 case QRhiGraphicsPipeline::Subtract:
6610 return VK_BLEND_OP_SUBTRACT;
6611 case QRhiGraphicsPipeline::ReverseSubtract:
6612 return VK_BLEND_OP_REVERSE_SUBTRACT;
6613 case QRhiGraphicsPipeline::Min:
6614 return VK_BLEND_OP_MIN;
6615 case QRhiGraphicsPipeline::Max:
6616 return VK_BLEND_OP_MAX;
6618 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
6625 case QRhiGraphicsPipeline::Never:
6626 return VK_COMPARE_OP_NEVER;
6627 case QRhiGraphicsPipeline::Less:
6628 return VK_COMPARE_OP_LESS;
6629 case QRhiGraphicsPipeline::Equal:
6630 return VK_COMPARE_OP_EQUAL;
6631 case QRhiGraphicsPipeline::LessOrEqual:
6632 return VK_COMPARE_OP_LESS_OR_EQUAL;
6633 case QRhiGraphicsPipeline::Greater:
6634 return VK_COMPARE_OP_GREATER;
6635 case QRhiGraphicsPipeline::NotEqual:
6636 return VK_COMPARE_OP_NOT_EQUAL;
6637 case QRhiGraphicsPipeline::GreaterOrEqual:
6638 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6639 case QRhiGraphicsPipeline::Always:
6640 return VK_COMPARE_OP_ALWAYS;
6642 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
6649 case QRhiGraphicsPipeline::StencilZero:
6650 return VK_STENCIL_OP_ZERO;
6651 case QRhiGraphicsPipeline::Keep:
6652 return VK_STENCIL_OP_KEEP;
6653 case QRhiGraphicsPipeline::Replace:
6654 return VK_STENCIL_OP_REPLACE;
6655 case QRhiGraphicsPipeline::IncrementAndClamp:
6656 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
6657 case QRhiGraphicsPipeline::DecrementAndClamp:
6658 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
6659 case QRhiGraphicsPipeline::Invert:
6660 return VK_STENCIL_OP_INVERT;
6661 case QRhiGraphicsPipeline::IncrementAndWrap:
6662 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
6663 case QRhiGraphicsPipeline::DecrementAndWrap:
6664 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
6666 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
6673 case QRhiGraphicsPipeline::Fill:
6674 return VK_POLYGON_MODE_FILL;
6675 case QRhiGraphicsPipeline::Line:
6676 return VK_POLYGON_MODE_LINE;
6678 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
6684 dst->failOp = toVkStencilOp(src.failOp);
6685 dst->passOp = toVkStencilOp(src.passOp);
6686 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
6687 dst->compareOp = toVkCompareOp(src.compareOp);
6693 case QRhiShaderResourceBinding::UniformBuffer:
6694 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
6695 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
6697 case QRhiShaderResourceBinding::SampledTexture:
6698 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6700 case QRhiShaderResourceBinding::Texture:
6701 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
6703 case QRhiShaderResourceBinding::Sampler:
6704 return VK_DESCRIPTOR_TYPE_SAMPLER;
6706 case QRhiShaderResourceBinding::ImageLoad:
6707 case QRhiShaderResourceBinding::ImageStore:
6708 case QRhiShaderResourceBinding::ImageLoadStore:
6709 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
6711 case QRhiShaderResourceBinding::BufferLoad:
6712 case QRhiShaderResourceBinding::BufferStore:
6713 case QRhiShaderResourceBinding::BufferLoadStore:
6714 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
6717 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
6724 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
6725 s |= VK_SHADER_STAGE_VERTEX_BIT;
6726 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
6727 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
6728 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
6729 s |= VK_SHADER_STAGE_COMPUTE_BIT;
6730 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
6731 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6732 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
6733 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6734 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
6735 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
6736 return VkShaderStageFlags(s);
6742 case QRhiSampler::Never:
6743 return VK_COMPARE_OP_NEVER;
6744 case QRhiSampler::Less:
6745 return VK_COMPARE_OP_LESS;
6746 case QRhiSampler::Equal:
6747 return VK_COMPARE_OP_EQUAL;
6748 case QRhiSampler::LessOrEqual:
6749 return VK_COMPARE_OP_LESS_OR_EQUAL;
6750 case QRhiSampler::Greater:
6751 return VK_COMPARE_OP_GREATER;
6752 case QRhiSampler::NotEqual:
6753 return VK_COMPARE_OP_NOT_EQUAL;
6754 case QRhiSampler::GreaterOrEqual:
6755 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6756 case QRhiSampler::Always:
6757 return VK_COMPARE_OP_ALWAYS;
6759 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
6767 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
6787 e.buffer.buffers[i] = buffers[i];
6789 e.buffer.stagingBuffers[i] = stagingBuffers[i];
6792 buffers[i] = VK_NULL_HANDLE;
6794 stagingBuffers[i] = VK_NULL_HANDLE;
6796 pendingDynamicUpdates[i].clear();
6804 rhiD->releaseQueue.append(e);
6805 rhiD->unregisterResource(
this);
6814 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
6815 qWarning(
"StorageBuffer cannot be combined with Dynamic");
6819 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
6821 VkBufferCreateInfo bufferInfo = {};
6822 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
6823 bufferInfo.size = nonZeroSize;
6824 bufferInfo.usage = toVkBufferUsage(m_usage);
6826 VmaAllocationCreateInfo allocInfo = {};
6828 if (m_type == Dynamic) {
6833 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
6836 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
6838 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
6839 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
6843 VkResult err = VK_SUCCESS;
6845 buffers[i] = VK_NULL_HANDLE;
6847 usageState[i].access = usageState[i].stage = 0;
6848 if (i == 0 || m_type == Dynamic) {
6849 VmaAllocation allocation;
6850 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
6851 if (err != VK_SUCCESS)
6854 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
6855 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
6856 m_type == Dynamic ? i : -1);
6860 if (err != VK_SUCCESS) {
6861 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
6862 rhiD->printExtraErrorInfo(err);
6868 rhiD->registerResource(
this);
6874 if (m_type == Dynamic) {
6880 b.objects[i] = &buffers[i];
6885 return { { &buffers[0] }, 1 };
6895 Q_ASSERT(m_type == Dynamic);
6897 Q_ASSERT(rhiD->inFrame);
6898 const int slot = rhiD->currentFrameSlot;
6900 VmaAllocation a = toVmaAllocation(allocations[slot]);
6901 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
6902 if (err != VK_SUCCESS) {
6903 qWarning(
"Failed to map buffer: %d", err);
6906 return static_cast<
char *>(p);
6912 const int slot = rhiD->currentFrameSlot;
6913 VmaAllocation a = toVmaAllocation(allocations[slot]);
6914 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
6915 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
6919 int sampleCount, Flags flags,
6920 QRhiTexture::Format backingFormatHint)
6933 if (!memory && !backingTexture)
6940 e.renderBuffer.memory = memory;
6941 e.renderBuffer.image = image;
6942 e.renderBuffer.imageView = imageView;
6944 memory = VK_NULL_HANDLE;
6945 image = VK_NULL_HANDLE;
6946 imageView = VK_NULL_HANDLE;
6956 rhiD->releaseQueue.append(e);
6957 rhiD->unregisterResource(
this);
6963 if (memory || backingTexture)
6966 if (m_pixelSize.isEmpty())
6970 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
6973 case QRhiRenderBuffer::Color:
6976 backingTexture =
QRHI_RES(QVkTexture, rhiD->createTexture(backingFormat(),
6981 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
6983 backingTexture->setPixelSize(m_pixelSize);
6984 backingTexture->setSampleCount(m_sampleCount);
6986 backingTexture->setName(m_objectName);
6989 vkformat = backingTexture->vkformat;
6992 case QRhiRenderBuffer::DepthStencil:
6993 vkformat = rhiD->optimalDepthStencilFormat();
6994 if (!rhiD->createTransientImage(vkformat,
6996 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
6997 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7006 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7015 rhiD->registerResource(
this);
7021 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7022 return m_backingFormatHint;
7024 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7028 int arraySize,
int sampleCount, Flags flags)
7032 stagingBuffers[i] = VK_NULL_HANDLE;
7035 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7036 perLevelImageViews[i] = VK_NULL_HANDLE;
7053 e.texture.image = owns ? image : VK_NULL_HANDLE;
7054 e.texture.imageView = imageView;
7058 e.texture.stagingBuffers[i] = stagingBuffers[i];
7061 stagingBuffers[i] = VK_NULL_HANDLE;
7065 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7066 e.texture.extraImageViews[i] = perLevelImageViews[i];
7067 perLevelImageViews[i] = VK_NULL_HANDLE;
7070 image = VK_NULL_HANDLE;
7071 imageView = VK_NULL_HANDLE;
7076 rhiD->releaseQueue.append(e);
7077 rhiD->unregisterResource(
this);
7087 vkformat = toVkTextureFormat(m_format, m_flags);
7088 if (m_writeViewFormat.format != UnknownFormat)
7089 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7091 viewFormat = vkformat;
7092 if (m_readViewFormat.format != UnknownFormat)
7093 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7095 viewFormatForSampling = vkformat;
7097 VkFormatProperties props;
7098 rhiD->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7099 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7100 if (!canSampleOptimal) {
7101 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7105 const bool isCube = m_flags.testFlag(CubeMap);
7106 const bool isArray = m_flags.testFlag(TextureArray);
7107 const bool is3D = m_flags.testFlag(ThreeDimensional);
7108 const bool is1D = m_flags.testFlag(OneDimensional);
7109 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7111 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7112 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7114 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7115 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7116 if (mipLevelCount > maxLevels) {
7117 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7118 mipLevelCount = maxLevels;
7120 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7121 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7123 qWarning(
"Cubemap texture cannot be multisample");
7127 qWarning(
"3D texture cannot be multisample");
7131 qWarning(
"Multisample texture cannot have mipmaps");
7135 if (isCube && is3D) {
7136 qWarning(
"Texture cannot be both cube and 3D");
7139 if (isArray && is3D) {
7140 qWarning(
"Texture cannot be both array and 3D");
7143 if (isCube && is1D) {
7144 qWarning(
"Texture cannot be both cube and 1D");
7148 qWarning(
"Texture cannot be both 1D and 3D");
7151 if (m_depth > 1 && !is3D) {
7152 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7155 if (m_arraySize > 0 && !isArray) {
7156 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7159 if (m_arraySize < 1 && isArray) {
7160 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7164 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7165 usageState.access = 0;
7166 usageState.stage = 0;
7169 *adjustedSize = size;
7178 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7179 const bool isCube = m_flags.testFlag(CubeMap);
7180 const bool isArray = m_flags.testFlag(TextureArray);
7181 const bool is3D = m_flags.testFlag(ThreeDimensional);
7182 const bool is1D = m_flags.testFlag(OneDimensional);
7184 VkImageViewCreateInfo viewInfo = {};
7185 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7186 viewInfo.image = image;
7187 viewInfo.viewType = isCube
7188 ? VK_IMAGE_VIEW_TYPE_CUBE
7189 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7190 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7191 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7192 viewInfo.format = viewFormatForSampling;
7193 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7194 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7195 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7196 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7197 viewInfo.subresourceRange.aspectMask = aspectMask;
7200 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7201 viewInfo.subresourceRange.levelCount = mipLevelCount;
7202 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7203 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7204 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7206 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7209 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7210 if (err != VK_SUCCESS) {
7211 qWarning(
"Failed to create image view: %d", err);
7224 if (!prepareCreate(&size))
7228 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7229 const bool isDepth = isDepthTextureFormat(m_format);
7230 const bool isCube = m_flags.testFlag(CubeMap);
7231 const bool isArray = m_flags.testFlag(TextureArray);
7232 const bool is3D = m_flags.testFlag(ThreeDimensional);
7233 const bool is1D = m_flags.testFlag(OneDimensional);
7235 VkImageCreateInfo imageInfo = {};
7236 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7237 imageInfo.flags = 0;
7239 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7241 if (is3D && isRenderTarget) {
7247 if (!rhiD->caps.texture3DSliceAs2D)
7248 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7249#ifdef VK_VERSION_1_1
7250 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7252 imageInfo.flags |= 0x00000020;
7256 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7257 imageInfo.format = vkformat;
7258 imageInfo.extent.width = uint32_t(size.width());
7259 imageInfo.extent.height = uint32_t(size.height());
7260 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7261 imageInfo.mipLevels = mipLevelCount;
7262 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7263 imageInfo.samples = samples;
7264 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7265 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7267 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7268 if (isRenderTarget) {
7270 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7272 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7274 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7275 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7276 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7277 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7278 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7279 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7280#ifdef VK_KHR_fragment_shading_rate
7281 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7282 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7285 VmaAllocationCreateInfo allocInfo = {};
7286 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7288 VmaAllocation allocation;
7289 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7290 if (err != VK_SUCCESS) {
7291 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7292 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7293 int(imageInfo.format),
7294 imageInfo.mipLevels,
7295 imageInfo.arrayLayers,
7296 int(imageInfo.samples),
7298 rhiD->printExtraErrorInfo(err);
7302 rhiD->setAllocationName(allocation, m_objectName);
7307 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7310 rhiD->registerResource(
this);
7316 VkImage img = VkImage(src.object);
7320 if (!prepareCreate())
7328 usageState.layout = VkImageLayout(src.layout);
7332 rhiD->registerResource(
this);
7338 return {quint64(image), usageState.layout};
7343 usageState.layout = VkImageLayout(layout);
7348 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7349 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7350 return perLevelImageViews[level];
7352 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7353 const bool isCube = m_flags.testFlag(CubeMap);
7354 const bool isArray = m_flags.testFlag(TextureArray);
7355 const bool is3D = m_flags.testFlag(ThreeDimensional);
7356 const bool is1D = m_flags.testFlag(OneDimensional);
7358 VkImageViewCreateInfo viewInfo = {};
7359 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7360 viewInfo.image = image;
7361 viewInfo.viewType = isCube
7362 ? VK_IMAGE_VIEW_TYPE_CUBE
7363 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7364 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7365 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7366 viewInfo.format = viewFormat;
7367 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7368 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7369 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7370 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7371 viewInfo.subresourceRange.aspectMask = aspectMask;
7372 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7373 viewInfo.subresourceRange.levelCount = 1;
7374 viewInfo.subresourceRange.baseArrayLayer = 0;
7375 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7377 VkImageView v = VK_NULL_HANDLE;
7379 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7380 if (err != VK_SUCCESS) {
7381 qWarning(
"Failed to create image view: %d", err);
7382 return VK_NULL_HANDLE;
7385 perLevelImageViews[level] = v;
7390 AddressMode u, AddressMode v, AddressMode w)
7409 e.sampler.sampler = sampler;
7410 sampler = VK_NULL_HANDLE;
7414 rhiD->releaseQueue.append(e);
7415 rhiD->unregisterResource(
this);
7424 VkSamplerCreateInfo samplerInfo = {};
7425 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7426 samplerInfo.magFilter = toVkFilter(m_magFilter);
7427 samplerInfo.minFilter = toVkFilter(m_minFilter);
7428 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7429 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7430 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7431 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7432 samplerInfo.maxAnisotropy = 1.0f;
7433 samplerInfo.compareEnable = m_compareOp != Never;
7434 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7435 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7438 VkResult err = rhiD->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7439 if (err != VK_SUCCESS) {
7440 qWarning(
"Failed to create sampler: %d", err);
7446 rhiD->registerResource(
this);
7453 serializedFormatData.reserve(64);
7467 rp = VK_NULL_HANDLE;
7475 e.renderPass.rp = rp;
7477 rp = VK_NULL_HANDLE;
7481 rhiD->releaseQueue.append(e);
7482 rhiD->unregisterResource(
this);
7488 return a.format == b.format
7489 && a.samples == b.samples
7490 && a.loadOp == b.loadOp
7491 && a.storeOp == b.storeOp
7492 && a.stencilLoadOp == b.stencilLoadOp
7493 && a.stencilStoreOp == b.stencilStoreOp
7494 && a.initialLayout == b.initialLayout
7495 && a.finalLayout == b.finalLayout;
7508 if (attDescs.size() != o->attDescs.size())
7510 if (colorRefs.size() != o->colorRefs.size())
7512 if (resolveRefs.size() != o->resolveRefs.size())
7518 if (multiViewCount != o->multiViewCount)
7523 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7524 const uint32_t attIdx = colorRefs[i].attachment;
7525 if (attIdx != o->colorRefs[i].attachment)
7527 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7532 const uint32_t attIdx = dsRef.attachment;
7533 if (attIdx != o->dsRef.attachment)
7535 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7539 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7540 const uint32_t attIdx = resolveRefs[i].attachment;
7541 if (attIdx != o->resolveRefs[i].attachment)
7543 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7548 const uint32_t attIdx = dsResolveRef.attachment;
7549 if (attIdx != o->dsResolveRef.attachment)
7551 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7556 const uint32_t attIdx = shadingRateRef.attachment;
7557 if (attIdx != o->shadingRateRef.attachment)
7559 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7570 serializedFormatData.clear();
7571 auto p = std::back_inserter(serializedFormatData);
7573 *p++ = attDescs.size();
7574 *p++ = colorRefs.size();
7575 *p++ = resolveRefs.size();
7579 *p++ = multiViewCount;
7581 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
7582 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
7583 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
7584 *p++ = used ? a->format : 0;
7585 *p++ = used ? a->samples : 0;
7586 *p++ = used ? a->loadOp : 0;
7587 *p++ = used ? a->storeOp : 0;
7588 *p++ = used ? a->stencilLoadOp : 0;
7589 *p++ = used ? a->stencilStoreOp : 0;
7590 *p++ = used ? a->initialLayout : 0;
7591 *p++ = used ? a->finalLayout : 0;
7594 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7595 const uint32_t attIdx = colorRefs[i].attachment;
7597 serializeAttachmentData(attIdx);
7601 const uint32_t attIdx = dsRef.attachment;
7603 serializeAttachmentData(attIdx);
7606 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7607 const uint32_t attIdx = resolveRefs[i].attachment;
7609 serializeAttachmentData(attIdx);
7613 const uint32_t attIdx = dsResolveRef.attachment;
7615 serializeAttachmentData(attIdx);
7619 const uint32_t attIdx = shadingRateRef.attachment;
7621 serializeAttachmentData(attIdx);
7630 rpD->attDescs = attDescs;
7631 rpD->colorRefs = colorRefs;
7632 rpD->resolveRefs = resolveRefs;
7633 rpD->subpassDeps = subpassDeps;
7637 rpD->multiViewCount = multiViewCount;
7639 rpD->dsResolveRef = dsResolveRef;
7640 rpD->shadingRateRef = shadingRateRef;
7642 VkRenderPassCreateInfo rpInfo;
7643 VkSubpassDescription subpassDesc;
7644 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
7648 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
7653#ifdef VK_KHR_create_renderpass2
7654 if (rhiD->caps.renderPass2KHR) {
7656 VkRenderPassCreateInfo2KHR rpInfo2;
7657 RenderPass2SetupHelper rp2Helper(rhiD);
7658 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
7662 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
7663 if (err != VK_SUCCESS) {
7664 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
7671 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
7672 if (err != VK_SUCCESS) {
7673 qWarning(
"Failed to create renderpass: %d", err);
7680 rhiD->registerResource(rpD);
7686 return serializedFormatData;
7691 nativeHandlesStruct.renderPass = rp;
7692 return &nativeHandlesStruct;
7718 texture =
QRHI_RES(QVkTexture, src);
7750 return d.sampleCount;
7754 const QRhiTextureRenderTargetDescription &desc,
7759 rtv[att] = VK_NULL_HANDLE;
7760 resrtv[att] = VK_NULL_HANDLE;
7778 e.textureRenderTarget.fb = d.fb;
7779 d.fb = VK_NULL_HANDLE;
7782 e.textureRenderTarget.rtv[att] = rtv[att];
7783 e.textureRenderTarget.resrtv[att] = resrtv[att];
7784 rtv[att] = VK_NULL_HANDLE;
7785 resrtv[att] = VK_NULL_HANDLE;
7788 e.textureRenderTarget.dsv = dsv;
7789 dsv = VK_NULL_HANDLE;
7790 e.textureRenderTarget.resdsv = resdsv;
7791 resdsv = VK_NULL_HANDLE;
7793 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
7794 shadingRateMapView = VK_NULL_HANDLE;
7798 rhiD->releaseQueue.append(e);
7799 rhiD->unregisterResource(
this);
7809 if (!rhiD->createOffscreenRenderPass(rp,
7810 m_desc.cbeginColorAttachments(),
7811 m_desc.cendColorAttachments(),
7812 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
7813 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
7814 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
7815 m_desc.depthStencilBuffer(),
7816 m_desc.depthTexture(),
7817 m_desc.depthResolveTexture(),
7818 m_desc.shadingRateMap()))
7826 rhiD->registerResource(rp);
7835 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
7836 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
7837 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
7840 QVarLengthArray<VkImageView, 8> views;
7841 d.multiViewCount = 0;
7843 d.colorAttCount = 0;
7845 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
7846 d.colorAttCount += 1;
7849 Q_ASSERT(texD || rbD);
7851 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
7852 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
7853 const bool isMultiView = it->multiViewCount() >= 2;
7854 if (isMultiView && d.multiViewCount == 0)
7855 d.multiViewCount = it->multiViewCount();
7856 VkImageViewCreateInfo viewInfo = {};
7857 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7858 viewInfo.image = texD->image;
7859 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
7860 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
7861 : VK_IMAGE_VIEW_TYPE_2D);
7862 viewInfo.format = texD->viewFormat;
7863 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7864 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7865 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7866 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7867 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7868 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
7869 viewInfo.subresourceRange.levelCount = 1;
7870 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
7871 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
7872 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
7873 if (err != VK_SUCCESS) {
7874 qWarning(
"Failed to create render target image view: %d", err);
7877 views.append(rtv[attIndex]);
7878 if (attIndex == 0) {
7879 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
7880 d.sampleCount = texD->samples;
7885 if (attIndex == 0) {
7886 d.pixelSize = rbD->pixelSize();
7887 d.sampleCount = rbD->samples;
7893 if (hasDepthStencil) {
7894 if (m_desc.depthTexture()) {
7897 VkImageViewCreateInfo viewInfo = {};
7898 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7899 viewInfo.image = depthTexD->image;
7900 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
7901 viewInfo.format = depthTexD->viewFormat;
7902 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7903 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7904 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7905 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7906 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
7907 viewInfo.subresourceRange.levelCount = 1;
7908 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
7909 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
7910 if (err != VK_SUCCESS) {
7911 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
7915 if (d.colorAttCount == 0) {
7916 d.pixelSize = depthTexD->pixelSize();
7917 d.sampleCount = depthTexD->samples;
7921 views.append(depthRbD->imageView);
7922 if (d.colorAttCount == 0) {
7923 d.pixelSize = depthRbD->pixelSize();
7924 d.sampleCount = depthRbD->samples;
7932 d.resolveAttCount = 0;
7934 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
7935 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
7936 if (it->resolveTexture()) {
7938 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
7939 d.resolveAttCount += 1;
7941 VkImageViewCreateInfo viewInfo = {};
7942 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7943 viewInfo.image = resTexD->image;
7944 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
7945 : VK_IMAGE_VIEW_TYPE_2D;
7946 viewInfo.format = resTexD->viewFormat;
7947 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7948 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7949 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7950 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7951 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7952 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
7953 viewInfo.subresourceRange.levelCount = 1;
7954 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
7955 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
7956 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
7957 if (err != VK_SUCCESS) {
7958 qWarning(
"Failed to create render target resolve image view: %d", err);
7961 views.append(resrtv[attIndex]);
7965 if (m_desc.depthResolveTexture()) {
7967 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
7969 VkImageViewCreateInfo viewInfo = {};
7970 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7971 viewInfo.image = resTexD->image;
7972 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
7973 : VK_IMAGE_VIEW_TYPE_2D;
7974 viewInfo.format = resTexD->viewFormat;
7975 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7976 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7977 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7978 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7979 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
7980 viewInfo.subresourceRange.baseMipLevel = 0;
7981 viewInfo.subresourceRange.levelCount = 1;
7982 viewInfo.subresourceRange.baseArrayLayer = 0;
7983 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
7984 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
7985 if (err != VK_SUCCESS) {
7986 qWarning(
"Failed to create render target depth resolve image view: %d", err);
7989 views.append(resdsv);
7990 d.dsResolveAttCount = 1;
7992 d.dsResolveAttCount = 0;
7995 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
7997 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
7999 VkImageViewCreateInfo viewInfo = {};
8000 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8001 viewInfo.image = texD->image;
8002 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8003 : VK_IMAGE_VIEW_TYPE_2D;
8004 viewInfo.format = texD->viewFormat;
8005 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8006 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8007 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8008 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8009 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8010 viewInfo.subresourceRange.baseMipLevel = 0;
8011 viewInfo.subresourceRange.levelCount = 1;
8012 viewInfo.subresourceRange.baseArrayLayer = 0;
8013 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8014 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8015 if (err != VK_SUCCESS) {
8016 qWarning(
"Failed to create render target shading rate map view: %d", err);
8019 views.append(shadingRateMapView);
8020 d.shadingRateAttCount = 1;
8022 d.shadingRateAttCount = 0;
8025 if (!m_renderPassDesc)
8026 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8028 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8029 Q_ASSERT(d.rp && d.rp->rp);
8031 VkFramebufferCreateInfo fbInfo = {};
8032 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8033 fbInfo.renderPass = d.rp->rp;
8034 fbInfo.attachmentCount = uint32_t(views.count());
8035 fbInfo.pAttachments = views.constData();
8036 fbInfo.width = uint32_t(d.pixelSize.width());
8037 fbInfo.height = uint32_t(d.pixelSize.height());
8040 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8041 if (err != VK_SUCCESS) {
8042 qWarning(
"Failed to create framebuffer: %d", err);
8046 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8049 rhiD->registerResource(
this);
8055 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8068 return d.sampleCount;
8086 sortedBindings.clear();
8092 e.shaderResourceBindings.poolIndex =
poolIndex;
8093 e.shaderResourceBindings.layout = layout;
8096 layout = VK_NULL_HANDLE;
8097 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8098 descSets[i] = VK_NULL_HANDLE;
8102 rhiD->releaseQueue.append(e);
8103 rhiD->unregisterResource(
this);
8113 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8116 rhiD->updateLayoutDesc(
this);
8118 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8119 descSets[i] = VK_NULL_HANDLE;
8121 sortedBindings.clear();
8122 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
8123 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8126 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8127 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8128 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8129 if (b->u.ubuf.hasDynamicOffset)
8130 hasDynamicOffset =
true;
8134 QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
8135 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8136 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8137 VkDescriptorSetLayoutBinding vkbinding = {};
8138 vkbinding.binding = uint32_t(b->binding);
8139 vkbinding.descriptorType = toVkDescriptorType(b);
8140 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8141 vkbinding.descriptorCount = b->u.stex.count;
8143 vkbinding.descriptorCount = 1;
8144 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8145 vkbindings.append(vkbinding);
8148 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8149 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8150 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8151 layoutInfo.pBindings = vkbindings.constData();
8153 VkResult err = rhiD->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8154 if (err != VK_SUCCESS) {
8155 qWarning(
"Failed to create descriptor set layout: %d", err);
8159 VkDescriptorSetAllocateInfo allocInfo = {};
8160 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8163 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8164 layouts[i] = layout;
8165 allocInfo.pSetLayouts = layouts;
8166 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &poolIndex))
8170 boundResourceData[i].resize(sortedBindings.size());
8171 for (BoundResourceData &bd : boundResourceData[i])
8172 memset(&bd, 0,
sizeof(BoundResourceData));
8177 rhiD->registerResource(
this);
8183 sortedBindings.clear();
8184 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
8185 if (!flags.testFlag(BindingsAreSorted))
8186 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8198 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8199 for (BoundResourceData &bd : boundResourceData[i])
8200 memset(&bd, 0,
sizeof(BoundResourceData));
8218 if (!pipeline && !layout)
8225 e.pipelineState.pipeline = pipeline;
8226 e.pipelineState.layout = layout;
8228 pipeline = VK_NULL_HANDLE;
8229 layout = VK_NULL_HANDLE;
8233 rhiD->releaseQueue.append(e);
8234 rhiD->unregisterResource(
this);
8244 rhiD->pipelineCreationStart();
8245 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8248 if (!rhiD->ensurePipelineCache())
8251 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8252 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8253 pipelineLayoutInfo.setLayoutCount = 1;
8255 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8256 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8257 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8258 if (err != VK_SUCCESS) {
8259 qWarning(
"Failed to create pipeline layout: %d", err);
8263 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8264 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8266 QVarLengthArray<VkShaderModule, 4> shaders;
8267 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8268 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8269 const QShader bakedShader = shaderStage.shader();
8270 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8271 if (spirv.shader().isEmpty()) {
8272 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8275 VkShaderModule shader = rhiD->createShader(spirv.shader());
8277 shaders.append(shader);
8278 VkPipelineShaderStageCreateInfo shaderInfo = {};
8279 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8280 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8281 shaderInfo.module = shader;
8282 shaderInfo.pName = spirv.entryPoint().constData();
8283 shaderStageCreateInfos.append(shaderInfo);
8286 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8287 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8289 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8290#ifdef VK_EXT_vertex_attribute_divisor
8291 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8293 int bindingIndex = 0;
8294 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8295 it != itEnd; ++it, ++bindingIndex)
8297 VkVertexInputBindingDescription bindingInfo = {
8298 uint32_t(bindingIndex),
8300 it->classification() == QRhiVertexInputBinding::PerVertex
8301 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8303 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8304#ifdef VK_EXT_vertex_attribute_divisor
8305 if (rhiD->caps.vertexAttribDivisor) {
8306 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8310 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8311 "VK_EXT_vertex_attribute_divisor on the device and "
8312 "VK_KHR_get_physical_device_properties2 on the instance");
8315 vertexBindings.append(bindingInfo);
8317 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8318 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8321 VkVertexInputAttributeDescription attributeInfo = {
8322 uint32_t(it->location()),
8323 uint32_t(it->binding()),
8324 toVkAttributeFormat(it->format()),
8327 vertexAttributes.append(attributeInfo);
8329 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8330 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8331 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8332 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8333 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8334 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8335#ifdef VK_EXT_vertex_attribute_divisor
8336 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8337 if (!nonOneStepRates.isEmpty()) {
8338 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8339 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8340 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8341 vertexInputInfo.pNext = &divisorInfo;
8344 pipelineInfo.pVertexInputState = &vertexInputInfo;
8346 QVarLengthArray<VkDynamicState, 8> dynEnable;
8347 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8348 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8349 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8350 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8351 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8352 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8353#ifdef VK_KHR_fragment_shading_rate
8354 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8355 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8358 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8359 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8360 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8361 dynamicInfo.pDynamicStates = dynEnable.constData();
8362 pipelineInfo.pDynamicState = &dynamicInfo;
8364 VkPipelineViewportStateCreateInfo viewportInfo = {};
8365 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8366 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8367 pipelineInfo.pViewportState = &viewportInfo;
8369 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8370 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8371 inputAsmInfo.topology = toVkTopology(m_topology);
8372 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8373 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8375 VkPipelineTessellationStateCreateInfo tessInfo = {};
8376#ifdef VK_VERSION_1_1
8377 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8379 if (m_topology == Patches) {
8380 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8381 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8388#ifdef VK_VERSION_1_1
8389 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8390 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8391 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8392 tessInfo.pNext = &originInfo;
8394 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8397 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8400 pipelineInfo.pTessellationState = &tessInfo;
8403 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8404 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8405 rastInfo.cullMode = toVkCullMode(m_cullMode);
8406 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8407 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8408 rastInfo.depthBiasEnable =
true;
8409 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8410 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8412 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8413 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8414 pipelineInfo.pRasterizationState = &rastInfo;
8416 VkPipelineMultisampleStateCreateInfo msInfo = {};
8417 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8418 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8419 pipelineInfo.pMultisampleState = &msInfo;
8421 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8422 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8423 dsInfo.depthTestEnable = m_depthTest;
8424 dsInfo.depthWriteEnable = m_depthWrite;
8425 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8426 dsInfo.stencilTestEnable = m_stencilTest;
8427 if (m_stencilTest) {
8428 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8429 dsInfo.front.compareMask = m_stencilReadMask;
8430 dsInfo.front.writeMask = m_stencilWriteMask;
8431 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8432 dsInfo.back.compareMask = m_stencilReadMask;
8433 dsInfo.back.writeMask = m_stencilWriteMask;
8435 pipelineInfo.pDepthStencilState = &dsInfo;
8437 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8438 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8439 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8440 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8441 VkPipelineColorBlendAttachmentState blend = {};
8442 blend.blendEnable = b.enable;
8443 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8444 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8445 blend.colorBlendOp = toVkBlendOp(b.opColor);
8446 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8447 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8448 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8449 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8450 vktargetBlends.append(blend);
8452 if (vktargetBlends.isEmpty()) {
8453 VkPipelineColorBlendAttachmentState blend = {};
8454 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8455 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8456 vktargetBlends.append(blend);
8458 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8459 blendInfo.pAttachments = vktargetBlends.constData();
8460 pipelineInfo.pColorBlendState = &blendInfo;
8462 pipelineInfo.layout = layout;
8464 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8465 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8467 err = rhiD->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8469 for (VkShaderModule shader : shaders)
8470 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8472 if (err != VK_SUCCESS) {
8473 qWarning(
"Failed to create graphics pipeline: %d", err);
8477 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8479 rhiD->pipelineCreationEnd();
8482 rhiD->registerResource(
this);
8498 if (!pipeline && !layout)
8505 e.pipelineState.pipeline = pipeline;
8506 e.pipelineState.layout = layout;
8508 pipeline = VK_NULL_HANDLE;
8509 layout = VK_NULL_HANDLE;
8513 rhiD->releaseQueue.append(e);
8514 rhiD->unregisterResource(
this);
8524 rhiD->pipelineCreationStart();
8525 if (!rhiD->ensurePipelineCache())
8528 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8529 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8530 pipelineLayoutInfo.setLayoutCount = 1;
8532 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8533 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8534 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8535 if (err != VK_SUCCESS) {
8536 qWarning(
"Failed to create pipeline layout: %d", err);
8540 VkComputePipelineCreateInfo pipelineInfo = {};
8541 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8542 pipelineInfo.layout = layout;
8544 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
8545 qWarning(
"Compute pipeline requires a compute shader stage");
8548 const QShader bakedShader = m_shaderStage.shader();
8549 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
8550 if (spirv.shader().isEmpty()) {
8551 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8554 if (bakedShader.stage() != QShader::ComputeStage) {
8555 qWarning() << bakedShader <<
"is not a compute shader";
8558 VkShaderModule shader = rhiD->createShader(spirv.shader());
8559 VkPipelineShaderStageCreateInfo shaderInfo = {};
8560 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8561 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8562 shaderInfo.module = shader;
8563 shaderInfo.pName = spirv.entryPoint().constData();
8564 pipelineInfo.stage = shaderInfo;
8566 err = rhiD->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8567 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8568 if (err != VK_SUCCESS) {
8569 qWarning(
"Failed to create graphics pipeline: %d", err);
8573 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8575 rhiD->pipelineCreationEnd();
8578 rhiD->registerResource(
this);
8607 nativeHandlesStruct.commandBuffer = cb;
8609 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
8610 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
8612 nativeHandlesStruct.commandBuffer = cb;
8615 return &nativeHandlesStruct;
8633 if (sc == VK_NULL_HANDLE)
8638 rhiD->swapchains.remove(
this);
8644 frame.cmdBuf = VK_NULL_HANDLE;
8648 surface = lastConnectedSurface = VK_NULL_HANDLE;
8651 rhiD->unregisterResource(
this);
8666 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
8676 VkSurfaceCapabilitiesKHR surfaceCaps = {};
8678 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
8679 VkExtent2D bufferSize = surfaceCaps.currentExtent;
8680 if (bufferSize.width == uint32_t(-1)) {
8681 Q_ASSERT(bufferSize.height == uint32_t(-1));
8682 return m_window->size() * m_window->devicePixelRatio();
8684 return QSize(
int(bufferSize.width),
int(bufferSize.height));
8690 case QRhiSwapChain::HDRExtendedSrgbLinear:
8691 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8692 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
8693 case QRhiSwapChain::HDR10:
8694 return (s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || s.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32)
8695 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
8696 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
8697 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8698 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
8711 qWarning(
"Attempted to call isFormatSupported() without a window set");
8716 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8719 uint32_t formatCount = 0;
8720 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
8721 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
8723 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
8724 for (uint32_t i = 0; i < formatCount; ++i) {
8725 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
8737 QRHI_RES_RHI(QRhiVulkan);
8739 if (m_window && rhiD->adapterLuidValid)
8740 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
8754 if (!rhiD->createDefaultRenderPass(rp,
8755 m_depthStencil !=
nullptr,
8766 rhiD->registerResource(rp);
8773 case VK_FORMAT_R8_SRGB:
8774 case VK_FORMAT_R8G8_SRGB:
8775 case VK_FORMAT_R8G8B8_SRGB:
8776 case VK_FORMAT_B8G8R8_SRGB:
8777 case VK_FORMAT_R8G8B8A8_SRGB:
8778 case VK_FORMAT_B8G8R8A8_SRGB:
8779 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
8794 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8796 qWarning(
"Failed to get surface for window");
8799 if (surface == surf)
8805 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
8806 qWarning(
"Presenting not supported on this window");
8810 quint32 formatCount = 0;
8811 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
8812 QList<VkSurfaceFormatKHR> formats(formatCount);
8814 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, formats.data());
8818 const bool srgbRequested = m_flags.testFlag(sRGB);
8819 for (
int i = 0; i <
int(formatCount); ++i) {
8820 if (formats[i].format != VK_FORMAT_UNDEFINED) {
8821 bool ok = srgbRequested == isSrgbFormat(formats[i].format);
8822 if (m_format != SDR)
8823 ok &= hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
8825 colorFormat = formats[i].format;
8826 colorSpace = formats[i].colorSpace;
8832 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
8834 quint32 presModeCount = 0;
8835 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
8836 supportedPresentationModes.resize(presModeCount);
8837 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
8838 supportedPresentationModes.data());
8846 const bool needsRegistration = !window || window != m_window;
8853 if (window && window != m_window)
8857 m_currentPixelSize = surfacePixelSize();
8858 pixelSize = m_currentPixelSize;
8861 qWarning(
"Failed to create new swapchain");
8865 if (needsRegistration || !rhiD->swapchains.contains(
this))
8866 rhiD->swapchains.insert(
this);
8868 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
8869 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
8870 m_depthStencil->sampleCount(), m_sampleCount);
8872 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
8873 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
8874 m_depthStencil->setPixelSize(pixelSize);
8875 if (!m_depthStencil->create())
8876 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
8877 pixelSize.width(), pixelSize.height());
8879 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
8880 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
8881 pixelSize.width(), pixelSize.height());
8885 if (!m_renderPassDesc)
8886 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8888 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
8889 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8890 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
8892 rtWrapper.d.pixelSize = pixelSize;
8893 rtWrapper.d.dpr =
float(window->devicePixelRatio());
8894 rtWrapper.d.sampleCount = samples;
8895 rtWrapper.d.colorAttCount = 1;
8896 if (m_depthStencil) {
8897 rtWrapper.d.dsAttCount = 1;
8898 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
8900 rtWrapper.d.dsAttCount = 0;
8903 rtWrapper.d.dsResolveAttCount = 0;
8904 if (samples > VK_SAMPLE_COUNT_1_BIT)
8905 rtWrapper.d.resolveAttCount = 1;
8907 rtWrapper.d.resolveAttCount = 0;
8909 if (shadingRateMapView)
8910 rtWrapper.d.shadingRateAttCount = 1;
8912 rtWrapper.d.shadingRateAttCount = 0;
8917 QVarLengthArray<VkImageView, 4> views;
8918 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
8920 views.append(
ds->imageView);
8921 if (samples > VK_SAMPLE_COUNT_1_BIT)
8922 views.append(image.imageView);
8923 if (shadingRateMapView)
8924 views.append(shadingRateMapView);
8926 VkFramebufferCreateInfo fbInfo = {};
8927 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8928 fbInfo.renderPass = rtWrapper.d.rp->rp;
8929 fbInfo.attachmentCount = uint32_t(views.count());
8930 fbInfo.pAttachments = views.constData();
8931 fbInfo.width = uint32_t(pixelSize.width());
8932 fbInfo.height = uint32_t(pixelSize.height());
8935 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
8936 if (err != VK_SUCCESS) {
8937 qWarning(
"Failed to create framebuffer: %d", err);
8943 rtWrapperRight.setRenderPassDescriptor(
8945 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8946 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
8948 rtWrapperRight.d.pixelSize = pixelSize;
8949 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
8950 rtWrapperRight.d.sampleCount = samples;
8951 rtWrapperRight.d.colorAttCount = 1;
8952 if (m_depthStencil) {
8953 rtWrapperRight.d.dsAttCount = 1;
8954 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
8956 rtWrapperRight.d.dsAttCount = 0;
8959 rtWrapperRight.d.dsResolveAttCount = 0;
8960 if (samples > VK_SAMPLE_COUNT_1_BIT)
8961 rtWrapperRight.d.resolveAttCount = 1;
8963 rtWrapperRight.d.resolveAttCount = 0;
8968 QVarLengthArray<VkImageView, 4> views;
8969 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
8971 views.append(
ds->imageView);
8972 if (samples > VK_SAMPLE_COUNT_1_BIT)
8973 views.append(image.imageView);
8974 if (shadingRateMapView)
8975 views.append(shadingRateMapView);
8977 VkFramebufferCreateInfo fbInfo = {};
8978 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8979 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
8980 fbInfo.attachmentCount = uint32_t(views.count());
8981 fbInfo.pAttachments = views.constData();
8982 fbInfo.width = uint32_t(pixelSize.width());
8983 fbInfo.height = uint32_t(pixelSize.height());
8986 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
8987 if (err != VK_SUCCESS) {
8988 qWarning(
"Failed to create framebuffer: %d", err);
8996 if (needsRegistration)
8997 rhiD->registerResource(
this);
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, const UsageState &state)
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, const UsageState &state)
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker)
VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD=nullptr)
QRhiSwapChain * createSwapChain() override
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
int resourceLimit(QRhi::ResourceLimit limit) const override
bool isDeviceLost() const override
void prepareUploadSubres(QVkTexture *texD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, size_t *curOfs, void *mp, BufferImageCopyList *copyInfos)
void executeDeferredReleases(bool forced=false)
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex)
QRhi::FrameOpResult finish() override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples, VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count)
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
void releaseCachedResources() override
QVkSwapChain * currentSwapChain
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams=nullptr)
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
QList< int > supportedSampleCounts() const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb)
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *colorAttachmentsBegin, const QRhiColorAttachment *colorAttachmentsEnd, bool preserveColor, bool preserveDs, bool storeDs, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture, QRhiTexture *depthResolveTexture, QRhiShadingRateMap *shadingRateMap)
void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot, VkAccessFlags access, VkPipelineStageFlags stage)
QRhi::FrameOpResult waitCommandCompletion(int frameSlot)
void endExternal(QRhiCommandBuffer *cb) override
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex)
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
VkResult createDescriptorPool(VkDescriptorPool *pool)
void prepareNewFrame(QRhiCommandBuffer *cb)
void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, int startLayer, int layerCount, int startLevel, int levelCount)
QList< QSize > supportedShadingRates(int sampleCount) const override
void printExtraErrorInfo(VkResult err)
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb)
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker, QVkTexture *texD, QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage)
bool releaseCachedResourcesCalledBeforeFrameStart
QRhiGraphicsPipeline * createGraphicsPipeline() override
QRhiComputePipeline * createComputePipeline() override
void setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot=-1)
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
const QRhiNativeHandles * nativeHandles(QRhiCommandBuffer *cb) override
bool recreateSwapChain(QRhiSwapChain *swapChain)
bool ensurePipelineCache(const void *initialData=nullptr, size_t initialDataSize=0)
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD)
void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD, VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
VkShaderModule createShader(const QByteArray &spirv)
void enqueueTransitionPassResources(QVkCommandBuffer *cbD)
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
bool create(QRhi::Flags flags) override
QVulkanDeviceFunctions * df
void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot=-1)
bool isFeatureSupported(QRhi::Feature feature) const override
void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
bool isYUpInFramebuffer() const override
void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override
void debugMarkEnd(QRhiCommandBuffer *cb) override
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
void releaseSwapChainResources(QRhiSwapChain *swapChain)
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, QVkBuffer *bufD, int slot, QRhiPassResourceTracker::BufferAccess access, QRhiPassResourceTracker::BufferStage stage)
VkFormat optimalDepthStencilFormat()
QRhiStats statistics() override
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD)
void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
bool isYUpInNDC() const override
const QRhiNativeHandles * nativeHandles() override
QRhiShadingRateMap * createShadingRateMap() override
void setPipelineCacheData(const QByteArray &data) override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
QRhiShaderResourceBindings * createShaderResourceBindings() override
void finishActiveReadbacks(bool forced=false)
void ensureCommandPoolForNewFrame()
QByteArray pipelineCacheData() override
void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD)
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
bool isClipDepthZeroToOne() const override
void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
QMatrix4x4 clipSpaceCorrMatrix() const override
int ubufAlignment() const override
QRhiDriverInfo driverInfo() const override
void beginExternal(QRhiCommandBuffer *cb) override
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat, QRhiShadingRateMap *shadingRateMap)
QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence, VkSemaphore *waitSem, VkSemaphore *signalSem)
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount)
bool makeThreadLocalNativeContextCurrent() override
QRhiDriverInfo info() const override
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)