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.depthClamp = physDevFeatures.depthClamp;
954 caps.wideLines = physDevFeatures.wideLines;
956 caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1);
958 caps.tessellation = physDevFeatures.tessellationShader;
959 caps.geometryShader = physDevFeatures.geometryShader;
961 caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
964 if (caps.apiVersion >= QVersionNumber(1, 2))
965 caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
969 if (caps.apiVersion == QVersionNumber(1, 1))
970 caps.multiView = multiviewFeaturesIfApi11.multiview;
973#ifdef VK_KHR_fragment_shading_rate
974 fragmentShadingRates.clear();
975 if (caps.apiVersion >= QVersionNumber(1, 1)) {
976 caps.perDrawShadingRate = fragmentShadingRateFeatures.pipelineFragmentShadingRate;
977 caps.imageBasedShadingRate = fragmentShadingRateFeatures.attachmentFragmentShadingRate;
978 if (caps.imageBasedShadingRate) {
979 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shadingRateProps = {};
980 shadingRateProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
981 VkPhysicalDeviceProperties2 props2 = {};
982 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
983 props2.pNext = &shadingRateProps;
984 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
985 caps.imageBasedShadingRateTileSize =
int(shadingRateProps.maxFragmentShadingRateAttachmentTexelSize.width);
988 if (caps.perDrawShadingRate) {
989 PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR =
990 reinterpret_cast<PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR>(
991 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceFragmentShadingRatesKHR"));
992 if (vkGetPhysicalDeviceFragmentShadingRatesKHR) {
994 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count,
nullptr);
995 fragmentShadingRates.resize(count);
996 for (VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
998 s.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
1000 vkGetPhysicalDeviceFragmentShadingRatesKHR(physDev, &count, fragmentShadingRates.data());
1002 vkCmdSetFragmentShadingRateKHR =
reinterpret_cast<PFN_vkCmdSetFragmentShadingRateKHR>(
1003 f->vkGetDeviceProcAddr(dev,
"vkCmdSetFragmentShadingRateKHR"));
1012#ifdef VK_KHR_create_renderpass2
1013 if (caps.renderPass2KHR) {
1014 vkCreateRenderPass2KHR =
reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateRenderPass2KHR"));
1015 if (!vkCreateRenderPass2KHR)
1016 caps.renderPass2KHR =
false;
1022 adapterLuidValid =
false;
1024#ifdef VK_VERSION_1_2
1025 if (caps.apiVersion >= QVersionNumber(1, 2)) {
1026 VkPhysicalDeviceVulkan11Properties v11props = {};
1027 v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
1028 VkPhysicalDeviceProperties2 props2 = {};
1029 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1030 props2.pNext = &v11props;
1031 f->vkGetPhysicalDeviceProperties2(physDev, &props2);
1032 if (v11props.deviceLUIDValid) {
1033 const LUID *luid =
reinterpret_cast<
const LUID *>(v11props.deviceLUID);
1034 memcpy(&adapterLuid, luid, VK_LUID_SIZE);
1035 adapterLuidValid =
true;
1036 dxgiHdrInfo =
new QDxgiHdrInfo(adapterLuid);
1037 qCDebug(QRHI_LOG_INFO,
"DXGI adapter LUID for physical device is %lu, %lu",
1038 adapterLuid.LowPart, adapterLuid.HighPart);
1045 VmaVulkanFunctions funcs = {};
1046 funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
1047 funcs.vkGetDeviceProcAddr = wrap_vkGetDeviceProcAddr;
1049 VmaAllocatorCreateInfo allocatorInfo = {};
1052 allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
1053 allocatorInfo.physicalDevice = physDev;
1054 allocatorInfo.device = dev;
1055 allocatorInfo.pVulkanFunctions = &funcs;
1056 allocatorInfo.instance = inst->vkInstance();
1064#ifdef VK_VERSION_1_4
1065 if (caps.apiVersion >= QVersionNumber(1, 4))
1066 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
1069#ifdef VK_VERSION_1_3
1070 if (caps.apiVersion >= QVersionNumber(1, 3))
1071 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
1074#ifdef VK_VERSION_1_2
1075 if (caps.apiVersion >= QVersionNumber(1, 2))
1076 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
1079#ifdef VK_VERSION_1_1
1080 if (caps.apiVersion >= QVersionNumber(1, 1))
1081 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1;
1084#ifdef VK_VERSION_1_0
1085 allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1088 VmaAllocator vmaallocator;
1089 VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
1090 if (err != VK_SUCCESS) {
1091 qWarning(
"Failed to create allocator: %d", err);
1097 inst->installDebugOutputFilter(qvk_debug_filter);
1099 VkDescriptorPool pool;
1100 VkResult err = createDescriptorPool(&pool);
1101 if (err == VK_SUCCESS)
1102 descriptorPools.append(pool);
1104 qWarning(
"Failed to create initial descriptor pool: %d", err);
1106 VkQueryPoolCreateInfo timestampQueryPoolInfo = {};
1107 timestampQueryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1108 timestampQueryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
1110 err = df->vkCreateQueryPool(dev, ×tampQueryPoolInfo,
nullptr, ×tampQueryPool);
1111 if (err != VK_SUCCESS) {
1112 qWarning(
"Failed to create timestamp query pool: %d", err);
1115 timestampQueryPoolMap.resize(QVK_MAX_ACTIVE_TIMESTAMP_PAIRS);
1116 timestampQueryPoolMap.fill(
false);
1118#ifdef VK_EXT_debug_utils
1119 if (caps.debugUtils) {
1120 vkSetDebugUtilsObjectNameEXT =
reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(f->vkGetDeviceProcAddr(dev,
"vkSetDebugUtilsObjectNameEXT"));
1121 vkCmdBeginDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdBeginDebugUtilsLabelEXT"));
1122 vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdEndDebugUtilsLabelEXT"));
1123 vkCmdInsertDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(f->vkGetDeviceProcAddr(dev,
"vkCmdInsertDebugUtilsLabelEXT"));
1129 nativeHandlesStruct.physDev = physDev;
1130 nativeHandlesStruct.dev = dev;
1131 nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
1132 nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
1133 nativeHandlesStruct.gfxQueue = gfxQueue;
1134 nativeHandlesStruct.vmemAllocator = allocator;
1135 nativeHandlesStruct.inst = inst;
1146 df->vkDeviceWaitIdle(dev);
1153 dxgiHdrInfo =
nullptr;
1157 df->vkDestroyFence(dev, ofr.cmdFence,
nullptr);
1158 ofr.cmdFence = VK_NULL_HANDLE;
1161 if (pipelineCache) {
1162 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
1163 pipelineCache = VK_NULL_HANDLE;
1166 for (
const DescriptorPoolData &pool : descriptorPools)
1167 df->vkDestroyDescriptorPool(dev, pool.pool,
nullptr);
1169 descriptorPools.clear();
1171 if (timestampQueryPool) {
1172 df->vkDestroyQueryPool(dev, timestampQueryPool,
nullptr);
1173 timestampQueryPool = VK_NULL_HANDLE;
1177 vmaDestroyAllocator(toVmaAllocator(allocator));
1183 df->vkDestroyCommandPool(dev, cmdPool[i],
nullptr);
1184 cmdPool[i] = VK_NULL_HANDLE;
1186 freeSecondaryCbs[i].clear();
1187 ofr.cbWrapper[i]->cb = VK_NULL_HANDLE;
1190 if (!importedDevice && dev) {
1191 df->vkDestroyDevice(dev,
nullptr);
1192 inst->resetDeviceFunctions(dev);
1193 dev = VK_NULL_HANDLE;
1203QRhi::AdapterList
QRhiVulkan::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
1205 VkPhysicalDevice requestedPhysDev = VK_NULL_HANDLE;
1206 if (nativeHandles) {
1207 QRhiVulkanNativeHandles *h =
static_cast<QRhiVulkanNativeHandles *>(nativeHandles);
1208 requestedPhysDev = h->physDev;
1211 QRhi::AdapterList list;
1212 QVulkanFunctions *f = inst->functions();
1213 uint32_t physDevCount = 0;
1214 f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount,
nullptr);
1218 QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
1219 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, physDevs.data());
1220 if (err != VK_SUCCESS || !physDevCount)
1223 VkPhysicalDeviceProperties physDevProperties = {};
1224 for (uint32_t i = 0; i < physDevCount; ++i) {
1225 if (requestedPhysDev && physDevs[i] != requestedPhysDev)
1228 f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
1229 QVulkanAdapter *a =
new QVulkanAdapter;
1230 a->physDev = physDevs[i];
1231 fillDriverInfo(&a->adapterInfo, physDevProperties);
1245 VkDescriptorPoolSize descPoolSizes[] = {
1246 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
1247 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
1248 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL },
1249 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, QVK_STORAGE_BUFFERS_PER_POOL },
1250 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, QVK_STORAGE_IMAGES_PER_POOL }
1252 VkDescriptorPoolCreateInfo descPoolInfo = {};
1253 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1257 descPoolInfo.flags = 0;
1259 descPoolInfo.poolSizeCount =
sizeof(descPoolSizes) /
sizeof(descPoolSizes[0]);
1260 descPoolInfo.pPoolSizes = descPoolSizes;
1261 return df->vkCreateDescriptorPool(dev, &descPoolInfo,
nullptr, pool);
1266 auto tryAllocate = [
this, allocInfo, result](
int poolIndex) {
1267 allocInfo->descriptorPool = descriptorPools[poolIndex].pool;
1268 VkResult r = df->vkAllocateDescriptorSets(dev, allocInfo, result);
1269 if (r == VK_SUCCESS)
1270 descriptorPools[poolIndex].refCount += 1;
1274 int lastPoolIdx = descriptorPools.size() - 1;
1275 for (
int i = lastPoolIdx; i >= 0; --i) {
1276 if (descriptorPools[i].refCount == 0) {
1277 df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
1278 descriptorPools[i].allocedDescSets = 0;
1280 if (descriptorPools[i].allocedDescSets +
int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
1281 VkResult err = tryAllocate(i);
1282 if (err == VK_SUCCESS) {
1283 descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
1284 *resultPoolIndex = i;
1290 VkDescriptorPool newPool;
1291 VkResult poolErr = createDescriptorPool(&newPool);
1292 if (poolErr == VK_SUCCESS) {
1293 descriptorPools.append(newPool);
1294 lastPoolIdx = descriptorPools.size() - 1;
1295 VkResult err = tryAllocate(lastPoolIdx);
1296 if (err != VK_SUCCESS) {
1297 qWarning(
"Failed to allocate descriptor set from new pool too, giving up: %d", err);
1300 descriptorPools[lastPoolIdx].allocedDescSets += allocInfo->descriptorSetCount;
1301 *resultPoolIndex = lastPoolIdx;
1304 qWarning(
"Failed to allocate new descriptor pool: %d", poolErr);
1311 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1313 case QRhiTexture::RGBA8:
1314 return srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
1315 case QRhiTexture::BGRA8:
1316 return srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
1317 case QRhiTexture::R8:
1318 return srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM;
1319 case QRhiTexture::RG8:
1320 return srgb ? VK_FORMAT_R8G8_SRGB : VK_FORMAT_R8G8_UNORM;
1321 case QRhiTexture::R16:
1322 return VK_FORMAT_R16_UNORM;
1323 case QRhiTexture::RG16:
1324 return VK_FORMAT_R16G16_UNORM;
1325 case QRhiTexture::RED_OR_ALPHA8:
1326 return VK_FORMAT_R8_UNORM;
1328 case QRhiTexture::RGBA16F:
1329 return VK_FORMAT_R16G16B16A16_SFLOAT;
1330 case QRhiTexture::RGBA32F:
1331 return VK_FORMAT_R32G32B32A32_SFLOAT;
1332 case QRhiTexture::R16F:
1333 return VK_FORMAT_R16_SFLOAT;
1334 case QRhiTexture::R32F:
1335 return VK_FORMAT_R32_SFLOAT;
1337 case QRhiTexture::RGB10A2:
1339 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1341 case QRhiTexture::R8SI:
1342 return VK_FORMAT_R8_SINT;
1343 case QRhiTexture::R32SI:
1344 return VK_FORMAT_R32_SINT;
1345 case QRhiTexture::RG32SI:
1346 return VK_FORMAT_R32G32_SINT;
1347 case QRhiTexture::RGBA32SI:
1348 return VK_FORMAT_R32G32B32A32_SINT;
1350 case QRhiTexture::R8UI:
1351 return VK_FORMAT_R8_UINT;
1352 case QRhiTexture::R32UI:
1353 return VK_FORMAT_R32_UINT;
1354 case QRhiTexture::RG32UI:
1355 return VK_FORMAT_R32G32_UINT;
1356 case QRhiTexture::RGBA32UI:
1357 return VK_FORMAT_R32G32B32A32_UINT;
1359 case QRhiTexture::D16:
1360 return VK_FORMAT_D16_UNORM;
1361 case QRhiTexture::D24:
1362 return VK_FORMAT_X8_D24_UNORM_PACK32;
1363 case QRhiTexture::D24S8:
1364 return VK_FORMAT_D24_UNORM_S8_UINT;
1365 case QRhiTexture::D32F:
1366 return VK_FORMAT_D32_SFLOAT;
1367 case QRhiTexture::D32FS8:
1368 return VK_FORMAT_D32_SFLOAT_S8_UINT;
1370 case QRhiTexture::BC1:
1371 return srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1372 case QRhiTexture::BC2:
1373 return srgb ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
1374 case QRhiTexture::BC3:
1375 return srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
1376 case QRhiTexture::BC4:
1377 return VK_FORMAT_BC4_UNORM_BLOCK;
1378 case QRhiTexture::BC5:
1379 return VK_FORMAT_BC5_UNORM_BLOCK;
1380 case QRhiTexture::BC6H:
1381 return VK_FORMAT_BC6H_UFLOAT_BLOCK;
1382 case QRhiTexture::BC7:
1383 return srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
1385 case QRhiTexture::ETC2_RGB8:
1386 return srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1387 case QRhiTexture::ETC2_RGB8A1:
1388 return srgb ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
1389 case QRhiTexture::ETC2_RGBA8:
1390 return srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
1392 case QRhiTexture::ASTC_4x4:
1393 return srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
1394 case QRhiTexture::ASTC_5x4:
1395 return srgb ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
1396 case QRhiTexture::ASTC_5x5:
1397 return srgb ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
1398 case QRhiTexture::ASTC_6x5:
1399 return srgb ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
1400 case QRhiTexture::ASTC_6x6:
1401 return srgb ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
1402 case QRhiTexture::ASTC_8x5:
1403 return srgb ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
1404 case QRhiTexture::ASTC_8x6:
1405 return srgb ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
1406 case QRhiTexture::ASTC_8x8:
1407 return srgb ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
1408 case QRhiTexture::ASTC_10x5:
1409 return srgb ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
1410 case QRhiTexture::ASTC_10x6:
1411 return srgb ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
1412 case QRhiTexture::ASTC_10x8:
1413 return srgb ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
1414 case QRhiTexture::ASTC_10x10:
1415 return srgb ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
1416 case QRhiTexture::ASTC_12x10:
1417 return srgb ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
1418 case QRhiTexture::ASTC_12x12:
1419 return srgb ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
1422 Q_UNREACHABLE_RETURN(VK_FORMAT_R8G8B8A8_UNORM);
1429 case VK_FORMAT_R8G8B8A8_UNORM:
1430 return QRhiTexture::RGBA8;
1431 case VK_FORMAT_R8G8B8A8_SRGB:
1433 (*flags) |= QRhiTexture::sRGB;
1434 return QRhiTexture::RGBA8;
1435 case VK_FORMAT_B8G8R8A8_UNORM:
1436 return QRhiTexture::BGRA8;
1437 case VK_FORMAT_B8G8R8A8_SRGB:
1439 (*flags) |= QRhiTexture::sRGB;
1440 return QRhiTexture::BGRA8;
1441 case VK_FORMAT_R16G16B16A16_SFLOAT:
1442 return QRhiTexture::RGBA16F;
1443 case VK_FORMAT_R32G32B32A32_SFLOAT:
1444 return QRhiTexture::RGBA32F;
1445 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1446 return QRhiTexture::RGB10A2;
1448 qWarning(
"VkFormat %d cannot be read back", format);
1451 return QRhiTexture::UnknownFormat;
1457 case QRhiTexture::Format::D16:
1458 case QRhiTexture::Format::D24:
1459 case QRhiTexture::Format::D24S8:
1460 case QRhiTexture::Format::D32F:
1461 case QRhiTexture::Format::D32FS8:
1472 case QRhiTexture::Format::D24S8:
1473 case QRhiTexture::Format::D32FS8:
1483 if (isDepthTextureFormat(format)) {
1484 if (isStencilTextureFormat(format))
1485 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1487 return VK_IMAGE_ASPECT_DEPTH_BIT;
1489 return VK_IMAGE_ASPECT_COLOR_BIT;
1500 VkPhysicalDeviceMemoryProperties physDevMemProps;
1501 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
1503 VkMemoryRequirements memReq;
1504 df->vkGetImageMemoryRequirements(dev, img, &memReq);
1505 uint32_t memTypeIndex = uint32_t(-1);
1507 if (memReq.memoryTypeBits) {
1509 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1510 bool foundDevLocal =
false;
1511 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1512 if (memReq.memoryTypeBits & (1 << i)) {
1513 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1514 if (!foundDevLocal) {
1515 foundDevLocal =
true;
1518 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1527 return memTypeIndex;
1531 const QSize &pixelSize,
1532 VkImageUsageFlags usage,
1533 VkImageAspectFlags aspectMask,
1534 VkSampleCountFlagBits samples,
1535 VkDeviceMemory *mem,
1540 VkMemoryRequirements memReq;
1543 for (
int i = 0; i < count; ++i) {
1544 VkImageCreateInfo imgInfo = {};
1545 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1546 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1547 imgInfo.format = format;
1548 imgInfo.extent.width = uint32_t(pixelSize.width());
1549 imgInfo.extent.height = uint32_t(pixelSize.height());
1550 imgInfo.extent.depth = 1;
1551 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1552 imgInfo.samples = samples;
1553 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1554 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1555 imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1557 err = df->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1558 if (err != VK_SUCCESS) {
1559 qWarning(
"Failed to create image: %d", err);
1566 df->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1569 VkMemoryAllocateInfo memInfo = {};
1570 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1571 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
1573 uint32_t startIndex = 0;
1575 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1576 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1577 qWarning(
"No suitable memory type found");
1580 startIndex = memInfo.memoryTypeIndex + 1;
1581 err = df->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1582 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1583 qWarning(
"Failed to allocate image memory: %d", err);
1586 }
while (err != VK_SUCCESS);
1588 VkDeviceSize ofs = 0;
1589 for (
int i = 0; i < count; ++i) {
1590 err = df->vkBindImageMemory(dev, images[i], *mem, ofs);
1591 if (err != VK_SUCCESS) {
1592 qWarning(
"Failed to bind image memory: %d", err);
1595 ofs += aligned(memReq.size, memReq.alignment);
1597 VkImageViewCreateInfo imgViewInfo = {};
1598 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1599 imgViewInfo.image = images[i];
1600 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1601 imgViewInfo.format = format;
1602 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1603 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1604 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1605 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1606 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1607 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1609 err = df->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1610 if (err != VK_SUCCESS) {
1611 qWarning(
"Failed to create image view: %d", err);
1621 if (optimalDsFormat != VK_FORMAT_UNDEFINED)
1622 return optimalDsFormat;
1624 const VkFormat dsFormatCandidates[] = {
1625 VK_FORMAT_D24_UNORM_S8_UINT,
1626 VK_FORMAT_D32_SFLOAT_S8_UINT,
1627 VK_FORMAT_D16_UNORM_S8_UINT
1629 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
1630 int dsFormatIdx = 0;
1631 while (dsFormatIdx < dsFormatCandidateCount) {
1632 optimalDsFormat = dsFormatCandidates[dsFormatIdx];
1633 VkFormatProperties fmtProp;
1634 f->vkGetPhysicalDeviceFormatProperties(physDev, optimalDsFormat, &fmtProp);
1635 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
1639 if (dsFormatIdx == dsFormatCandidateCount)
1640 qWarning(
"Failed to find an optimal depth-stencil format");
1642 return optimalDsFormat;
1647 bool prepare(VkRenderPassCreateInfo *rpInfo,
int multiViewCount,
bool multiViewCap)
1649 if (multiViewCount < 2)
1651 if (!multiViewCap) {
1652 qWarning(
"Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
1655#ifdef VK_VERSION_1_1
1656 uint32_t allViewsMask = 0;
1657 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1658 allViewsMask |= (1 << i);
1659 multiViewMask = allViewsMask;
1660 multiViewCorrelationMask = allViewsMask;
1661 multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1662 multiViewInfo.subpassCount = 1;
1663 multiViewInfo.pViewMasks = &multiViewMask;
1664 multiViewInfo.correlationMaskCount = 1;
1665 multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
1666 rpInfo->pNext = &multiViewInfo;
1671#ifdef VK_VERSION_1_1
1678#ifdef VK_KHR_create_renderpass2
1682struct RenderPass2SetupHelper
1684 RenderPass2SetupHelper(QRhiVulkan *rhiD) : rhiD(rhiD) { }
1686 bool prepare(VkRenderPassCreateInfo2 *rpInfo2,
const VkRenderPassCreateInfo *rpInfo,
const QVkRenderPassDescriptor *rpD,
int multiViewCount) {
1690 if (multiViewCount >= 2) {
1691 for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
1692 viewMask |= (1 << i);
1695 attDescs2.resize(rpInfo->attachmentCount);
1696 for (qsizetype i = 0; i < attDescs2.count(); ++i) {
1697 VkAttachmentDescription2KHR &att2(attDescs2[i]);
1698 const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
1700 att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
1701 att2.flags = att.flags;
1702 att2.format = att.format;
1703 att2.samples = att.samples;
1704 att2.loadOp = att.loadOp;
1705 att2.storeOp = att.storeOp;
1706 att2.stencilLoadOp = att.stencilLoadOp;
1707 att2.stencilStoreOp = att.stencilStoreOp;
1708 att2.initialLayout = att.initialLayout;
1709 att2.finalLayout = att.finalLayout;
1714 subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
1715 const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
1716 subpass2.flags = subpassDesc.flags;
1717 subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
1718 if (multiViewCount >= 2)
1719 subpass2.viewMask = viewMask;
1722 qsizetype startIndex = attRefs2.count();
1723 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1724 attRefs2.append({});
1725 VkAttachmentReference2KHR &attref2(attRefs2.last());
1726 const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
1727 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1728 attref2.attachment = attref.attachment;
1729 attref2.layout = attref.layout;
1730 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1732 subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
1733 subpass2.pColorAttachments = attRefs2.constData() + startIndex;
1736 if (subpassDesc.pResolveAttachments) {
1737 startIndex = attRefs2.count();
1738 for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
1739 attRefs2.append({});
1740 VkAttachmentReference2KHR &attref2(attRefs2.last());
1741 const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
1742 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1743 attref2.attachment = attref.attachment;
1744 attref2.layout = attref.layout;
1745 attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1747 subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
1751 if (subpassDesc.pDepthStencilAttachment) {
1752 startIndex = attRefs2.count();
1753 attRefs2.append({});
1754 VkAttachmentReference2KHR &attref2(attRefs2.last());
1755 const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
1756 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1757 attref2.attachment = attref.attachment;
1758 attref2.layout = attref.layout;
1759 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1760 subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
1764#ifdef VK_KHR_depth_stencil_resolve
1766 if (rpD->hasDepthStencilResolve) {
1767 startIndex = attRefs2.count();
1768 attRefs2.append({});
1769 VkAttachmentReference2KHR &attref2(attRefs2.last());
1770 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1771 attref2.attachment = rpD->dsResolveRef.attachment;
1772 attref2.layout = rpD->dsResolveRef.layout;
1773 attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1774 dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
1775 dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1776 dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1777 dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
1778 addToChain(&subpass2, &dsResolveDesc);
1782#ifdef VK_KHR_fragment_shading_rate
1783 shadingRateAttInfo = {};
1784 if (rpD->hasShadingRateMap) {
1785 startIndex = attRefs2.count();
1786 attRefs2.append({});
1787 VkAttachmentReference2KHR &attref2(attRefs2.last());
1788 attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
1789 attref2.attachment = rpD->shadingRateRef.attachment;
1790 attref2.layout = rpD->shadingRateRef.layout;
1791 shadingRateAttInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
1792 shadingRateAttInfo.pFragmentShadingRateAttachment = attRefs2.constData() + startIndex;
1793 shadingRateAttInfo.shadingRateAttachmentTexelSize.width = rhiD->caps.imageBasedShadingRateTileSize;
1794 shadingRateAttInfo.shadingRateAttachmentTexelSize.height = rhiD->caps.imageBasedShadingRateTileSize;
1795 addToChain(&subpass2, &shadingRateAttInfo);
1801 subpassDeps2.clear();
1802 for (uint32_t i = 0; i < rpInfo->dependencyCount; ++i) {
1803 const VkSubpassDependency &dep(rpInfo->pDependencies[i]);
1804 subpassDeps2.append({});
1805 VkSubpassDependency2 &dep2(subpassDeps2.last());
1806 dep2.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
1807 dep2.srcSubpass = dep.srcSubpass;
1808 dep2.dstSubpass = dep.dstSubpass;
1809 dep2.srcStageMask = dep.srcStageMask;
1810 dep2.dstStageMask = dep.dstStageMask;
1811 dep2.srcAccessMask = dep.srcAccessMask;
1812 dep2.dstAccessMask = dep.dstAccessMask;
1813 dep2.dependencyFlags = dep.dependencyFlags;
1816 rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
1817 rpInfo2->pNext =
nullptr;
1818 rpInfo2->flags = rpInfo->flags;
1819 rpInfo2->attachmentCount = rpInfo->attachmentCount;
1820 rpInfo2->pAttachments = attDescs2.constData();
1821 rpInfo2->subpassCount = 1;
1822 rpInfo2->pSubpasses = &subpass2;
1823 rpInfo2->dependencyCount = subpassDeps2.count();
1824 rpInfo2->pDependencies = !subpassDeps2.isEmpty() ? subpassDeps2.constData() :
nullptr;
1825 if (multiViewCount >= 2) {
1826 rpInfo2->correlatedViewMaskCount = 1;
1827 rpInfo2->pCorrelatedViewMasks = &viewMask;
1833 QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
1834 QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
1835 VkSubpassDescription2KHR subpass2;
1836 QVarLengthArray<VkSubpassDependency2KHR, 4> subpassDeps2;
1837#ifdef VK_KHR_depth_stencil_resolve
1838 VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
1840#ifdef VK_KHR_fragment_shading_rate
1841 VkFragmentShadingRateAttachmentInfoKHR shadingRateAttInfo;
1848 VkSubpassDescription *subpassDesc,
1851 memset(subpassDesc, 0,
sizeof(VkSubpassDescription));
1852 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1853 subpassDesc->colorAttachmentCount = uint32_t(rpD->colorRefs.size());
1854 subpassDesc->pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() :
nullptr;
1855 subpassDesc->pDepthStencilAttachment = rpD
->hasDepthStencil ? &rpD->dsRef :
nullptr;
1856 subpassDesc->pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() :
nullptr;
1858 memset(rpInfo, 0,
sizeof(VkRenderPassCreateInfo));
1859 rpInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1860 rpInfo->attachmentCount = uint32_t(rpD->attDescs.size());
1861 rpInfo->pAttachments = rpD->attDescs.constData();
1862 rpInfo->subpassCount = 1;
1863 rpInfo->pSubpasses = subpassDesc;
1864 rpInfo->dependencyCount = uint32_t(rpD->subpassDeps.size());
1865 rpInfo->pDependencies = !rpD->subpassDeps.isEmpty() ? rpD->subpassDeps.constData() :
nullptr;
1869 bool hasDepthStencil,
1870 VkSampleCountFlagBits samples,
1871 VkFormat colorFormat,
1872 QRhiShadingRateMap *shadingRateMap)
1876 VkAttachmentDescription attDesc = {};
1877 attDesc.format = colorFormat;
1878 attDesc.samples = samples;
1879 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1880 attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
1881 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1882 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1883 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1884 attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1885 rpD->attDescs.append(attDesc);
1887 rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1892 rpD->multiViewCount = 0;
1894 if (hasDepthStencil) {
1898 attDesc.format = optimalDepthStencilFormat();
1899 attDesc.samples = samples;
1900 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1901 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1902 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1903 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1904 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1905 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1906 rpD->attDescs.append(attDesc);
1908 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1913 if (samples > VK_SAMPLE_COUNT_1_BIT) {
1915 attDesc.format = colorFormat;
1916 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1917 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1918 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1919 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1920 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1921 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1922 attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1923 rpD->attDescs.append(attDesc);
1925 rpD->resolveRefs.append({ uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
1928 rpD->dsResolveRef = {};
1930 rpD->shadingRateRef = {};
1931#ifdef VK_KHR_fragment_shading_rate
1932 if (shadingRateMap) {
1934 attDesc.format = VK_FORMAT_R8_UINT;
1935 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
1936 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1937 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1938 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1939 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1940 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1941 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
1942 rpD->attDescs.append(attDesc);
1944 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
1949 VkSubpassDependency subpassDep = {};
1950 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1951 subpassDep.dstSubpass = 0;
1952 subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1953 subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1954 subpassDep.srcAccessMask = 0;
1955 subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1956 rpD->subpassDeps.append(subpassDep);
1957 if (hasDepthStencil) {
1958 memset(&subpassDep, 0,
sizeof(subpassDep));
1959 subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
1960 subpassDep.dstSubpass = 0;
1961 subpassDep.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1962 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1963 subpassDep.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
1964 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1965 subpassDep.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1966 subpassDep.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
1967 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1968 rpD->subpassDeps.append(subpassDep);
1971 VkRenderPassCreateInfo rpInfo;
1972 VkSubpassDescription subpassDesc;
1973 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
1975#ifdef VK_KHR_create_renderpass2
1976 if (caps.renderPass2KHR) {
1978 VkRenderPassCreateInfo2KHR rpInfo2;
1979 RenderPass2SetupHelper rp2Helper(
this);
1980 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, 0))
1982 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
1983 if (err != VK_SUCCESS) {
1984 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
1991 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
1992 VkResult err = df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
1993 if (err != VK_SUCCESS) {
1994 qWarning(
"Failed to create renderpass: %d", err);
2003 const QRhiColorAttachment *colorAttachmentsBegin,
2004 const QRhiColorAttachment *colorAttachmentsEnd,
2008 QRhiRenderBuffer *depthStencilBuffer,
2009 QRhiTexture *depthTexture,
2010 QRhiTexture *depthResolveTexture,
2011 QRhiShadingRateMap *shadingRateMap)
2015 int multiViewCount = 0;
2016 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2019 Q_ASSERT(texD || rbD);
2020 const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
2021 const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
2023 VkAttachmentDescription attDesc = {};
2024 attDesc.format = vkformat;
2025 attDesc.samples = samples;
2026 attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2027 attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
2028 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2029 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2031 attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2032 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2033 rpD->attDescs.append(attDesc);
2035 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2036 rpD->colorRefs.append(ref);
2038 if (it->multiViewCount() >= 2) {
2039 if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
2040 qWarning(
"Inconsistent multiViewCount in color attachment set");
2042 multiViewCount = it->multiViewCount();
2043 }
else if (multiViewCount > 0) {
2044 qWarning(
"Mixing non-multiview color attachments within a multiview render pass");
2047 Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
2048 rpD->multiViewCount = uint32_t(multiViewCount);
2052 const VkFormat dsFormat = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->viewFormat
2053 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
2054 const VkSampleCountFlagBits samples = depthTexture ?
QRHI_RES(QVkTexture, depthTexture)->samples
2055 :
QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
2056 const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
2057 const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
2058 VkAttachmentDescription attDesc = {};
2059 attDesc.format = dsFormat;
2060 attDesc.samples = samples;
2061 attDesc.loadOp = loadOp;
2062 attDesc.storeOp = storeOp;
2063 attDesc.stencilLoadOp = loadOp;
2064 attDesc.stencilStoreOp = storeOp;
2065 attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
2066 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2067 rpD->attDescs.append(attDesc);
2068 if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
2069 multiViewCount = depthTexture->arraySize();
2070 rpD->multiViewCount = multiViewCount;
2072 rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2077 for (
auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
2078 if (it->resolveTexture()) {
2080 const VkFormat dstFormat = rtexD->vkformat;
2081 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2082 qWarning(
"Resolving into a multisample texture is not supported");
2086 const VkFormat srcFormat = texD ? texD->vkformat : rbD->vkformat;
2087 if (srcFormat != dstFormat) {
2091 qWarning(
"Multisample resolve between different formats (%d and %d) is not supported.",
2092 int(srcFormat),
int(dstFormat));
2095 VkAttachmentDescription attDesc = {};
2096 attDesc.format = rtexD->viewFormat;
2097 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2098 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2099 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2100 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2101 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2102 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2103 attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2104 rpD->attDescs.append(attDesc);
2106 const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2107 rpD->resolveRefs.append(ref);
2109 const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
2110 rpD->resolveRefs.append(ref);
2113 Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
2118 if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
2119 qWarning(
"Resolving into a multisample depth texture is not supported");
2122 if (texD->vkformat != rtexD->vkformat) {
2123 qWarning(
"Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
2124 int(texD->vkformat),
int(rtexD->vkformat));
2127 VkAttachmentDescription attDesc = {};
2128 attDesc.format = rtexD->viewFormat;
2129 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2130 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2131 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2132 attDesc.stencilLoadOp = attDesc.loadOp;
2133 attDesc.stencilStoreOp = attDesc.storeOp;
2134 attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2135 attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2136 rpD->attDescs.append(attDesc);
2137 rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
2139 rpD->dsResolveRef = {};
2143 rpD->shadingRateRef = {};
2144#ifdef VK_KHR_fragment_shading_rate
2145 if (shadingRateMap) {
2146 VkAttachmentDescription attDesc = {};
2147 attDesc.format = VK_FORMAT_R8_UINT;
2148 attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
2149 attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
2150 attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2151 attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2152 attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
2153 attDesc.initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2154 attDesc.finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
2155 rpD->attDescs.append(attDesc);
2156 rpD->shadingRateRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR };
2165 VkRenderPassCreateInfo rpInfo;
2166 VkSubpassDescription subpassDesc;
2167 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
2170 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
2173#ifdef VK_KHR_create_renderpass2
2174 if (caps.renderPass2KHR) {
2176 VkRenderPassCreateInfo2KHR rpInfo2;
2177 RenderPass2SetupHelper rp2Helper(
this);
2178 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
2181 VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2,
nullptr, &rpD->rp);
2182 if (err != VK_SUCCESS) {
2183 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
2190 qWarning(
"Resolving multisample depth-stencil buffers is not supported without "
2191 "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
2194 qWarning(
"Variable rate shading with image is not supported without VK_KHR_create_renderpass2");
2195 VkResult err = df->vkCreateRenderPass(dev, &rpInfo,
nullptr, &rpD->rp);
2196 if (err != VK_SUCCESS) {
2197 qWarning(
"Failed to create renderpass: %d", err);
2208 if (swapChainD->pixelSize.isEmpty()) {
2209 qWarning(
"Surface size is 0, cannot create swapchain");
2213 df->vkDeviceWaitIdle(dev);
2215 if (!vkCreateSwapchainKHR) {
2216 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
2217 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
2218 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
2219 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
2220 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
2221 if (!vkCreateSwapchainKHR || !vkDestroySwapchainKHR || !vkGetSwapchainImagesKHR || !vkAcquireNextImageKHR || !vkQueuePresentKHR) {
2222 qWarning(
"Swapchain functions not available");
2227 VkSurfaceCapabilitiesKHR surfaceCaps;
2228 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, swapChainD->surface, &surfaceCaps);
2229 quint32 reqBufferCount;
2230 if (swapChainD->m_flags.testFlag(QRhiSwapChain::MinimalBufferCount) || surfaceCaps.maxImageCount == 0) {
2231 reqBufferCount = qMax<quint32>(2, surfaceCaps.minImageCount);
2233 reqBufferCount = qMax(qMin<quint32>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
2235 VkSurfaceTransformFlagBitsKHR preTransform =
2236 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
2237 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
2238 : surfaceCaps.currentTransform;
2264 VkCompositeAlphaFlagBitsKHR compositeAlpha =
2265 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
2266 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
2267 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2269 if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasPreMulAlpha)) {
2270 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2271 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2272 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2273 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2274 }
else if (swapChainD->m_flags.testFlag(QRhiSwapChain::SurfaceHasNonPreMulAlpha)) {
2275 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
2276 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
2277 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
2278 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
2281 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2282 swapChainD->supportsReadback = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2283 if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
2284 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2286 const bool stereo =
bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
2287 && surfaceCaps.maxImageArrayLayers > 1;
2290 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
2291 if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
2295 if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
2296 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
2297 else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
2298 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
2306 const bool reuseExisting = swapChainD->sc && swapChainD->lastConnectedSurface == swapChainD->surface;
2308 qCDebug(QRHI_LOG_INFO,
"Creating %s swapchain of %u buffers, size %dx%d, presentation mode %d",
2309 reuseExisting ?
"recycled" :
"new",
2310 reqBufferCount, swapChainD->pixelSize.width(), swapChainD->pixelSize.height(), presentMode);
2312 VkSwapchainCreateInfoKHR swapChainInfo = {};
2313 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2314 swapChainInfo.surface = swapChainD->surface;
2315 swapChainInfo.minImageCount = reqBufferCount;
2316 swapChainInfo.imageFormat = swapChainD->colorFormat;
2317 swapChainInfo.imageColorSpace = swapChainD->colorSpace;
2318 swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
2319 swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
2320 swapChainInfo.imageUsage = usage;
2321 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2322 swapChainInfo.preTransform = preTransform;
2323 swapChainInfo.compositeAlpha = compositeAlpha;
2324 swapChainInfo.presentMode = presentMode;
2325 swapChainInfo.clipped =
true;
2326 swapChainInfo.oldSwapchain = reuseExisting ? swapChainD->sc : VK_NULL_HANDLE;
2328 VkSwapchainKHR newSwapChain;
2329 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
2330 if (err != VK_SUCCESS) {
2331 qWarning(
"Failed to create swapchain: %d", err);
2338 swapChainD->sc = newSwapChain;
2339 swapChainD->lastConnectedSurface = swapChainD->surface;
2341 quint32 actualSwapChainBufferCount = 0;
2342 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount,
nullptr);
2343 if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
2344 qWarning(
"Failed to get swapchain images: %d", err);
2348 if (actualSwapChainBufferCount != reqBufferCount)
2349 qCDebug(QRHI_LOG_INFO,
"Actual swapchain buffer count is %u", actualSwapChainBufferCount);
2352 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> swapChainImages(actualSwapChainBufferCount);
2353 err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages.data());
2354 if (err != VK_SUCCESS) {
2355 qWarning(
"Failed to get swapchain images: %d", err);
2359 QVarLengthArray<VkImage, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaImages(swapChainD->bufferCount);
2360 QVarLengthArray<VkImageView, QVkSwapChain::EXPECTED_MAX_BUFFER_COUNT> msaaViews(swapChainD->bufferCount);
2361 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2362 if (!createTransientImage(swapChainD->colorFormat,
2363 swapChainD->pixelSize,
2364 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
2365 VK_IMAGE_ASPECT_COLOR_BIT,
2366 swapChainD->samples,
2367 &swapChainD->msaaImageMem,
2370 swapChainD->bufferCount))
2372 qWarning(
"Failed to create transient image for MSAA color buffer");
2377 VkFenceCreateInfo fenceInfo = {};
2378 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2379 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2382 swapChainD->imageRes.resize(swapChainD
->bufferCount * (stereo ? 2u : 1u));
2386 image.image = swapChainImages[i];
2387 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2388 image.msaaImage = msaaImages[i];
2389 image.msaaImageView = msaaViews[i];
2392 VkImageViewCreateInfo imgViewInfo = {};
2393 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2394 imgViewInfo.image = swapChainImages[i];
2395 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2396 imgViewInfo.format = swapChainD->colorFormat;
2397 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2398 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2399 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2400 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2401 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2402 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2403 err = df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2404 if (err != VK_SUCCESS) {
2405 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2411 VkSemaphoreCreateInfo semInfo = {};
2412 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2413 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2418 image.image = swapChainImages[i];
2419 if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
2420 image.msaaImage = msaaImages[i];
2421 image.msaaImageView = msaaViews[i];
2424 VkImageViewCreateInfo imgViewInfo = {};
2425 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2426 imgViewInfo.image = swapChainImages[i];
2427 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2428 imgViewInfo.format = swapChainD->colorFormat;
2429 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2430 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2431 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2432 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2433 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2434 imgViewInfo.subresourceRange.baseArrayLayer = 1;
2435 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
2436 err = df->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
2437 if (err != VK_SUCCESS) {
2438 qWarning(
"Failed to create swapchain image view %d: %d", i, err);
2442 VkSemaphoreCreateInfo semInfo = {};
2443 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2444 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &image.drawSem);
2450 swapChainD->currentImageIndex = 0;
2452 if (swapChainD->shadingRateMap() && caps.renderPass2KHR && caps.imageBasedShadingRate) {
2454 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
2455 VkImageViewCreateInfo viewInfo = {};
2456 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2457 viewInfo.image = texD->image;
2458 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
2459 viewInfo.format = texD->viewFormat;
2460 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
2461 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
2462 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
2463 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
2464 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2465 viewInfo.subresourceRange.baseMipLevel = 0;
2466 viewInfo.subresourceRange.levelCount = 1;
2467 viewInfo.subresourceRange.baseArrayLayer = 0;
2468 viewInfo.subresourceRange.layerCount = 1;
2469 VkResult err = df->vkCreateImageView(dev, &viewInfo,
nullptr, &swapChainD->shadingRateMapView);
2470 if (err != VK_SUCCESS) {
2471 qWarning(
"Failed to create swapchain shading rate map view: %d", err);
2476 VkSemaphoreCreateInfo semInfo = {};
2477 semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2485 df->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
2487 err = df->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
2488 if (err != VK_SUCCESS) {
2489 qWarning(
"Failed to create command buffer fence: %d", err);
2495 swapChainD->currentFrameSlot = 0;
2504 if (swapChainD->sc == VK_NULL_HANDLE)
2508 df->vkDeviceWaitIdle(dev);
2512 if (frame.cmdFence) {
2513 if (!deviceLost && frame.cmdFenceWaitable)
2514 df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2515 df->vkDestroyFence(dev, frame.cmdFence,
nullptr);
2516 frame.cmdFence = VK_NULL_HANDLE;
2519 if (frame.imageSem) {
2520 df->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
2521 frame.imageSem = VK_NULL_HANDLE;
2528 df->vkDestroyFramebuffer(dev, image.fb,
nullptr);
2529 image.fb = VK_NULL_HANDLE;
2531 if (image.imageView) {
2532 df->vkDestroyImageView(dev, image.imageView,
nullptr);
2533 image.imageView = VK_NULL_HANDLE;
2535 if (image.msaaImageView) {
2536 df->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
2537 image.msaaImageView = VK_NULL_HANDLE;
2539 if (image.msaaImage) {
2540 df->vkDestroyImage(dev, image.msaaImage,
nullptr);
2541 image.msaaImage = VK_NULL_HANDLE;
2543 if (image.drawSem) {
2544 df->vkDestroySemaphore(dev, image.drawSem,
nullptr);
2545 image.drawSem = VK_NULL_HANDLE;
2549 if (swapChainD->msaaImageMem) {
2550 df->vkFreeMemory(dev, swapChainD->msaaImageMem,
nullptr);
2551 swapChainD->msaaImageMem = VK_NULL_HANDLE;
2554 if (swapChainD->shadingRateMapView) {
2555 df->vkDestroyImageView(dev, swapChainD->shadingRateMapView,
nullptr);
2556 swapChainD->shadingRateMapView = VK_NULL_HANDLE;
2559 vkDestroySwapchainKHR(dev, swapChainD->sc,
nullptr);
2560 swapChainD->sc = VK_NULL_HANDLE;
2567 VkCommandPoolResetFlags flags = 0;
2572 if (releaseCachedResourcesCalledBeforeFrameStart)
2573 flags |= VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT;
2576 df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
2582 for (quint64 i = 0; i < timestampValidBits; i += 8)
2583 mask |= 0xFFULL << i;
2584 const quint64 ts0 = timestamp[0] & mask;
2585 const quint64 ts1 = timestamp[1] & mask;
2586 const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
2587 if (!qFuzzyIsNull(nsecsPerTick)) {
2588 const float elapsedMs =
float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
2589 const double elapsedSec = elapsedMs / 1000.0;
2600 const int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2603 inst->handle()->beginFrame(swapChainD->window);
2613 QRhi::FrameOpResult waitResult = waitCommandCompletion(frameResIndex);
2614 if (waitResult != QRhi::FrameOpSuccess)
2619 uint32_t imageIndex = 0;
2620 VkResult err = vkAcquireNextImageKHR(dev, swapChainD->sc, UINT64_MAX,
2621 frame.imageSem, VK_NULL_HANDLE, &imageIndex);
2623 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
2624 swapChainD->currentImageIndex = imageIndex;
2627 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2628 return QRhi::FrameOpSwapChainOutOfDate;
2630 if (err == VK_ERROR_DEVICE_LOST) {
2631 qWarning(
"Device loss detected in vkAcquireNextImageKHR()");
2633 return QRhi::FrameOpDeviceLost;
2635 qWarning(
"Failed to acquire next swapchain image: %d", err);
2636 return QRhi::FrameOpError;
2640 currentFrameSlot =
int(swapChainD->currentFrameSlot);
2643 swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
2649 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&frame.cmdBuf);
2650 if (cbres != QRhi::FrameOpSuccess)
2653 swapChainD->cbWrapper.cb = frame.cmdBuf;
2656 swapChainD->rtWrapper.d.fb = image.fb;
2660 swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD
->bufferCount]);
2661 swapChainD->rtWrapperRight.d.fb = image.fb;
2668 quint64 timestamp[2] = { 0, 0 };
2669 VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame.timestampQueryIndex), 2,
2670 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
2671 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
2672 timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
2674 if (err == VK_SUCCESS) {
2676 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
2678 swapChainD->cbWrapper.lastGpuTime = elapsedSec;
2680 qWarning(
"Failed to query timestamp: %d", err);
2685 if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
2686 int timestampQueryIdx = -1;
2687 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2688 if (!timestampQueryPoolMap.testBit(i)) {
2689 timestampQueryPoolMap.setBit(i);
2690 timestampQueryIdx = i * 2;
2694 if (timestampQueryIdx >= 0) {
2695 df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2697 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2698 timestampQueryPool, uint32_t(timestampQueryIdx));
2703 return QRhi::FrameOpSuccess;
2711 auto cleanup = qScopeGuard([
this, swapChainD] {
2712 inst->handle()->endFrame(swapChainD->window);
2717 int frameResIndex = swapChainD
->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
2722 VkImageMemoryBarrier presTrans = {};
2723 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2724 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2725 presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2726 presTrans.image = image.image;
2727 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2728 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2732 presTrans.srcAccessMask = 0;
2733 presTrans.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2734 df->vkCmdPipelineBarrier(frame.cmdBuf,
2735 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2736 0, 0,
nullptr, 0,
nullptr,
2740 presTrans.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2741 presTrans.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2742 df->vkCmdPipelineBarrier(frame.cmdBuf,
2743 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2744 0, 0,
nullptr, 0,
nullptr,
2752 df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2753 timestampQueryPool, uint32_t(frame.timestampQueryIndex + 1));
2758 const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
2759 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(frame.cmdBuf,
2761 frame.imageSemWaitable ? &frame.imageSem :
nullptr,
2762 needsPresent ? &image.drawSem :
nullptr);
2763 if (submitres != QRhi::FrameOpSuccess)
2771 VkPresentInfoKHR presInfo = {};
2772 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2773 presInfo.swapchainCount = 1;
2774 presInfo.pSwapchains = &swapChainD->sc;
2775 presInfo.pImageIndices = &swapChainD->currentImageIndex;
2776 waitSemaphoresForPresent.append(image.drawSem);
2777 presInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForPresent.count());;
2778 presInfo.pWaitSemaphores = waitSemaphoresForPresent.constData();
2782 inst->presentAboutToBeQueued(swapChainD->window);
2784 VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
2785 waitSemaphoresForPresent.clear();
2786 if (err != VK_SUCCESS) {
2787 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2788 return QRhi::FrameOpSwapChainOutOfDate;
2789 }
else if (err != VK_SUBOPTIMAL_KHR) {
2790 if (err == VK_ERROR_DEVICE_LOST) {
2791 qWarning(
"Device loss detected in vkQueuePresentKHR()");
2793 return QRhi::FrameOpDeviceLost;
2795 qWarning(
"Failed to present: %d", err);
2796 return QRhi::FrameOpError;
2802 inst->presentQueued(swapChainD->window);
2812 return QRhi::FrameOpSuccess;
2831 QRHI_RES(QVkCommandBuffer, cb)->resetState();
2841 VkCommandBufferAllocateInfo cmdBufInfo = {};
2842 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2843 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
2844 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2845 cmdBufInfo.commandBufferCount = 1;
2847 VkResult err = df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
2848 if (err != VK_SUCCESS) {
2849 if (err == VK_ERROR_DEVICE_LOST) {
2850 qWarning(
"Device loss detected in vkAllocateCommandBuffers()");
2852 return QRhi::FrameOpDeviceLost;
2854 qWarning(
"Failed to allocate frame command buffer: %d", err);
2855 return QRhi::FrameOpError;
2859 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
2860 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2862 VkResult err =
df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
2863 if (err != VK_SUCCESS) {
2864 if (err == VK_ERROR_DEVICE_LOST) {
2865 qWarning(
"Device loss detected in vkBeginCommandBuffer()");
2867 return QRhi::FrameOpDeviceLost;
2869 qWarning(
"Failed to begin frame command buffer: %d", err);
2870 return QRhi::FrameOpError;
2873 return QRhi::FrameOpSuccess;
2877 VkSemaphore *waitSem, VkSemaphore *signalSem)
2879 VkResult err =
df->vkEndCommandBuffer(cb);
2880 if (err != VK_SUCCESS) {
2881 if (err == VK_ERROR_DEVICE_LOST) {
2882 qWarning(
"Device loss detected in vkEndCommandBuffer()");
2884 return QRhi::FrameOpDeviceLost;
2886 qWarning(
"Failed to end frame command buffer: %d", err);
2887 return QRhi::FrameOpError;
2890 VkSubmitInfo submitInfo = {};
2891 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2892 submitInfo.commandBufferCount = 1;
2893 submitInfo.pCommandBuffers = &cb;
2896 waitSemaphoresForQueueSubmit.append(*waitSem);
2898 signalSemaphoresForQueueSubmit.append(*signalSem);
2900 submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoresForQueueSubmit.count());
2901 if (!waitSemaphoresForQueueSubmit.isEmpty()) {
2902 submitInfo.pWaitSemaphores = waitSemaphoresForQueueSubmit.constData();
2903 semaphoresWaitMasksForQueueSubmit.resize(waitSemaphoresForQueueSubmit.count(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2904 submitInfo.pWaitDstStageMask = semaphoresWaitMasksForQueueSubmit.constData();
2906 submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoresForQueueSubmit.count());
2907 if (!signalSemaphoresForQueueSubmit.isEmpty()) {
2908 submitInfo.pSignalSemaphores = signalSemaphoresForQueueSubmit.constData();
2911 err = df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
2913 waitSemaphoresForQueueSubmit.clear();
2914 signalSemaphoresForQueueSubmit.clear();
2916 if (err != VK_SUCCESS) {
2917 if (err == VK_ERROR_DEVICE_LOST) {
2918 qWarning(
"Device loss detected in vkQueueSubmit()");
2920 return QRhi::FrameOpDeviceLost;
2922 qWarning(
"Failed to submit to graphics queue: %d", err);
2923 return QRhi::FrameOpError;
2926 return QRhi::FrameOpSuccess;
2931 for (QVkSwapChain *sc : std::as_const(swapchains)) {
2932 const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
2933 QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
2934 if (frame.cmdFenceWaitable) {
2935 VkResult err = df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2937 if (err != VK_SUCCESS) {
2938 if (err == VK_ERROR_DEVICE_LOST) {
2939 qWarning(
"Device loss detected in vkWaitForFences()");
2941 return QRhi::FrameOpDeviceLost;
2943 qWarning(
"Failed to wait for fence: %d", err);
2944 return QRhi::FrameOpError;
2947 df->vkResetFences(dev, 1, &frame.cmdFence);
2948 frame.cmdFenceWaitable =
false;
2952 return QRhi::FrameOpSuccess;
2966 currentFrameSlot = (currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
2968 QRhi::FrameOpResult waitResult = waitCommandCompletion(currentFrameSlot);
2969 if (waitResult != QRhi::FrameOpSuccess)
2975 QRhi::FrameOpResult cbres = startPrimaryCommandBuffer(&cbWrapper->cb);
2976 if (cbres != QRhi::FrameOpSuccess)
2982 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
2983 int timestampQueryIdx = -1;
2984 for (
int i = 0; i < timestampQueryPoolMap.size(); ++i) {
2985 if (!timestampQueryPoolMap.testBit(i)) {
2986 timestampQueryPoolMap.setBit(i);
2987 timestampQueryIdx = i * 2;
2991 if (timestampQueryIdx >= 0) {
2992 df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
2994 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2995 timestampQueryPool, uint32_t(timestampQueryIdx));
2996 ofr.timestampQueryIndex = timestampQueryIdx;
3001 return QRhi::FrameOpSuccess;
3007 Q_ASSERT(ofr.active);
3014 if (ofr.timestampQueryIndex >= 0) {
3015 df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
3016 timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
3019 if (!ofr.cmdFence) {
3020 VkFenceCreateInfo fenceInfo = {};
3021 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
3022 VkResult err = df->vkCreateFence(dev, &fenceInfo,
nullptr, &ofr.cmdFence);
3023 if (err != VK_SUCCESS) {
3024 qWarning(
"Failed to create command buffer fence: %d", err);
3025 return QRhi::FrameOpError;
3029 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cbWrapper->cb, ofr.cmdFence,
nullptr,
nullptr);
3030 if (submitres != QRhi::FrameOpSuccess)
3034 df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
3035 df->vkResetFences(dev, 1, &ofr.cmdFence);
3042 if (ofr.timestampQueryIndex >= 0) {
3043 quint64 timestamp[2] = { 0, 0 };
3044 VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
3045 2 *
sizeof(quint64), timestamp,
sizeof(quint64),
3046 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
3047 timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
3048 ofr.timestampQueryIndex = -1;
3049 if (err == VK_SUCCESS) {
3051 const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
3055 qWarning(
"Failed to query timestamp: %d", err);
3059 return QRhi::FrameOpSuccess;
3081 swapChainD->cbWrapper.resetCommands();
3082 cb = swapChainD->cbWrapper.cb;
3084 QRhi::FrameOpResult submitres = endAndSubmitPrimaryCommandBuffer(cb, VK_NULL_HANDLE,
nullptr,
nullptr);
3085 if (submitres != QRhi::FrameOpSuccess)
3089 df->vkQueueWaitIdle(gfxQueue);
3096 startPrimaryCommandBuffer(&ofr.cbWrapper[currentFrameSlot]->cb);
3099 startPrimaryCommandBuffer(&frame.cmdBuf);
3100 swapChainD->cbWrapper.cb = frame.cmdBuf;
3107 return QRhi::FrameOpSuccess;
3114 u
.access =
int(bufUsage.access);
3115 u
.stage =
int(bufUsage.stage);
3123 u
.access =
int(texUsage.access);
3124 u
.stage =
int(texUsage.stage);
3130 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList))
3133 rtD->lastActiveFrameSlot = currentFrameSlot;
3134 rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
3136 for (
auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
3144 texD->lastActiveFrameSlot = currentFrameSlot;
3149 rbD->lastActiveFrameSlot = currentFrameSlot;
3155 resolveTexD->lastActiveFrameSlot = currentFrameSlot;
3158 if (rtD->m_desc.depthStencilBuffer()) {
3160 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
3167 rbD->lastActiveFrameSlot = currentFrameSlot;
3169 if (rtD->m_desc.depthTexture()) {
3174 depthTexD->lastActiveFrameSlot = currentFrameSlot;
3176 if (rtD->m_desc.depthResolveTexture()) {
3181 depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
3183 if (rtD->m_desc.shadingRateMap()) {
3188 texD->lastActiveFrameSlot = currentFrameSlot;
3202 VkCommandBuffer secondaryCb;
3204 if (!freeSecondaryCbs[currentFrameSlot].isEmpty()) {
3205 secondaryCb = freeSecondaryCbs[currentFrameSlot].last();
3206 freeSecondaryCbs[currentFrameSlot].removeLast();
3208 VkCommandBufferAllocateInfo cmdBufInfo = {};
3209 cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
3210 cmdBufInfo.commandPool = cmdPool[currentFrameSlot];
3211 cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
3212 cmdBufInfo.commandBufferCount = 1;
3214 VkResult err = df->vkAllocateCommandBuffers(dev, &cmdBufInfo, &secondaryCb);
3215 if (err != VK_SUCCESS) {
3216 qWarning(
"Failed to create secondary command buffer: %d", err);
3217 return VK_NULL_HANDLE;
3221 VkCommandBufferBeginInfo cmdBufBeginInfo = {};
3222 cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
3223 cmdBufBeginInfo.flags = rtD ? VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT : 0;
3224 VkCommandBufferInheritanceInfo cmdBufInheritInfo = {};
3225 cmdBufInheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
3226 cmdBufInheritInfo.subpass = 0;
3228 cmdBufInheritInfo.renderPass = rtD
->rp->rp;
3229 cmdBufInheritInfo.framebuffer = rtD->fb;
3231 cmdBufBeginInfo.pInheritanceInfo = &cmdBufInheritInfo;
3233 VkResult err =
df->vkBeginCommandBuffer(secondaryCb, &cmdBufBeginInfo);
3234 if (err != VK_SUCCESS) {
3235 qWarning(
"Failed to begin secondary command buffer: %d", err);
3236 return VK_NULL_HANDLE;
3244 VkResult err =
df->vkEndCommandBuffer(cb);
3245 if (err != VK_SUCCESS)
3246 qWarning(
"Failed to end secondary command buffer: %d", err);
3250 cmd.args.executeSecondary.cb = cb;
3254 e.lastActiveFrameSlot = currentFrameSlot;
3255 e.secondaryCommandBuffer.cb = cb;
3256 releaseQueue.append(e);
3260 QRhiRenderTarget *rt,
3261 const QColor &colorClearValue,
3262 const QRhiDepthStencilClearValue &depthStencilClearValue,
3263 QRhiResourceUpdateBatch *resourceUpdates,
3264 QRhiCommandBuffer::BeginPassFlags flags)
3269 if (resourceUpdates)
3279 switch (rt->resourceType()) {
3280 case QRhiResource::SwapChainRenderTarget:
3282 rtD->rp->lastActiveFrameSlot = currentFrameSlot;
3292 texD->lastActiveFrameSlot = currentFrameSlot;
3295 case QRhiResource::TextureRenderTarget:
3308 cbD->passUsesSecondaryCb = flags.testFlag(QRhiCommandBuffer::ExternalContent);
3309 cbD->currentTarget = rt;
3314 VkRenderPassBeginInfo rpBeginInfo = {};
3315 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
3316 rpBeginInfo.renderPass = rtD
->rp->rp;
3317 rpBeginInfo.framebuffer = rtD->fb;
3318 rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
3319 rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
3321 QVarLengthArray<VkClearValue, (QVkRenderTargetData::MAX_COLOR_ATTACHMENTS + 1) * 2 + 1> cvs;
3324 cv.color = { {
float(colorClearValue.redF()),
float(colorClearValue.greenF()),
float(colorClearValue.blueF()),
3325 float(colorClearValue.alphaF()) } };
3330 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3335 cv.color = { {
float(colorClearValue.redF()),
float(colorClearValue.greenF()),
float(colorClearValue.blueF()),
3336 float(colorClearValue.alphaF()) } };
3341 cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
3346 cv.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
3349 rpBeginInfo.clearValueCount = uint32_t(cvs.size());
3353 cmd.args.beginRenderPass.desc = rpBeginInfo;
3354 cmd.args.beginRenderPass.clearValueIndex = cbD->pools.clearValue.size();
3356 cbD->pools.clearValue.append(cvs.constData(), cvs.size());
3358 if (cbD->passUsesSecondaryCb)
3359 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(rtD));
3364 rateCmd.args.setShadingRate.w = 1;
3365 rateCmd.args.setShadingRate.h = 1;
3377 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3378 cbD->activeSecondaryCbStack.removeLast();
3379 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3386 cbD->currentTarget =
nullptr;
3388 if (resourceUpdates)
3393 QRhiResourceUpdateBatch *resourceUpdates,
3394 QRhiCommandBuffer::BeginPassFlags flags)
3399 if (resourceUpdates)
3405 cbD->passUsesSecondaryCb = flags.testFlag(QRhiCommandBuffer::ExternalContent);
3407 cbD->computePassState.reset();
3409 if (cbD->passUsesSecondaryCb)
3410 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer());
3421 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3422 cbD->activeSecondaryCbStack.removeLast();
3423 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
3428 if (resourceUpdates)
3435 Q_ASSERT(psD->pipeline);
3439 if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
3441 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_COMPUTE, psD->pipeline);
3445 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
3446 cmd.args.bindPipeline.pipeline = psD->pipeline;
3449 cbD->currentGraphicsPipeline =
nullptr;
3450 cbD->currentComputePipeline = ps;
3451 cbD->currentPipelineGeneration = psD->generation;
3454 psD->lastActiveFrameSlot = currentFrameSlot;
3459 QRhiShaderResourceBinding::Type bindingType,
3460 int loadTypeVal,
int storeTypeVal,
int loadStoreTypeVal)
3462 VkAccessFlags access = 0;
3463 if (bindingType == loadTypeVal) {
3464 access = VK_ACCESS_SHADER_READ_BIT;
3466 access = VK_ACCESS_SHADER_WRITE_BIT;
3467 if (bindingType == loadStoreTypeVal)
3468 access |= VK_ACCESS_SHADER_READ_BIT;
3470 auto it = writtenResources->find(resource);
3471 if (it != writtenResources->end())
3472 it->first |= access;
3473 else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
3474 writtenResources->insert(resource, { access,
true });
3484 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
3485 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
3486 if (cbD->currentComputeSrb) {
3490 for (
auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
3491 accessAndIsNewFlag = { 0,
false };
3494 const int bindingCount = srbD->m_bindings.size();
3495 for (
int i = 0; i < bindingCount; ++i) {
3496 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings.at(i));
3498 case QRhiShaderResourceBinding::ImageLoad:
3499 case QRhiShaderResourceBinding::ImageStore:
3500 case QRhiShaderResourceBinding::ImageLoadStore:
3501 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3504 QRhiShaderResourceBinding::ImageLoad,
3505 QRhiShaderResourceBinding::ImageStore,
3506 QRhiShaderResourceBinding::ImageLoadStore);
3508 case QRhiShaderResourceBinding::BufferLoad:
3509 case QRhiShaderResourceBinding::BufferStore:
3510 case QRhiShaderResourceBinding::BufferLoadStore:
3511 qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
3514 QRhiShaderResourceBinding::BufferLoad,
3515 QRhiShaderResourceBinding::BufferStore,
3516 QRhiShaderResourceBinding::BufferLoadStore);
3523 for (
auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
3524 const int accessInThisDispatch = it->first;
3525 const bool isNewInThisDispatch = it->second;
3526 if (accessInThisDispatch && !isNewInThisDispatch) {
3527 if (it.key()->resourceType() == QRhiResource::Texture) {
3529 VkImageMemoryBarrier barrier = {};
3530 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3531 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3533 barrier.subresourceRange.baseMipLevel = 0;
3534 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3535 barrier.subresourceRange.baseArrayLayer = 0;
3536 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3537 barrier.oldLayout = texD->usageState.layout;
3538 barrier.newLayout = texD->usageState.layout;
3539 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3540 barrier.dstAccessMask = accessInThisDispatch;
3541 barrier.image = texD->image;
3542 imageBarriers.append(barrier);
3545 VkBufferMemoryBarrier barrier = {};
3546 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3547 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3548 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3549 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3550 barrier.dstAccessMask = accessInThisDispatch;
3551 barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
3552 barrier.size = VK_WHOLE_SIZE;
3553 bufferBarriers.append(barrier);
3559 if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
3560 it = cbD->computePassState.writtenResources.erase(it);
3567 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
3568 if (!imageBarriers.isEmpty()) {
3569 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3572 imageBarriers.size(), imageBarriers.constData());
3574 if (!bufferBarriers.isEmpty()) {
3575 df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3577 bufferBarriers.size(), bufferBarriers.constData(),
3580 df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
3582 if (!imageBarriers.isEmpty()) {
3585 cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3586 cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3587 cmd.args.imageBarrier.count = imageBarriers.size();
3588 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3589 cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.size());
3591 if (!bufferBarriers.isEmpty()) {
3594 cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3595 cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
3596 cmd.args.bufferBarrier.count = bufferBarriers.size();
3597 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3598 cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.size());
3602 cmd.args.dispatch.x = x;
3603 cmd.args.dispatch.y = y;
3604 cmd.args.dispatch.z = z;
3610 VkShaderModuleCreateInfo shaderInfo = {};
3611 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3612 shaderInfo.codeSize = size_t(spirv.size());
3613 shaderInfo.pCode =
reinterpret_cast<
const quint32 *>(spirv.constData());
3614 VkShaderModule shaderModule;
3615 VkResult err = df->vkCreateShaderModule(dev, &shaderInfo,
nullptr, &shaderModule);
3616 if (err != VK_SUCCESS) {
3617 qWarning(
"Failed to create shader module: %d", err);
3618 return VK_NULL_HANDLE;
3620 return shaderModule;
3628 VkPipelineCacheCreateInfo pipelineCacheInfo = {};
3629 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3630 pipelineCacheInfo.initialDataSize = initialDataSize;
3631 pipelineCacheInfo.pInitialData = initialData;
3632 VkResult err = df->vkCreatePipelineCache(dev, &pipelineCacheInfo,
nullptr, &pipelineCache);
3633 if (err != VK_SUCCESS) {
3634 qWarning(
"Failed to create pipeline cache: %d", err);
3644 QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
3645 using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
3646 QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
3647 QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
3648 QVarLengthArray<std::pair<
int,
int>, 12> infoIndices;
3650 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
3651 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
3654 VkWriteDescriptorSet writeInfo = {};
3655 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3656 writeInfo.dstSet = srbD->descSets[currentFrameSlot];
3657 writeInfo.dstBinding = uint32_t(b->binding);
3658 writeInfo.descriptorCount = 1;
3660 int bufferInfoIndex = -1;
3661 int imageInfoIndex = -1;
3664 case QRhiShaderResourceBinding::UniformBuffer:
3666 writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
3667 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3668 QRhiBuffer *buf = b->u.ubuf.buf;
3670 bd.ubuf.id = bufD->m_id;
3671 bd.ubuf.generation = bufD->generation;
3672 VkDescriptorBufferInfo bufInfo;
3673 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3674 bufInfo.offset = b->u.ubuf.offset;
3675 bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : VK_WHOLE_SIZE;
3677 Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
3678 bufferInfoIndex = bufferInfos.size();
3679 bufferInfos.append(bufInfo);
3682 case QRhiShaderResourceBinding::SampledTexture:
3684 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3685 writeInfo.descriptorCount = data->count;
3686 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3687 ArrayOfImageDesc imageInfo(data->count);
3688 for (
int elem = 0; elem < data->count; ++elem) {
3691 bd.stex.d[elem].texId = texD->m_id;
3692 bd.stex.d[elem].texGeneration = texD->generation;
3693 bd.stex.d[elem].samplerId = samplerD->m_id;
3694 bd.stex.d[elem].samplerGeneration = samplerD->generation;
3695 imageInfo[elem].sampler = samplerD->sampler;
3696 imageInfo[elem].imageView = texD->imageView;
3697 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3699 bd.stex.count = data->count;
3700 imageInfoIndex = imageInfos.size();
3701 imageInfos.append(imageInfo);
3704 case QRhiShaderResourceBinding::Texture:
3706 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
3707 writeInfo.descriptorCount = data->count;
3708 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3709 ArrayOfImageDesc imageInfo(data->count);
3710 for (
int elem = 0; elem < data->count; ++elem) {
3712 bd.stex.d[elem].texId = texD->m_id;
3713 bd.stex.d[elem].texGeneration = texD->generation;
3714 bd.stex.d[elem].samplerId = 0;
3715 bd.stex.d[elem].samplerGeneration = 0;
3716 imageInfo[elem].sampler = VK_NULL_HANDLE;
3717 imageInfo[elem].imageView = texD->imageView;
3718 imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3720 bd.stex.count = data->count;
3721 imageInfoIndex = imageInfos.size();
3722 imageInfos.append(imageInfo);
3725 case QRhiShaderResourceBinding::Sampler:
3728 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
3729 bd.stex.d[0].texId = 0;
3730 bd.stex.d[0].texGeneration = 0;
3731 bd.stex.d[0].samplerId = samplerD->m_id;
3732 bd.stex.d[0].samplerGeneration = samplerD->generation;
3733 ArrayOfImageDesc imageInfo(1);
3734 imageInfo[0].sampler = samplerD->sampler;
3735 imageInfo[0].imageView = VK_NULL_HANDLE;
3736 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3737 imageInfoIndex = imageInfos.size();
3738 imageInfos.append(imageInfo);
3741 case QRhiShaderResourceBinding::ImageLoad:
3742 case QRhiShaderResourceBinding::ImageStore:
3743 case QRhiShaderResourceBinding::ImageLoadStore:
3746 VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
3748 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3749 bd.simage.id = texD->m_id;
3750 bd.simage.generation = texD->generation;
3751 ArrayOfImageDesc imageInfo(1);
3752 imageInfo[0].sampler = VK_NULL_HANDLE;
3753 imageInfo[0].imageView = view;
3754 imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
3755 imageInfoIndex = imageInfos.size();
3756 imageInfos.append(imageInfo);
3760 case QRhiShaderResourceBinding::BufferLoad:
3761 case QRhiShaderResourceBinding::BufferStore:
3762 case QRhiShaderResourceBinding::BufferLoadStore:
3765 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3766 bd.sbuf.id = bufD->m_id;
3767 bd.sbuf.generation = bufD->generation;
3768 VkDescriptorBufferInfo bufInfo;
3769 bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[currentFrameSlot] : bufD->buffers[0];
3770 bufInfo.offset = b->u.sbuf.offset;
3771 bufInfo.range = b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : VK_WHOLE_SIZE;
3772 bufferInfoIndex = bufferInfos.size();
3773 bufferInfos.append(bufInfo);
3780 writeInfos.append(writeInfo);
3781 infoIndices.append({ bufferInfoIndex, imageInfoIndex });
3784 for (
int i = 0, writeInfoCount = writeInfos.size(); i < writeInfoCount; ++i) {
3785 const int bufferInfoIndex = infoIndices[i].first;
3786 const int imageInfoIndex = infoIndices[i].second;
3787 if (bufferInfoIndex >= 0)
3788 writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
3789 else if (imageInfoIndex >= 0)
3790 writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
3793 df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.size()), writeInfos.constData(), 0,
nullptr);
3798 return (access & VK_ACCESS_SHADER_WRITE_BIT) != 0
3799 || (access & VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) != 0
3800 || (access & VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) != 0
3801 || (access & VK_ACCESS_TRANSFER_WRITE_BIT) != 0
3802 || (access & VK_ACCESS_HOST_WRITE_BIT) != 0
3803 || (access & VK_ACCESS_MEMORY_WRITE_BIT) != 0;
3807 VkAccessFlags access, VkPipelineStageFlags stage)
3810 Q_ASSERT(access && stage);
3818 if (s.access == access && s.stage == stage) {
3821 if (!accessIsWrite(access))
3825 VkBufferMemoryBarrier bufMemBarrier = {};
3826 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
3827 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3828 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
3829 bufMemBarrier.srcAccessMask = s.access;
3830 bufMemBarrier.dstAccessMask = access;
3831 bufMemBarrier.buffer = bufD->buffers[slot];
3832 bufMemBarrier.size = VK_WHOLE_SIZE;
3836 cmd.args.bufferBarrier.srcStageMask = s.stage;
3837 cmd.args.bufferBarrier.dstStageMask = stage;
3838 cmd.args.bufferBarrier.count = 1;
3839 cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.size();
3840 cbD->pools.bufferBarrier.append(bufMemBarrier);
3847 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage)
3850 Q_ASSERT(layout && access && stage);
3852 if (s.access == access && s.stage == stage && s.layout == layout) {
3853 if (!accessIsWrite(access))
3857 VkImageMemoryBarrier barrier = {};
3858 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3859 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
3860 barrier.subresourceRange.baseMipLevel = 0;
3861 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3862 barrier.subresourceRange.baseArrayLayer = 0;
3863 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3864 barrier.oldLayout = s.layout;
3865 barrier.newLayout = layout;
3866 barrier.srcAccessMask = s.access;
3867 barrier.dstAccessMask = access;
3868 barrier.image = texD->image;
3870 VkPipelineStageFlags srcStage = s.stage;
3873 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
3877 cmd.args.imageBarrier.srcStageMask = srcStage;
3878 cmd.args.imageBarrier.dstStageMask = stage;
3879 cmd.args.imageBarrier.count = 1;
3880 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3881 cbD->pools.imageBarrier.append(barrier);
3892 VkImageMemoryBarrier barrier = {};
3893 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3894 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
3895 barrier.subresourceRange.baseMipLevel = 0;
3896 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
3897 barrier.subresourceRange.baseArrayLayer = 0;
3898 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
3899 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3900 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
3901 barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3902 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
3903 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
3904 barrier.image = rbD->image;
3906 const VkPipelineStageFlags stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
3907 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
3911 cmd.args.imageBarrier.srcStageMask = stages;
3912 cmd.args.imageBarrier.dstStageMask = stages;
3913 cmd.args.imageBarrier.count = 1;
3914 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3915 cbD->pools.imageBarrier.append(barrier);
3919 VkImageLayout oldLayout, VkImageLayout newLayout,
3920 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
3921 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
3922 int startLayer,
int layerCount,
3923 int startLevel,
int levelCount)
3926 VkImageMemoryBarrier barrier = {};
3927 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
3928 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3929 barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
3930 barrier.subresourceRange.levelCount = uint32_t(levelCount);
3931 barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
3932 barrier.subresourceRange.layerCount = uint32_t(layerCount);
3933 barrier.oldLayout = oldLayout;
3934 barrier.newLayout = newLayout;
3935 barrier.srcAccessMask = srcAccess;
3936 barrier.dstAccessMask = dstAccess;
3937 barrier.image = image;
3941 cmd.args.imageBarrier.srcStageMask = srcStage;
3942 cmd.args.imageBarrier.dstStageMask = dstStage;
3943 cmd.args.imageBarrier.count = 1;
3944 cmd.args.imageBarrier.index = cbD->pools.imageBarrier.size();
3945 cbD->pools.imageBarrier.append(barrier);
3950 VkDeviceSize size = 0;
3951 const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
3952 subresDesc.data().size() : subresDesc.image().sizeInBytes();
3953 if (imageSizeBytes > 0)
3954 size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
3959 const QRhiTextureSubresourceUploadDescription &subresDesc,
3960 size_t *curOfs,
void *mp,
3961 BufferImageCopyList *copyInfos)
3963 qsizetype copySizeBytes = 0;
3964 qsizetype imageSizeBytes = 0;
3965 const void *src =
nullptr;
3966 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3967 const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
3969 VkBufferImageCopy copyInfo = {};
3970 copyInfo.bufferOffset = *curOfs;
3971 copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3972 copyInfo.imageSubresource.mipLevel = uint32_t(level);
3973 copyInfo.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(layer);
3974 copyInfo.imageSubresource.layerCount = 1;
3975 copyInfo.imageExtent.depth = 1;
3977 copyInfo.imageOffset.z = uint32_t(layer);
3979 copyInfo.imageOffset.y = uint32_t(layer);
3981 const QByteArray rawData = subresDesc.data();
3982 const QPoint dp = subresDesc.destinationTopLeft();
3983 QImage image = subresDesc.image();
3984 if (!image.isNull()) {
3985 copySizeBytes = imageSizeBytes = image.sizeInBytes();
3986 QSize size = image.size();
3987 src = image.constBits();
3990 int bpc = qMax(1, image.depth() / 8);
3992 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
3993 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
3994 const int sx = subresDesc.sourceTopLeft().x();
3995 const int sy = subresDesc.sourceTopLeft().y();
3996 if (!subresDesc.sourceSize().isEmpty())
3997 size = subresDesc.sourceSize();
3999 if (size.width() == image.width()) {
4002 src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
4003 copySizeBytes = size.height() * image.bytesPerLine();
4005 image = image.copy(sx, sy, size.width(), size.height());
4006 src = image.constBits();
4009 copySizeBytes = image.sizeInBytes();
4010 bpc = qMax(1, image.depth() / 8);
4011 copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
4014 copyInfo.imageOffset.x = dp.x();
4015 copyInfo.imageOffset.y = dp.y();
4016 copyInfo.imageExtent.width = uint32_t(size.width());
4017 copyInfo.imageExtent.height = uint32_t(size.height());
4018 copyInfos->append(copyInfo);
4019 }
else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
4020 copySizeBytes = imageSizeBytes = rawData.size();
4021 src = rawData.constData();
4022 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4023 const int subresw = size.width();
4024 const int subresh = size.height();
4025 if (!subresDesc.sourceSize().isEmpty())
4026 size = subresDesc.sourceSize();
4027 const int w = size.width();
4028 const int h = size.height();
4030 compressedFormatInfo(texD->m_format, QSize(w, h),
nullptr,
nullptr, &blockDim);
4032 copyInfo.imageOffset.x = aligned(dp.x(), blockDim.width());
4033 copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
4036 copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
4037 copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
4038 copyInfos->append(copyInfo);
4039 }
else if (!rawData.isEmpty()) {
4040 copySizeBytes = imageSizeBytes = rawData.size();
4041 src = rawData.constData();
4042 QSize size = q->sizeForMipLevel(level, texD->m_pixelSize);
4043 if (subresDesc.dataStride()) {
4044 quint32 bytesPerPixel = 0;
4045 textureFormatInfo(texD->m_format, size,
nullptr,
nullptr, &bytesPerPixel);
4047 copyInfo.bufferRowLength = subresDesc.dataStride() / bytesPerPixel;
4049 if (!subresDesc.sourceSize().isEmpty())
4050 size = subresDesc.sourceSize();
4051 copyInfo.imageOffset.x = dp.x();
4052 copyInfo.imageOffset.y = dp.y();
4053 copyInfo.imageExtent.width = uint32_t(size.width());
4054 copyInfo.imageExtent.height = uint32_t(size.height());
4055 copyInfos->append(copyInfo);
4057 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4061 memcpy(
reinterpret_cast<
char *>(mp) + *curOfs, src, size_t(copySizeBytes));
4062 *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
4068 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
4069 qWarning() <<
"Out of device memory, current allocator statistics are" << statistics();
4080 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4082 if (u.offset == 0 && u
.data.size() == bufD->m_size)
4083 bufD->pendingDynamicUpdates[i].clear();
4084 bufD->pendingDynamicUpdates[i].append({ u.offset, u
.data });
4088 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4089 Q_ASSERT(u.offset + u
.data.size() <= bufD->m_size);
4091 if (!bufD->stagingBuffers[currentFrameSlot]) {
4092 VkBufferCreateInfo bufferInfo = {};
4093 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4096 bufferInfo.size = bufD->m_size;
4097 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4099 VmaAllocationCreateInfo allocInfo = {};
4100 allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
4102 VmaAllocation allocation;
4103 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4104 &bufD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4105 if (err == VK_SUCCESS) {
4106 bufD->stagingAllocations[currentFrameSlot] = allocation;
4107 setAllocationName(allocation, bufD->name());
4109 qWarning(
"Failed to create staging buffer of size %u: %d", bufD->m_size, err);
4110 printExtraErrorInfo(err);
4115 VkResult err = vmaCopyMemoryToAllocation(toVmaAllocator(allocator), u.data.constData(),
4116 toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]),
4117 u.offset, u.data.size());
4118 if (err != VK_SUCCESS) {
4119 qWarning(
"Failed to copy memory to buffer: %d", err);
4123 trackedBufferBarrier(cbD, bufD, 0,
4124 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4126 VkBufferCopy copyInfo = {};
4127 copyInfo.srcOffset = u.offset;
4128 copyInfo.dstOffset = u.offset;
4129 copyInfo.size = u
.data.size();
4133 cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
4134 cmd.args.copyBuffer.dst = bufD->buffers[0];
4135 cmd.args.copyBuffer.desc = copyInfo;
4144 bufD->lastActiveFrameSlot = currentFrameSlot;
4146 if (bufD->m_type == QRhiBuffer::Immutable) {
4149 e.lastActiveFrameSlot = currentFrameSlot;
4150 e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
4151 e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
4152 bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4153 bufD->stagingAllocations[currentFrameSlot] =
nullptr;
4154 releaseQueue.append(e);
4158 if (bufD->m_type == QRhiBuffer::Dynamic) {
4159 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
4160 u.result->data.resizeForOverwrite(u.readSize);
4161 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4162 toVmaAllocation(bufD->allocations[currentFrameSlot]),
4163 u.offset, u.result->data.data(), u.readSize);
4164 if (err != VK_SUCCESS) {
4165 qWarning(
"Failed to copy memory from buffer: %d", err);
4166 u.result->data.clear();
4168 if (u.result->completed)
4169 u.result->completed();
4178 readback.activeFrameSlot = currentFrameSlot;
4179 readback.result = u.result;
4180 readback.byteSize = u.readSize;
4182 VkBufferCreateInfo bufferInfo = {};
4183 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4184 bufferInfo.size = readback.byteSize;
4185 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4187 VmaAllocationCreateInfo allocInfo = {};
4188 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4190 VmaAllocation allocation;
4191 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4192 if (err == VK_SUCCESS) {
4194 setAllocationName(allocation, bufD->name());
4196 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4197 printExtraErrorInfo(err);
4201 trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4203 VkBufferCopy copyInfo = {};
4204 copyInfo.srcOffset = u.offset;
4205 copyInfo.size = u.readSize;
4209 cmd.args.copyBuffer.src = bufD->buffers[0];
4210 cmd.args.copyBuffer.dst = readback.stagingBuf;
4211 cmd.args.copyBuffer.desc = copyInfo;
4213 bufD->lastActiveFrameSlot = currentFrameSlot;
4215 activeBufferReadbacks.append(readback);
4225 VkDeviceSize stagingSize = 0;
4226 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4227 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4228 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
4229 stagingSize += subresUploadByteSize(subresDesc);
4233 Q_ASSERT(!utexD->stagingBuffers[currentFrameSlot]);
4234 VkBufferCreateInfo bufferInfo = {};
4235 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4236 bufferInfo.size = stagingSize;
4237 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
4239 VmaAllocationCreateInfo allocInfo = {};
4240 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
4242 VmaAllocation allocation;
4243 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
4244 &utexD->stagingBuffers[currentFrameSlot], &allocation,
nullptr);
4245 if (err != VK_SUCCESS) {
4246 qWarning(
"Failed to create image staging buffer of size %d: %d",
int(stagingSize), err);
4247 printExtraErrorInfo(err);
4250 utexD->stagingAllocations[currentFrameSlot] = allocation;
4251 setAllocationName(allocation, utexD->name());
4253 BufferImageCopyList copyInfos;
4256 VmaAllocation a = toVmaAllocation(utexD->stagingAllocations[currentFrameSlot]);
4257 err = vmaMapMemory(toVmaAllocator(allocator), a, &mp);
4258 if (err != VK_SUCCESS) {
4259 qWarning(
"Failed to map image data: %d", err);
4263 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4264 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4265 const QList<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
4268 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(srd)) {
4269 prepareUploadSubres(utexD, layer, level,
4270 subresDesc, &curOfs, mp, ©Infos);
4274 vmaFlushAllocation(toVmaAllocator(allocator), a, 0, stagingSize);
4275 vmaUnmapMemory(toVmaAllocator(allocator), a);
4277 trackedImageBarrier(cbD, utexD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4278 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4282 cmd.args.copyBufferToImage.src = utexD->stagingBuffers[currentFrameSlot];
4283 cmd.args.copyBufferToImage.dst = utexD->image;
4284 cmd.args.copyBufferToImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4285 cmd.args.copyBufferToImage.count = copyInfos.size();
4286 cmd.args.copyBufferToImage.bufferImageCopyIndex = cbD->pools.bufferImageCopy.size();
4287 cbD->pools.bufferImageCopy.append(copyInfos.constData(), copyInfos.size());
4292 e.lastActiveFrameSlot = currentFrameSlot;
4293 e.stagingBuffer.stagingBuffer = utexD->stagingBuffers[currentFrameSlot];
4294 e.stagingBuffer.stagingAllocation = utexD->stagingAllocations[currentFrameSlot];
4295 utexD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
4296 utexD->stagingAllocations[currentFrameSlot] =
nullptr;
4297 releaseQueue.append(e);
4302 utexD->lastActiveFrameSlot = currentFrameSlot;
4306 qWarning(
"Texture copy with matching source and destination is not supported");
4311 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4312 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4314 VkImageCopy region = {};
4315 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4316 region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
4317 region.srcSubresource.baseArrayLayer = srcIs3D ? 0 : uint32_t(u.desc.sourceLayer());
4318 region.srcSubresource.layerCount = 1;
4320 region.srcOffset.x = u.desc.sourceTopLeft().x();
4321 region.srcOffset.y = u.desc.sourceTopLeft().y();
4323 region.srcOffset.z = uint32_t(u.desc.sourceLayer());
4325 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4326 region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
4327 region.dstSubresource.baseArrayLayer = dstIs3D ? 0 : uint32_t(u.desc.destinationLayer());
4328 region.dstSubresource.layerCount = 1;
4330 region.dstOffset.x = u.desc.destinationTopLeft().x();
4331 region.dstOffset.y = u.desc.destinationTopLeft().y();
4333 region.dstOffset.z = uint32_t(u.desc.destinationLayer());
4335 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4336 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4337 region.extent.width = uint32_t(copySize.width());
4338 region.extent.height = uint32_t(copySize.height());
4339 region.extent.depth = 1;
4341 trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4342 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4343 trackedImageBarrier(cbD, dstD, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4344 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4348 cmd.args.copyImage.src = srcD->image;
4349 cmd.args.copyImage.srcLayout = srcD->usageState.layout;
4350 cmd.args.copyImage.dst = dstD->image;
4351 cmd.args.copyImage.dstLayout = dstD->usageState.layout;
4352 cmd.args.copyImage.desc = region;
4354 srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
4357 readback.activeFrameSlot = currentFrameSlot;
4358 readback.desc = u.rb;
4359 readback.result = u.result;
4365 if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
4366 qWarning(
"Multisample texture cannot be read back");
4369 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4370 if (u.rb.rect().isValid())
4371 readback.rect = u.rb.rect();
4373 readback.rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4374 readback.format = texD->m_format;
4375 texD->lastActiveFrameSlot = currentFrameSlot;
4380 qWarning(
"Swapchain does not support readback");
4383 if (u.rb.rect().isValid())
4384 readback.rect = u.rb.rect();
4386 readback.rect = QRect({0, 0}, swapChainD->pixelSize);
4387 readback.format = swapchainReadbackTextureFormat(swapChainD->colorFormat,
nullptr);
4388 if (readback.format == QRhiTexture::UnknownFormat)
4394 textureFormatInfo(readback.format, readback.rect.size(),
nullptr, &readback.byteSize,
nullptr);
4397 VkBufferCreateInfo bufferInfo = {};
4398 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4399 bufferInfo.size = readback.byteSize;
4400 bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4402 VmaAllocationCreateInfo allocInfo = {};
4403 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
4405 VmaAllocation allocation;
4406 VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation,
nullptr);
4407 if (err == VK_SUCCESS) {
4409 setAllocationName(allocation, texD ? texD->name() : swapChainD->name());
4411 qWarning(
"Failed to create readback buffer of size %u: %d", readback.byteSize, err);
4412 printExtraErrorInfo(err);
4417 VkBufferImageCopy copyDesc = {};
4418 copyDesc.bufferOffset = 0;
4419 copyDesc.imageSubresource.aspectMask = aspectMaskForTextureFormat(readback.format);
4420 copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
4421 copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer());
4422 copyDesc.imageSubresource.layerCount = 1;
4423 copyDesc.imageOffset.x = readback.rect.x();
4424 copyDesc.imageOffset.y = readback.rect.y();
4426 copyDesc.imageOffset.z = u.rb.layer();
4427 copyDesc.imageExtent.width = uint32_t(readback.rect.width());
4428 copyDesc.imageExtent.height = uint32_t(readback.rect.height());
4429 copyDesc.imageExtent.depth = 1;
4432 trackedImageBarrier(cbD, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4433 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
4436 cmd.args.copyImageToBuffer.src = texD->image;
4437 cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
4438 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4439 cmd.args.copyImageToBuffer.desc = copyDesc;
4443 VkImage image = imageRes.image;
4446 qWarning(
"Attempted to read back undefined swapchain image content, "
4447 "results are undefined. (do a render pass first)");
4449 subresourceBarrier(cbD, image,
4450 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4451 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4452 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4460 cmd.args.copyImageToBuffer.src = image;
4461 cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4462 cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
4463 cmd.args.copyImageToBuffer.desc = copyDesc;
4466 activeTextureReadbacks.append(readback);
4469 Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
4470 const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap);
4471 const bool isArray = utexD->m_flags.testFlag(QRhiTexture::TextureArray);
4472 const bool is3D = utexD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4474 VkImageLayout origLayout = utexD->usageState.layout;
4475 VkAccessFlags origAccess = utexD->usageState.access;
4476 VkPipelineStageFlags origStage = utexD->usageState.stage;
4478 origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
4480 for (
int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
4481 int w = utexD->m_pixelSize.width();
4482 int h = utexD->m_pixelSize.height();
4483 int depth = is3D ? qMax(1, utexD->m_depth) : 1;
4484 for (
int level = 1; level <
int(utexD->mipLevelCount); ++level) {
4486 subresourceBarrier(cbD, utexD->image,
4487 origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4488 origAccess, VK_ACCESS_TRANSFER_READ_BIT,
4489 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4493 subresourceBarrier(cbD, utexD->image,
4494 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4495 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
4496 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
4501 subresourceBarrier(cbD, utexD->image,
4502 origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4503 origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
4504 origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
4508 VkImageBlit region = {};
4509 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4510 region.srcSubresource.mipLevel = uint32_t(level) - 1;
4511 region.srcSubresource.baseArrayLayer = uint32_t(layer);
4512 region.srcSubresource.layerCount = 1;
4514 region.srcOffsets[1].x = qMax(1, w);
4515 region.srcOffsets[1].y = qMax(1, h);
4516 region.srcOffsets[1].z = qMax(1, depth);
4518 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4519 region.dstSubresource.mipLevel = uint32_t(level);
4520 region.dstSubresource.baseArrayLayer = uint32_t(layer);
4521 region.dstSubresource.layerCount = 1;
4523 region.dstOffsets[1].x = qMax(1, w >> 1);
4524 region.dstOffsets[1].y = qMax(1, h >> 1);
4525 region.dstOffsets[1].z = qMax(1, depth >> 1);
4529 cmd.args.blitImage.src = utexD->image;
4530 cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4531 cmd.args.blitImage.dst = utexD->image;
4532 cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
4533 cmd.args.blitImage.filter = VK_FILTER_LINEAR;
4534 cmd.args.blitImage.desc = region;
4541 if (utexD->mipLevelCount > 1) {
4542 subresourceBarrier(cbD, utexD->image,
4543 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
4544 VK_ACCESS_TRANSFER_READ_BIT, origAccess,
4545 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4547 0,
int(utexD->mipLevelCount) - 1);
4548 subresourceBarrier(cbD, utexD->image,
4549 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
4550 VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
4551 VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
4553 int(utexD->mipLevelCount) - 1, 1);
4556 utexD->lastActiveFrameSlot = currentFrameSlot;
4565 if (bufD->pendingDynamicUpdates[slot].isEmpty())
4568 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4570 VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
4574 VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
4575 if (err != VK_SUCCESS) {
4576 qWarning(
"Failed to map buffer: %d", err);
4579 quint32 changeBegin = UINT32_MAX;
4580 quint32 changeEnd = 0;
4581 for (
const QVkBuffer::DynamicUpdate &u : std::as_const(bufD->pendingDynamicUpdates[slot])) {
4582 memcpy(
static_cast<
char *>(p) + u.offset, u.data.constData(), u.data.size());
4583 if (u.offset < changeBegin)
4584 changeBegin = u.offset;
4585 if (u.offset + u.data.size() > changeEnd)
4586 changeEnd = u.offset + u.data.size();
4588 if (changeBegin < UINT32_MAX && changeBegin < changeEnd)
4589 vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
4590 vmaUnmapMemory(toVmaAllocator(allocator), a);
4592 bufD->pendingDynamicUpdates[slot].clear();
4598 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.buffers[i], toVmaAllocation(e.buffer.allocations[i]));
4599 vmaDestroyBuffer(toVmaAllocator(allocator), e.buffer.stagingBuffers[i], toVmaAllocation(e.buffer.stagingAllocations[i]));
4605 df->vkDestroyImageView(dev, e.renderBuffer.imageView,
nullptr);
4606 df->vkDestroyImage(dev, e.renderBuffer.image,
nullptr);
4607 df->vkFreeMemory(dev, e.renderBuffer.memory,
nullptr);
4612 df->vkDestroyImageView(dev, e.texture.imageView,
nullptr);
4613 vmaDestroyImage(toVmaAllocator(allocator), e.texture.image, toVmaAllocation(e.texture.allocation));
4614 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
4615 vmaDestroyBuffer(toVmaAllocator(allocator), e.texture.stagingBuffers[i], toVmaAllocation(e.texture.stagingAllocations[i]));
4616 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
4617 if (e.texture.extraImageViews[i])
4618 df->vkDestroyImageView(dev, e.texture.extraImageViews[i],
nullptr);
4624 df->vkDestroySampler(dev, e.sampler.sampler,
nullptr);
4629 for (
int i = releaseQueue.size() - 1; i >= 0; --i) {
4631 if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) {
4633 case QRhiVulkan::DeferredReleaseEntry::Pipeline:
4634 df->vkDestroyPipeline(dev, e.pipelineState.pipeline,
nullptr);
4635 df->vkDestroyPipelineLayout(dev, e.pipelineState.layout,
nullptr);
4637 case QRhiVulkan::DeferredReleaseEntry::ShaderResourceBindings:
4638 df->vkDestroyDescriptorSetLayout(dev, e.shaderResourceBindings.layout,
nullptr);
4639 if (e.shaderResourceBindings.poolIndex >= 0) {
4640 descriptorPools[e.shaderResourceBindings.poolIndex].refCount -= 1;
4641 Q_ASSERT(descriptorPools[e.shaderResourceBindings.poolIndex].refCount >= 0);
4647 case QRhiVulkan::DeferredReleaseEntry::RenderBuffer:
4648 qrhivk_releaseRenderBuffer(e, dev, df);
4650 case QRhiVulkan::DeferredReleaseEntry::Texture:
4651 qrhivk_releaseTexture(e, dev, df, allocator);
4653 case QRhiVulkan::DeferredReleaseEntry::Sampler:
4654 qrhivk_releaseSampler(e, dev, df);
4656 case QRhiVulkan::DeferredReleaseEntry::TextureRenderTarget:
4657 df->vkDestroyFramebuffer(dev, e.textureRenderTarget.fb,
nullptr);
4659 df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att],
nullptr);
4660 df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att],
nullptr);
4662 df->vkDestroyImageView(dev, e.textureRenderTarget.dsv,
nullptr);
4663 df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv,
nullptr);
4664 df->vkDestroyImageView(dev, e.textureRenderTarget.shadingRateMapView,
nullptr);
4666 case QRhiVulkan::DeferredReleaseEntry::RenderPass:
4667 df->vkDestroyRenderPass(dev, e.renderPass.rp,
nullptr);
4669 case QRhiVulkan::DeferredReleaseEntry::StagingBuffer:
4670 vmaDestroyBuffer(toVmaAllocator(allocator), e.stagingBuffer.stagingBuffer, toVmaAllocation(e.stagingBuffer.stagingAllocation));
4672 case QRhiVulkan::DeferredReleaseEntry::SecondaryCommandBuffer:
4673 freeSecondaryCbs[e.lastActiveFrameSlot].append(e.secondaryCommandBuffer.cb);
4679 releaseQueue.removeAt(i);
4686 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4688 for (
int i = activeTextureReadbacks.size() - 1; i >= 0; --i) {
4690 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4691 readback.result->format = readback.format;
4692 readback.result->pixelSize = readback.rect.size();
4693 readback.result->data.resizeForOverwrite(readback.byteSize);
4694 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4695 toVmaAllocation(readback.stagingAlloc),
4696 0, readback.result->data.data(), readback.byteSize);
4697 if (err != VK_SUCCESS) {
4698 qWarning(
"Failed to copy texture readback buffer of size %u: %d", readback.byteSize, err);
4699 readback.result->data.clear();
4702 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4704 if (readback.result->completed)
4705 completedCallbacks.append(readback.result->completed);
4707 activeTextureReadbacks.remove(i);
4711 for (
int i = activeBufferReadbacks.size() - 1; i >= 0; --i) {
4713 if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
4714 readback.result->data.resizeForOverwrite(readback.byteSize);
4715 VkResult err = vmaCopyAllocationToMemory(toVmaAllocator(allocator),
4716 toVmaAllocation(readback.stagingAlloc),
4717 0, readback.result->data.data(), readback.byteSize);
4718 if (err != VK_SUCCESS) {
4719 qWarning(
"Failed to copy buffer readback buffer of size %d: %d", readback.byteSize, err);
4720 readback.result->data.clear();
4723 vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, toVmaAllocation(readback.stagingAlloc));
4725 if (readback.result->completed)
4726 completedCallbacks.append(readback.result->completed);
4728 activeBufferReadbacks.remove(i);
4732 for (
auto f : completedCallbacks)
4739} qvk_sampleCounts[] = {
4741 { VK_SAMPLE_COUNT_1_BIT, 1 },
4742 { VK_SAMPLE_COUNT_2_BIT, 2 },
4743 { VK_SAMPLE_COUNT_4_BIT, 4 },
4744 { VK_SAMPLE_COUNT_8_BIT, 8 },
4745 { VK_SAMPLE_COUNT_16_BIT, 16 },
4746 { VK_SAMPLE_COUNT_32_BIT, 32 },
4747 { VK_SAMPLE_COUNT_64_BIT, 64 }
4752 const VkPhysicalDeviceLimits *limits = &physDevProperties.limits;
4753 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
4754 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
4755 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
4758 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4759 if ((color & qvk_sampleCount.mask)
4760 && (depth & qvk_sampleCount.mask)
4761 && (stencil & qvk_sampleCount.mask))
4763 result.append(qvk_sampleCount.count);
4772 const int s = effectiveSampleCount(sampleCount);
4774 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4775 if (qvk_sampleCount.count == s)
4776 return qvk_sampleCount.mask;
4779 Q_UNREACHABLE_RETURN(VK_SAMPLE_COUNT_1_BIT);
4784 QList<QSize> result;
4785#ifdef VK_KHR_fragment_shading_rate
4786 sampleCount = qMax(1, sampleCount);
4787 VkSampleCountFlagBits mask = VK_SAMPLE_COUNT_1_BIT;
4788 for (
const auto &qvk_sampleCount : qvk_sampleCounts) {
4789 if (qvk_sampleCount.count == sampleCount) {
4790 mask = qvk_sampleCount.mask;
4794 for (
const VkPhysicalDeviceFragmentShadingRateKHR &s : fragmentShadingRates) {
4795 if (s.sampleCounts & mask)
4796 result.append(QSize(
int(s.fragmentSize.width),
int(s.fragmentSize.height)));
4799 Q_UNUSED(sampleCount);
4800 result.append(QSize(1, 1));
4807 cbD->passResTrackers.emplace_back();
4812 cmd.args.transitionResources.trackerIndex = cbD->passResTrackers.size() - 1;
4819 for (
auto it = cbD->commands.begin(), end = cbD->commands.end(); it != end; ++it) {
4823 df->vkCmdCopyBuffer(cbD->cb, cmd.args.copyBuffer.src, cmd.args.copyBuffer.dst,
4824 1, &cmd.args.copyBuffer.desc);
4827 df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
4828 cmd.args.copyBufferToImage.dstLayout,
4829 uint32_t(cmd.args.copyBufferToImage.count),
4830 cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
4833 df->vkCmdCopyImage(cbD->cb, cmd.args.copyImage.src, cmd.args.copyImage.srcLayout,
4834 cmd.args.copyImage.dst, cmd.args.copyImage.dstLayout,
4835 1, &cmd.args.copyImage.desc);
4838 df->vkCmdCopyImageToBuffer(cbD->cb, cmd.args.copyImageToBuffer.src, cmd.args.copyImageToBuffer.srcLayout,
4839 cmd.args.copyImageToBuffer.dst,
4840 1, &cmd.args.copyImageToBuffer.desc);
4843 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
4844 0, 0,
nullptr, 0,
nullptr,
4845 cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
4848 df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
4850 cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
4854 df->vkCmdBlitImage(cbD->cb, cmd.args.blitImage.src, cmd.args.blitImage.srcLayout,
4855 cmd.args.blitImage.dst, cmd.args.blitImage.dstLayout,
4856 1, &cmd.args.blitImage.desc,
4857 cmd.args.blitImage.filter);
4860 cmd.args.beginRenderPass.desc.pClearValues = cbD->pools.clearValue.constData() + cmd.args.beginRenderPass.clearValueIndex;
4861 df->vkCmdBeginRenderPass(cbD->cb, &cmd.args.beginRenderPass.desc,
4862 cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
4863 : VK_SUBPASS_CONTENTS_INLINE);
4866 df->vkCmdEndRenderPass(cbD->cb);
4869 df->vkCmdBindPipeline(cbD->cb, cmd.args.bindPipeline.bindPoint, cmd.args.bindPipeline.pipeline);
4873 const uint32_t *offsets =
nullptr;
4874 if (cmd.args.bindDescriptorSet.dynamicOffsetCount > 0)
4875 offsets = cbD->pools.dynamicOffset.constData() + cmd.args.bindDescriptorSet.dynamicOffsetIndex;
4876 df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
4877 cmd.args.bindDescriptorSet.pipelineLayout,
4878 0, 1, &cmd.args.bindDescriptorSet.descSet,
4879 uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
4884 df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
4885 uint32_t(cmd.args.bindVertexBuffer.count),
4886 cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
4887 cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
4890 df->vkCmdBindIndexBuffer(cbD->cb, cmd.args.bindIndexBuffer.buf,
4891 cmd.args.bindIndexBuffer.ofs, cmd.args.bindIndexBuffer.type);
4894 df->vkCmdSetViewport(cbD->cb, 0, 1, &cmd.args.setViewport.viewport);
4897 df->vkCmdSetScissor(cbD->cb, 0, 1, &cmd.args.setScissor.scissor);
4900 df->vkCmdSetBlendConstants(cbD->cb, cmd.args.setBlendConstants.c);
4902 case QVkCommandBuffer::Command::SetStencilRef:
4903 df->vkCmdSetStencilReference(cbD->cb, VK_STENCIL_FRONT_AND_BACK, cmd.args.setStencilRef.ref);
4906 df->vkCmdDraw(cbD->cb, cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
4907 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
4910 df->vkCmdDrawIndexed(cbD->cb, cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
4911 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
4912 cmd.args.drawIndexed.firstInstance);
4915#ifdef VK_EXT_debug_utils
4916 cmd.args.debugMarkerBegin.label.pLabelName =
4917 cbD->pools.debugMarkerData[cmd.args.debugMarkerBegin.labelNameIndex].constData();
4918 vkCmdBeginDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerBegin.label);
4922#ifdef VK_EXT_debug_utils
4923 vkCmdEndDebugUtilsLabelEXT(cbD->cb);
4927#ifdef VK_EXT_debug_utils
4928 cmd.args.debugMarkerInsert.label.pLabelName =
4929 cbD->pools.debugMarkerData[cmd.args.debugMarkerInsert.labelNameIndex].constData();
4930 vkCmdInsertDebugUtilsLabelEXT(cbD->cb, &cmd.args.debugMarkerInsert.label);
4937 df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
4940 df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
4944#ifdef VK_KHR_fragment_shading_rate
4945 VkFragmentShadingRateCombinerOpKHR op[2] = {
4946 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
4947 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
4949 VkExtent2D size = { cmd.args.setShadingRate.w, cmd.args.setShadingRate.h };
4950 vkCmdSetFragmentShadingRateKHR(cbD->cb, &size, op);
4963 case QRhiPassResourceTracker::BufVertexInput:
4964 return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
4965 case QRhiPassResourceTracker::BufIndexRead:
4966 return VK_ACCESS_INDEX_READ_BIT;
4967 case QRhiPassResourceTracker::BufUniformRead:
4968 return VK_ACCESS_UNIFORM_READ_BIT;
4969 case QRhiPassResourceTracker::BufStorageLoad:
4970 return VK_ACCESS_SHADER_READ_BIT;
4971 case QRhiPassResourceTracker::BufStorageStore:
4972 return VK_ACCESS_SHADER_WRITE_BIT;
4973 case QRhiPassResourceTracker::BufStorageLoadStore:
4974 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
4985 case QRhiPassResourceTracker::BufVertexInputStage:
4986 return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
4987 case QRhiPassResourceTracker::BufVertexStage:
4988 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
4989 case QRhiPassResourceTracker::BufTCStage:
4990 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
4991 case QRhiPassResourceTracker::BufTEStage:
4992 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
4993 case QRhiPassResourceTracker::BufFragmentStage:
4994 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
4995 case QRhiPassResourceTracker::BufComputeStage:
4996 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
4997 case QRhiPassResourceTracker::BufGeometryStage:
4998 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5009 u.access = VkAccessFlags(usage
.access);
5010 u.stage = VkPipelineStageFlags(usage
.stage);
5017 case QRhiPassResourceTracker::TexSample:
5018 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5019 case QRhiPassResourceTracker::TexColorOutput:
5020 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
5021 case QRhiPassResourceTracker::TexDepthOutput:
5022 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
5023 case QRhiPassResourceTracker::TexStorageLoad:
5024 case QRhiPassResourceTracker::TexStorageStore:
5025 case QRhiPassResourceTracker::TexStorageLoadStore:
5026 return VK_IMAGE_LAYOUT_GENERAL;
5027 case QRhiPassResourceTracker::TexShadingRate:
5028#ifdef VK_KHR_fragment_shading_rate
5029 return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
5031 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
5037 return VK_IMAGE_LAYOUT_GENERAL;
5043 case QRhiPassResourceTracker::TexSample:
5044 return VK_ACCESS_SHADER_READ_BIT;
5045 case QRhiPassResourceTracker::TexColorOutput:
5046 return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
5047 case QRhiPassResourceTracker::TexDepthOutput:
5048 return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
5049 case QRhiPassResourceTracker::TexStorageLoad:
5050 return VK_ACCESS_SHADER_READ_BIT;
5051 case QRhiPassResourceTracker::TexStorageStore:
5052 return VK_ACCESS_SHADER_WRITE_BIT;
5053 case QRhiPassResourceTracker::TexStorageLoadStore:
5054 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
5067 case QRhiPassResourceTracker::TexVertexStage:
5068 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
5069 case QRhiPassResourceTracker::TexTCStage:
5070 return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
5071 case QRhiPassResourceTracker::TexTEStage:
5072 return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
5073 case QRhiPassResourceTracker::TexFragmentStage:
5074 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
5075 case QRhiPassResourceTracker::TexColorOutputStage:
5076 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
5077 case QRhiPassResourceTracker::TexDepthOutputStage:
5078 return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
5079 case QRhiPassResourceTracker::TexComputeStage:
5080 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
5081 case QRhiPassResourceTracker::TexGeometryStage:
5082 return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
5093 u.layout = VkImageLayout(usage
.layout);
5094 u.access = VkAccessFlags(usage
.access);
5095 u.stage = VkPipelineStageFlags(usage
.stage);
5106 const VkAccessFlags newAccess = toVkAccess(access);
5107 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5108 if (u.access == newAccess && u.stage == newStage) {
5109 if (!accessIsWrite(access))
5113 u.access = newAccess;
5123 const VkAccessFlags newAccess = toVkAccess(access);
5124 const VkPipelineStageFlags newStage = toVkPipelineStage(stage);
5125 const VkImageLayout newLayout = toVkLayout(access);
5126 if (u.access == newAccess && u.stage == newStage && u.layout == newLayout) {
5127 if (!accessIsWrite(access))
5131 u.layout = newLayout;
5132 u.access = newAccess;
5141 for (
const auto &[rhiB, trackedB]: tracker.buffers()) {
5142 QVkBuffer *bufD =
QRHI_RES(QVkBuffer, rhiB);
5143 VkAccessFlags access = toVkAccess(trackedB.access);
5144 VkPipelineStageFlags stage = toVkPipelineStage(trackedB.stage);
5145 QVkBuffer::UsageState s = toVkBufferUsageState(trackedB.stateAtPassBegin);
5148 if (s.access == access && s.stage == stage) {
5149 if (!accessIsWrite(access))
5152 VkBufferMemoryBarrier bufMemBarrier = {};
5153 bufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5154 bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5155 bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
5156 bufMemBarrier.srcAccessMask = s.access;
5157 bufMemBarrier.dstAccessMask = access;
5158 bufMemBarrier.buffer = bufD->buffers[trackedB.slot];
5159 bufMemBarrier.size = VK_WHOLE_SIZE;
5160 df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
5166 for (
const auto &[rhiT, trackedT]: tracker.textures()) {
5167 QVkTexture *texD =
QRHI_RES(QVkTexture, rhiT);
5168 VkImageLayout layout = toVkLayout(trackedT.access);
5169 VkAccessFlags access = toVkAccess(trackedT.access);
5170 VkPipelineStageFlags stage = toVkPipelineStage(trackedT.stage);
5171 QVkTexture::UsageState s = toVkTextureUsageState(trackedT.stateAtPassBegin);
5172 if (s.access == access && s.stage == stage && s.layout == layout) {
5173 if (!accessIsWrite(access))
5176 VkImageMemoryBarrier barrier = {};
5177 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5178 barrier.subresourceRange.aspectMask = aspectMaskForTextureFormat(texD->m_format);
5179 barrier.subresourceRange.baseMipLevel = 0;
5180 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
5181 barrier.subresourceRange.baseArrayLayer = 0;
5182 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
5183 barrier.oldLayout = s.layout;
5184 barrier.newLayout = layout;
5185 barrier.srcAccessMask = s.access;
5186 barrier.dstAccessMask = access;
5187 barrier.image = texD->image;
5188 VkPipelineStageFlags srcStage = s.stage;
5191 srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
5192 df->vkCmdPipelineBarrier(cbD->cb, srcStage, stage, 0,
5201 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
5202 || !vkGetPhysicalDeviceSurfaceFormatsKHR
5203 || !vkGetPhysicalDeviceSurfacePresentModesKHR)
5205 qWarning(
"Physical device surface queries not available");
5209 return new QVkSwapChain(
this);
5212QRhiBuffer *
QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
5214 return new QVkBuffer(
this, type, usage, size);
5219 return int(ubufAlign);
5241 static QMatrix4x4 m;
5242 if (m.isIdentity()) {
5244 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
5245 0.0f, -1.0f, 0.0f, 0.0f,
5246 0.0f, 0.0f, 0.5f, 0.5f,
5247 0.0f, 0.0f, 0.0f, 1.0f);
5257 if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
5258 if (!physDevFeatures.textureCompressionBC)
5262 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
5263 if (!physDevFeatures.textureCompressionETC2)
5267 if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
5268 if (!physDevFeatures.textureCompressionASTC_LDR)
5272 VkFormat vkformat = toVkTextureFormat(format, flags);
5273 VkFormatProperties props;
5274 f->vkGetPhysicalDeviceFormatProperties(physDev, vkformat, &props);
5275 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0;
5281 case QRhi::MultisampleTexture:
5283 case QRhi::MultisampleRenderBuffer:
5285 case QRhi::DebugMarkers:
5286 return caps.debugUtils;
5287 case QRhi::Timestamps:
5288 return timestampValidBits != 0;
5289 case QRhi::Instancing:
5291 case QRhi::CustomInstanceStepRate:
5292 return caps.vertexAttribDivisor;
5293 case QRhi::PrimitiveRestart:
5295 case QRhi::NonDynamicUniformBuffers:
5297 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
5299 case QRhi::NPOTTextureRepeat:
5301 case QRhi::RedOrAlpha8IsRed:
5303 case QRhi::ElementIndexUint:
5306 return caps.compute;
5307 case QRhi::WideLines:
5308 return caps.wideLines;
5309 case QRhi::VertexShaderPointSize:
5311 case QRhi::BaseVertex:
5313 case QRhi::BaseInstance:
5315 case QRhi::TriangleFanTopology:
5317 case QRhi::ReadBackNonUniformBuffer:
5319 case QRhi::ReadBackNonBaseMipLevel:
5321 case QRhi::TexelFetch:
5323 case QRhi::RenderToNonBaseMipLevel:
5325 case QRhi::IntAttributes:
5327 case QRhi::ScreenSpaceDerivatives:
5329 case QRhi::ReadBackAnyTextureFormat:
5331 case QRhi::PipelineCacheDataLoadSave:
5333 case QRhi::ImageDataStride:
5335 case QRhi::RenderBufferImport:
5337 case QRhi::ThreeDimensionalTextures:
5339 case QRhi::RenderTo3DTextureSlice:
5340 return caps.texture3DSliceAs2D;
5341 case QRhi::TextureArrays:
5343 case QRhi::Tessellation:
5344 return caps.tessellation;
5345 case QRhi::GeometryShader:
5346 return caps.geometryShader;
5347 case QRhi::TextureArrayRange:
5349 case QRhi::NonFillPolygonMode:
5350 return caps.nonFillPolygonMode;
5351 case QRhi::OneDimensionalTextures:
5353 case QRhi::OneDimensionalTextureMipmaps:
5355 case QRhi::HalfAttributes:
5357 case QRhi::RenderToOneDimensionalTexture:
5359 case QRhi::ThreeDimensionalTextureMipmaps:
5361 case QRhi::MultiView:
5362 return caps.multiView;
5363 case QRhi::TextureViewFormat:
5365 case QRhi::ResolveDepthStencil:
5366 return caps.renderPass2KHR && caps.depthStencilResolveKHR;
5367 case QRhi::VariableRateShading:
5368 return caps.renderPass2KHR && caps.perDrawShadingRate;
5369 case QRhi::VariableRateShadingMap:
5370 case QRhi::VariableRateShadingMapWithTexture:
5371 return caps.renderPass2KHR && caps.imageBasedShadingRate;
5372 case QRhi::PerRenderTargetBlending:
5373 case QRhi::SampleVariables:
5375 case QRhi::InstanceIndexIncludesBaseInstance:
5378 Q_UNREACHABLE_RETURN(
false);
5385 case QRhi::TextureSizeMin:
5387 case QRhi::TextureSizeMax:
5388 return int(physDevProperties.limits.maxImageDimension2D);
5389 case QRhi::MaxColorAttachments:
5390 return int(physDevProperties.limits.maxColorAttachments);
5391 case QRhi::FramesInFlight:
5393 case QRhi::MaxAsyncReadbackFrames:
5395 case QRhi::MaxThreadGroupsPerDimension:
5396 return int(qMin(physDevProperties.limits.maxComputeWorkGroupCount[0],
5397 qMin(physDevProperties.limits.maxComputeWorkGroupCount[1],
5398 physDevProperties.limits.maxComputeWorkGroupCount[2])));
5399 case QRhi::MaxThreadsPerThreadGroup:
5400 return int(physDevProperties.limits.maxComputeWorkGroupInvocations);
5401 case QRhi::MaxThreadGroupX:
5402 return int(physDevProperties.limits.maxComputeWorkGroupSize[0]);
5403 case QRhi::MaxThreadGroupY:
5404 return int(physDevProperties.limits.maxComputeWorkGroupSize[1]);
5405 case QRhi::MaxThreadGroupZ:
5406 return int(physDevProperties.limits.maxComputeWorkGroupSize[2]);
5407 case QRhi::TextureArraySizeMax:
5408 return int(physDevProperties.limits.maxImageArrayLayers);
5409 case QRhi::MaxUniformBufferRange:
5410 return int(qMin<uint32_t>(INT_MAX, physDevProperties.limits.maxUniformBufferRange));
5411 case QRhi::MaxVertexInputs:
5412 return physDevProperties.limits.maxVertexInputAttributes;
5413 case QRhi::MaxVertexOutputs:
5414 return physDevProperties.limits.maxVertexOutputComponents / 4;
5415 case QRhi::ShadingRateImageTileSize:
5416 return caps.imageBasedShadingRateTileSize;
5418 Q_UNREACHABLE_RETURN(0);
5424 return &nativeHandlesStruct;
5429 return driverInfoStruct;
5435 result.totalPipelineCreationTime = totalPipelineCreationTime();
5437 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
5438 vmaGetHeapBudgets(toVmaAllocator(allocator), budgets);
5440 uint32_t count = toVmaAllocator(allocator)->GetMemoryHeapCount();
5441 for (uint32_t i = 0; i < count; ++i) {
5442 const VmaStatistics &stats(budgets[i].statistics);
5443 result.blockCount += stats.blockCount;
5444 result.allocCount += stats.allocationCount;
5445 result.usedBytes += stats.allocationBytes;
5446 result.unusedBytes += stats.blockBytes - stats.allocationBytes;
5460 QRhiVulkanQueueSubmitParams *sp =
static_cast<QRhiVulkanQueueSubmitParams *>(params);
5464 waitSemaphoresForQueueSubmit.clear();
5465 if (sp->waitSemaphoreCount)
5466 waitSemaphoresForQueueSubmit.append(sp->waitSemaphores, sp->waitSemaphoreCount);
5468 signalSemaphoresForQueueSubmit.clear();
5469 if (sp->signalSemaphoreCount)
5470 signalSemaphoresForQueueSubmit.append(sp->signalSemaphores, sp->signalSemaphoreCount);
5472 waitSemaphoresForPresent.clear();
5473 if (sp->presentWaitSemaphoreCount)
5474 waitSemaphoresForPresent.append(sp->presentWaitSemaphores, sp->presentWaitSemaphoreCount);
5504 if (!pipelineCache || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
5507 size_t dataSize = 0;
5508 VkResult err = df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize,
nullptr);
5509 if (err != VK_SUCCESS) {
5510 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data size: %d", err);
5511 return QByteArray();
5514 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5515 data.resize(dataOffset + dataSize);
5516 err = df->vkGetPipelineCacheData(dev, pipelineCache, &dataSize, data.data() + dataOffset);
5517 if (err != VK_SUCCESS) {
5518 qCDebug(QRHI_LOG_INFO,
"Failed to get pipeline cache data of %d bytes: %d",
int(dataSize), err);
5519 return QByteArray();
5523 header.rhiId = pipelineCacheRhiId();
5524 header.arch = quint32(
sizeof(
void*));
5525 header.driverVersion = physDevProperties.driverVersion;
5526 header.vendorId = physDevProperties.vendorID;
5527 header.deviceId = physDevProperties.deviceID;
5528 header.dataSize = quint32(dataSize);
5529 header.uuidSize = VK_UUID_SIZE;
5530 header.reserved = 0;
5531 memcpy(data.data(), &header, headerSize);
5532 memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
5543 if (data.size() < qsizetype(headerSize)) {
5544 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
5548 memcpy(&header, data.constData(), headerSize);
5550 const quint32 rhiId = pipelineCacheRhiId();
5551 if (header.rhiId != rhiId) {
5552 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
5553 rhiId, header.rhiId);
5556 const quint32 arch = quint32(
sizeof(
void*));
5557 if (header.arch != arch) {
5558 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
5562 if (header.driverVersion != physDevProperties.driverVersion) {
5563 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: driverVersion does not match (%u, %u)",
5564 physDevProperties.driverVersion, header.driverVersion);
5567 if (header.vendorId != physDevProperties.vendorID) {
5568 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorID does not match (%u, %u)",
5569 physDevProperties.vendorID, header.vendorId);
5572 if (header.deviceId != physDevProperties.deviceID) {
5573 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceID does not match (%u, %u)",
5574 physDevProperties.deviceID, header.deviceId);
5577 if (header.uuidSize != VK_UUID_SIZE) {
5578 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: VK_UUID_SIZE does not match (%u, %u)",
5579 quint32(VK_UUID_SIZE), header.uuidSize);
5583 if (data.size() < qsizetype(headerSize + VK_UUID_SIZE)) {
5584 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, no uuid");
5587 if (memcmp(data.constData() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE)) {
5588 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: pipelineCacheUUID does not match");
5592 const size_t dataOffset = headerSize + VK_UUID_SIZE;
5593 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
5594 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
5598 if (pipelineCache) {
5599 df->vkDestroyPipelineCache(dev, pipelineCache,
nullptr);
5600 pipelineCache = VK_NULL_HANDLE;
5603 if (ensurePipelineCache(data.constData() + dataOffset, header.dataSize)) {
5604 qCDebug(QRHI_LOG_INFO,
"Created pipeline cache with initial data of %d bytes",
5605 int(header.dataSize));
5607 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline cache with initial data specified");
5611QRhiRenderBuffer *
QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
5612 int sampleCount, QRhiRenderBuffer::Flags flags,
5613 QRhiTexture::Format backingFormatHint)
5615 return new QVkRenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
5619 const QSize &pixelSize,
int depth,
int arraySize,
5620 int sampleCount, QRhiTexture::Flags flags)
5622 return new QVkTexture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
5626 QRhiSampler::Filter mipmapMode,
5627 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
5629 return new QVkSampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
5634 return new QVkShadingRateMap(
this);
5638 QRhiTextureRenderTarget::Flags flags)
5645 return new QVkGraphicsPipeline(
this);
5650 return new QVkComputePipeline(
this);
5655 return new QVkShaderResourceBindings(
this);
5661 Q_ASSERT(psD->pipeline);
5665 if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
5667 df->vkCmdBindPipeline(cbD->activeSecondaryCbStack.last(), VK_PIPELINE_BIND_POINT_GRAPHICS, psD->pipeline);
5671 cmd.args.bindPipeline.bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
5672 cmd.args.bindPipeline.pipeline = psD->pipeline;
5675 cbD->currentGraphicsPipeline = ps;
5676 cbD->currentComputePipeline =
nullptr;
5677 cbD->currentPipelineGeneration = psD->generation;
5680 psD->lastActiveFrameSlot = currentFrameSlot;
5684 int dynamicOffsetCount,
5685 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
5695 srb = gfxPsD->m_shaderResourceBindings;
5697 srb = compPsD->m_shaderResourceBindings;
5701 auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
5702 bool rewriteDescSet =
false;
5706 for (
int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
5707 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
5710 case QRhiShaderResourceBinding::UniformBuffer:
5713 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
5715 if (bufD->m_type == QRhiBuffer::Dynamic)
5716 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
5718 bufD->lastActiveFrameSlot = currentFrameSlot;
5719 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5720 QRhiPassResourceTracker::BufUniformRead,
5721 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5727 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
5728 rewriteDescSet =
true;
5729 bd.ubuf.id = bufD->m_id;
5730 bd.ubuf.generation = bufD->generation;
5734 case QRhiShaderResourceBinding::SampledTexture:
5735 case QRhiShaderResourceBinding::Texture:
5736 case QRhiShaderResourceBinding::Sampler:
5738 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
5739 if (bd.stex.count != data->count) {
5740 bd.stex.count = data->count;
5741 rewriteDescSet =
true;
5743 for (
int elem = 0; elem < data->count; ++elem) {
5749 Q_ASSERT(texD || samplerD);
5751 texD->lastActiveFrameSlot = currentFrameSlot;
5757 samplerD->lastActiveFrameSlot = currentFrameSlot;
5758 const quint64 texId = texD ? texD->m_id : 0;
5759 const uint texGen = texD ? texD->generation : 0;
5760 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
5761 const uint samplerGen = samplerD ? samplerD->generation : 0;
5762 if (texGen != bd.stex.d[elem].texGeneration
5763 || texId != bd.stex.d[elem].texId
5764 || samplerGen != bd.stex.d[elem].samplerGeneration
5765 || samplerId != bd.stex.d[elem].samplerId)
5767 rewriteDescSet =
true;
5768 bd.stex.d[elem].texId = texId;
5769 bd.stex.d[elem].texGeneration = texGen;
5770 bd.stex.d[elem].samplerId = samplerId;
5771 bd.stex.d[elem].samplerGeneration = samplerGen;
5776 case QRhiShaderResourceBinding::ImageLoad:
5777 case QRhiShaderResourceBinding::ImageStore:
5778 case QRhiShaderResourceBinding::ImageLoadStore:
5781 Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore));
5782 texD->lastActiveFrameSlot = currentFrameSlot;
5784 if (b->type == QRhiShaderResourceBinding::ImageLoad)
5786 else if (b->type == QRhiShaderResourceBinding::ImageStore)
5794 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
5795 rewriteDescSet =
true;
5796 bd.simage.id = texD->m_id;
5797 bd.simage.generation = texD->generation;
5801 case QRhiShaderResourceBinding::BufferLoad:
5802 case QRhiShaderResourceBinding::BufferStore:
5803 case QRhiShaderResourceBinding::BufferLoadStore:
5806 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
5808 if (bufD->m_type == QRhiBuffer::Dynamic)
5809 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
5811 bufD->lastActiveFrameSlot = currentFrameSlot;
5813 if (b->type == QRhiShaderResourceBinding::BufferLoad)
5815 else if (b->type == QRhiShaderResourceBinding::BufferStore)
5819 trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
5821 QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
5823 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
5824 rewriteDescSet =
true;
5825 bd.sbuf.id = bufD->m_id;
5826 bd.sbuf.generation = bufD->generation;
5838 updateShaderResourceBindings(srb);
5842 const bool forceRebind = cbD->currentDescSetSlot != currentFrameSlot || srbD->hasDynamicOffset;
5844 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
5846 if (forceRebind || rewriteDescSet || srbChanged || cbD->currentSrbGeneration != srbD->generation) {
5847 QVarLengthArray<uint32_t, 4> dynOfs;
5853 for (
const QRhiShaderResourceBinding &binding : std::as_const(srbD->sortedBindings)) {
5854 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding);
5855 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
5856 uint32_t offset = 0;
5857 for (
int i = 0; i < dynamicOffsetCount; ++i) {
5858 const QRhiCommandBuffer::DynamicOffset &bindingOffsetPair(dynamicOffsets[i]);
5859 if (bindingOffsetPair.first == b->binding) {
5860 offset = bindingOffsetPair.second;
5864 dynOfs.append(offset);
5870 df->vkCmdBindDescriptorSets(cbD->activeSecondaryCbStack.last(),
5871 gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
5872 gfxPsD ? gfxPsD->layout : compPsD->layout,
5873 0, 1, &srbD->descSets[currentFrameSlot],
5874 uint32_t(dynOfs.size()),
5875 dynOfs.size() ? dynOfs.constData() :
nullptr);
5879 cmd.args.bindDescriptorSet.bindPoint = gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS
5880 : VK_PIPELINE_BIND_POINT_COMPUTE;
5881 cmd.args.bindDescriptorSet.pipelineLayout = gfxPsD ? gfxPsD->layout : compPsD->layout;
5882 cmd.args.bindDescriptorSet.descSet = srbD->descSets[currentFrameSlot];
5883 cmd.args.bindDescriptorSet.dynamicOffsetCount = dynOfs.size();
5884 cmd.args.bindDescriptorSet.dynamicOffsetIndex = cbD->pools.dynamicOffset.size();
5885 cbD->pools.dynamicOffset.append(dynOfs.constData(), dynOfs.size());
5889 cbD->currentGraphicsSrb = srb;
5890 cbD->currentComputeSrb =
nullptr;
5892 cbD->currentGraphicsSrb =
nullptr;
5893 cbD->currentComputeSrb = srb;
5895 cbD->currentSrbGeneration = srbD->generation;
5896 cbD->currentDescSetSlot = currentFrameSlot;
5899 srbD->lastActiveFrameSlot = currentFrameSlot;
5903 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
5904 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
5910 bool needsBindVBuf =
false;
5911 for (
int i = 0; i < bindingCount; ++i) {
5912 const int inputSlot = startBinding + i;
5914 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
5915 bufD->lastActiveFrameSlot = currentFrameSlot;
5916 if (bufD->m_type == QRhiBuffer::Dynamic)
5917 executeBufferHostWritesForSlot(bufD, currentFrameSlot);
5919 const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
5920 if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
5921 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
5923 needsBindVBuf =
true;
5924 cbD->currentVertexBuffers[inputSlot] = vkvertexbuf;
5925 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
5929 if (needsBindVBuf) {
5930 QVarLengthArray<VkBuffer, 4> bufs;
5931 QVarLengthArray<VkDeviceSize, 4> ofs;
5932 for (
int i = 0; i < bindingCount; ++i) {
5934 const int slot = bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
5935 bufs.append(bufD->buffers[slot]);
5936 ofs.append(bindings[i].second);
5943 df->vkCmdBindVertexBuffers(cbD->activeSecondaryCbStack.last(), uint32_t(startBinding),
5944 uint32_t(bufs.size()), bufs.constData(), ofs.constData());
5948 cmd.args.bindVertexBuffer.startBinding = startBinding;
5949 cmd.args.bindVertexBuffer.count = bufs.size();
5950 cmd.args.bindVertexBuffer.vertexBufferIndex = cbD->pools.vertexBuffer.size();
5951 cbD->pools.vertexBuffer.append(bufs.constData(), bufs.size());
5952 cmd.args.bindVertexBuffer.vertexBufferOffsetIndex = cbD->pools.vertexBufferOffset.size();
5953 cbD->pools.vertexBufferOffset.append(ofs.constData(), ofs.size());
5959 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
5960 ibufD->lastActiveFrameSlot = currentFrameSlot;
5961 if (ibufD->m_type == QRhiBuffer::Dynamic)
5962 executeBufferHostWritesForSlot(ibufD, currentFrameSlot);
5964 const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
5965 const VkBuffer vkindexbuf = ibufD->buffers[slot];
5966 const VkIndexType type = indexFormat == QRhiCommandBuffer::IndexUInt16 ? VK_INDEX_TYPE_UINT16
5967 : VK_INDEX_TYPE_UINT32;
5969 if (cbD->currentIndexBuffer != vkindexbuf
5970 || cbD->currentIndexOffset != indexOffset
5971 || cbD->currentIndexFormat != type)
5973 cbD->currentIndexBuffer = vkindexbuf;
5974 cbD->currentIndexOffset = indexOffset;
5975 cbD->currentIndexFormat = type;
5978 df->vkCmdBindIndexBuffer(cbD->activeSecondaryCbStack.last(), vkindexbuf, indexOffset, type);
5982 cmd.args.bindIndexBuffer.buf = vkindexbuf;
5983 cmd.args.bindIndexBuffer.ofs = indexOffset;
5984 cmd.args.bindIndexBuffer.type = type;
5998 const QSize outputSize = cbD->currentTarget->pixelSize();
6002 if (!qrhi_toTopLeftRenderTargetRect<
UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
6006 VkViewport *vp = &cmd.args.setViewport.viewport;
6011 vp->minDepth = viewport.minDepth();
6012 vp->maxDepth = viewport.maxDepth();
6015 df->vkCmdSetViewport(cbD->activeSecondaryCbStack.last(), 0, 1, vp);
6016 cbD->commands.unget();
6021 if (cbD->currentGraphicsPipeline
6022 && !
QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
6025 VkRect2D *s = &cmd.args.setScissor.scissor;
6026 qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
6027 s->offset.x = int32_t(x);
6028 s->offset.y = int32_t(y);
6029 s->extent.width = uint32_t(w);
6030 s->extent.height = uint32_t(h);
6032 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6033 cbD->commands.unget();
6044 Q_ASSERT(!cbD->currentGraphicsPipeline
6045 ||
QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)
6046 ->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
6047 const QSize outputSize = cbD->currentTarget->pixelSize();
6051 if (!qrhi_toTopLeftRenderTargetRect<
Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
6055 VkRect2D *s = &cmd.args.setScissor.scissor;
6058 s->extent.width = uint32_t(w);
6059 s->extent.height = uint32_t(h);
6062 df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s);
6063 cbD->commands.unget();
6075 float constants[] = {
float(c.redF()),
float(c.greenF()),
float(c.blueF()),
float(c.alphaF()) };
6076 df->vkCmdSetBlendConstants(cbD->activeSecondaryCbStack.last(), constants);
6080 cmd.args.setBlendConstants.c[0] = c.redF();
6081 cmd.args.setBlendConstants.c[1] = c.greenF();
6082 cmd.args.setBlendConstants.c[2] = c.blueF();
6083 cmd.args.setBlendConstants.c[3] = c.alphaF();
6093 df->vkCmdSetStencilReference(cbD->activeSecondaryCbStack.last(), VK_STENCIL_FRONT_AND_BACK, refValue);
6097 cmd.args.setStencilRef.ref = refValue;
6103#ifdef VK_KHR_fragment_shading_rate
6104 if (!vkCmdSetFragmentShadingRateKHR)
6107 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6108 Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
6109 Q_ASSERT(!cbD->currentGraphicsPipeline || QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate));
6111 VkFragmentShadingRateCombinerOpKHR ops[2] = {
6112 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR,
6113 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR
6115 VkExtent2D size = { uint32_t(coarsePixelSize.width()), uint32_t(coarsePixelSize.height()) };
6116 if (cbD->passUsesSecondaryCb) {
6117 vkCmdSetFragmentShadingRateKHR(cbD->activeSecondaryCbStack.last(), &size, ops);
6119 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6120 cmd.cmd = QVkCommandBuffer::Command::SetShadingRate;
6121 cmd.args.setShadingRate.w = size.width;
6122 cmd.args.setShadingRate.h = size.height;
6124 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
6125 cbD->hasShadingRateSet =
true;
6128 Q_UNUSED(coarsePixelSize);
6133 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
6139 df->vkCmdDraw(cbD->activeSecondaryCbStack.last(), vertexCount, instanceCount, firstVertex, firstInstance);
6143 cmd.args.draw.vertexCount = vertexCount;
6144 cmd.args.draw.instanceCount = instanceCount;
6145 cmd.args.draw.firstVertex = firstVertex;
6146 cmd.args.draw.firstInstance = firstInstance;
6151 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
6157 df->vkCmdDrawIndexed(cbD->activeSecondaryCbStack.last(), indexCount, instanceCount,
6158 firstIndex, vertexOffset, firstInstance);
6162 cmd.args.drawIndexed.indexCount = indexCount;
6163 cmd.args.drawIndexed.instanceCount = instanceCount;
6164 cmd.args.drawIndexed.firstIndex = firstIndex;
6165 cmd.args.drawIndexed.vertexOffset = vertexOffset;
6166 cmd.args.drawIndexed.firstInstance = firstInstance;
6172#ifdef VK_EXT_debug_utils
6173 if (!debugMarkers || !caps.debugUtils)
6176 VkDebugUtilsLabelEXT label = {};
6177 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6179 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6180 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6181 label.pLabelName = name.constData();
6182 vkCmdBeginDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6184 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6185 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerBegin;
6186 cmd.args.debugMarkerBegin.label = label;
6187 cmd.args.debugMarkerBegin.labelNameIndex = cbD->pools.debugMarkerData.size();
6188 cbD->pools.debugMarkerData.append(name);
6198#ifdef VK_EXT_debug_utils
6199 if (!debugMarkers || !caps.debugUtils)
6202 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6203 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6204 vkCmdEndDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last());
6206 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6207 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerEnd;
6216#ifdef VK_EXT_debug_utils
6217 if (!debugMarkers || !caps.debugUtils)
6220 VkDebugUtilsLabelEXT label = {};
6221 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
6223 QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
6224 if (cbD->recordingPass != QVkCommandBuffer::NoPass && cbD->passUsesSecondaryCb) {
6225 label.pLabelName = msg.constData();
6226 vkCmdInsertDebugUtilsLabelEXT(cbD->activeSecondaryCbStack.last(), &label);
6228 QVkCommandBuffer::Command &cmd(cbD->commands.get());
6229 cmd.cmd = QVkCommandBuffer::Command::DebugMarkerInsert;
6230 cmd.args.debugMarkerInsert.label = label;
6231 cmd.args.debugMarkerInsert.labelNameIndex = cbD->pools.debugMarkerData.size();
6232 cbD->pools.debugMarkerData.append(msg);
6242 return QRHI_RES(QVkCommandBuffer, cb)->nativeHandles();
6247 Q_ASSERT(cbD->currentTarget);
6250 switch (cbD->currentTarget->resourceType()) {
6251 case QRhiResource::SwapChainRenderTarget:
6254 case QRhiResource::TextureRenderTarget:
6286 qWarning(
"beginExternal() within a pass is only supported with secondary command buffers. "
6287 "This can be enabled by passing QRhiCommandBuffer::ExternalContent to beginPass().");
6291 VkCommandBuffer secondaryCb = cbD->activeSecondaryCbStack.last();
6292 cbD->activeSecondaryCbStack.removeLast();
6293 endAndEnqueueSecondaryCommandBuffer(secondaryCb, cbD);
6295 VkCommandBuffer extCb = startSecondaryCommandBuffer(maybeRenderTargetData(cbD));
6297 cbD->activeSecondaryCbStack.append(extCb);
6309 VkCommandBuffer extCb = cbD->activeSecondaryCbStack.last();
6310 cbD->activeSecondaryCbStack.removeLast();
6311 endAndEnqueueSecondaryCommandBuffer(extCb, cbD);
6312 cbD->activeSecondaryCbStack.append(startSecondaryCommandBuffer(maybeRenderTargetData(cbD)));
6326 if (!debugMarkers || name.isEmpty())
6329 QByteArray decoratedName = name;
6331 decoratedName +=
'/';
6332 decoratedName += QByteArray::number(slot);
6334 vmaSetAllocationName(toVmaAllocator(allocator), toVmaAllocation(allocation), decoratedName.constData());
6339#ifdef VK_EXT_debug_utils
6340 if (!debugMarkers || !caps.debugUtils || name.isEmpty())
6343 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
6344 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
6345 nameInfo.objectType = type;
6346 nameInfo.objectHandle = object;
6347 QByteArray decoratedName = name;
6349 decoratedName +=
'/';
6350 decoratedName += QByteArray::number(slot);
6352 nameInfo.pObjectName = decoratedName.constData();
6353 vkSetDebugUtilsObjectNameEXT(dev, &nameInfo);
6365 if (usage.testFlag(QRhiBuffer::VertexBuffer))
6366 u |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
6367 if (usage.testFlag(QRhiBuffer::IndexBuffer))
6368 u |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
6369 if (usage.testFlag(QRhiBuffer::UniformBuffer))
6370 u |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
6371 if (usage.testFlag(QRhiBuffer::StorageBuffer))
6372 u |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
6373 return VkBufferUsageFlagBits(u);
6379 case QRhiSampler::Nearest:
6380 return VK_FILTER_NEAREST;
6381 case QRhiSampler::Linear:
6382 return VK_FILTER_LINEAR;
6384 Q_UNREACHABLE_RETURN(VK_FILTER_NEAREST);
6391 case QRhiSampler::None:
6392 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6393 case QRhiSampler::Nearest:
6394 return VK_SAMPLER_MIPMAP_MODE_NEAREST;
6395 case QRhiSampler::Linear:
6396 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
6398 Q_UNREACHABLE_RETURN(VK_SAMPLER_MIPMAP_MODE_NEAREST);
6405 case QRhiSampler::Repeat:
6406 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
6407 case QRhiSampler::ClampToEdge:
6408 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
6409 case QRhiSampler::Mirror:
6410 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
6412 Q_UNREACHABLE_RETURN(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
6419 case QRhiShaderStage::Vertex:
6420 return VK_SHADER_STAGE_VERTEX_BIT;
6421 case QRhiShaderStage::TessellationControl:
6422 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6423 case QRhiShaderStage::TessellationEvaluation:
6424 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6425 case QRhiShaderStage::Fragment:
6426 return VK_SHADER_STAGE_FRAGMENT_BIT;
6427 case QRhiShaderStage::Compute:
6428 return VK_SHADER_STAGE_COMPUTE_BIT;
6429 case QRhiShaderStage::Geometry:
6430 return VK_SHADER_STAGE_GEOMETRY_BIT;
6432 Q_UNREACHABLE_RETURN(VK_SHADER_STAGE_VERTEX_BIT);
6439 case QRhiVertexInputAttribute::Float4:
6440 return VK_FORMAT_R32G32B32A32_SFLOAT;
6441 case QRhiVertexInputAttribute::Float3:
6442 return VK_FORMAT_R32G32B32_SFLOAT;
6443 case QRhiVertexInputAttribute::Float2:
6444 return VK_FORMAT_R32G32_SFLOAT;
6445 case QRhiVertexInputAttribute::Float:
6446 return VK_FORMAT_R32_SFLOAT;
6447 case QRhiVertexInputAttribute::UNormByte4:
6448 return VK_FORMAT_R8G8B8A8_UNORM;
6449 case QRhiVertexInputAttribute::UNormByte2:
6450 return VK_FORMAT_R8G8_UNORM;
6451 case QRhiVertexInputAttribute::UNormByte:
6452 return VK_FORMAT_R8_UNORM;
6453 case QRhiVertexInputAttribute::UInt4:
6454 return VK_FORMAT_R32G32B32A32_UINT;
6455 case QRhiVertexInputAttribute::UInt3:
6456 return VK_FORMAT_R32G32B32_UINT;
6457 case QRhiVertexInputAttribute::UInt2:
6458 return VK_FORMAT_R32G32_UINT;
6459 case QRhiVertexInputAttribute::UInt:
6460 return VK_FORMAT_R32_UINT;
6461 case QRhiVertexInputAttribute::SInt4:
6462 return VK_FORMAT_R32G32B32A32_SINT;
6463 case QRhiVertexInputAttribute::SInt3:
6464 return VK_FORMAT_R32G32B32_SINT;
6465 case QRhiVertexInputAttribute::SInt2:
6466 return VK_FORMAT_R32G32_SINT;
6467 case QRhiVertexInputAttribute::SInt:
6468 return VK_FORMAT_R32_SINT;
6469 case QRhiVertexInputAttribute::Half4:
6470 return VK_FORMAT_R16G16B16A16_SFLOAT;
6471 case QRhiVertexInputAttribute::Half3:
6472 return VK_FORMAT_R16G16B16_SFLOAT;
6473 case QRhiVertexInputAttribute::Half2:
6474 return VK_FORMAT_R16G16_SFLOAT;
6475 case QRhiVertexInputAttribute::Half:
6476 return VK_FORMAT_R16_SFLOAT;
6477 case QRhiVertexInputAttribute::UShort4:
6478 return VK_FORMAT_R16G16B16A16_UINT;
6479 case QRhiVertexInputAttribute::UShort3:
6480 return VK_FORMAT_R16G16B16_UINT;
6481 case QRhiVertexInputAttribute::UShort2:
6482 return VK_FORMAT_R16G16_UINT;
6483 case QRhiVertexInputAttribute::UShort:
6484 return VK_FORMAT_R16_UINT;
6485 case QRhiVertexInputAttribute::SShort4:
6486 return VK_FORMAT_R16G16B16A16_SINT;
6487 case QRhiVertexInputAttribute::SShort3:
6488 return VK_FORMAT_R16G16B16_SINT;
6489 case QRhiVertexInputAttribute::SShort2:
6490 return VK_FORMAT_R16G16_SINT;
6491 case QRhiVertexInputAttribute::SShort:
6492 return VK_FORMAT_R16_SINT;
6494 Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
6501 case QRhiGraphicsPipeline::Triangles:
6502 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6503 case QRhiGraphicsPipeline::TriangleStrip:
6504 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
6505 case QRhiGraphicsPipeline::TriangleFan:
6506 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
6507 case QRhiGraphicsPipeline::Lines:
6508 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
6509 case QRhiGraphicsPipeline::LineStrip:
6510 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
6511 case QRhiGraphicsPipeline::Points:
6512 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
6513 case QRhiGraphicsPipeline::Patches:
6514 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
6516 Q_UNREACHABLE_RETURN(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
6523 case QRhiGraphicsPipeline::None:
6524 return VK_CULL_MODE_NONE;
6525 case QRhiGraphicsPipeline::Front:
6526 return VK_CULL_MODE_FRONT_BIT;
6527 case QRhiGraphicsPipeline::Back:
6528 return VK_CULL_MODE_BACK_BIT;
6530 Q_UNREACHABLE_RETURN(VK_CULL_MODE_NONE);
6537 case QRhiGraphicsPipeline::CCW:
6538 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
6539 case QRhiGraphicsPipeline::CW:
6540 return VK_FRONT_FACE_CLOCKWISE;
6542 Q_UNREACHABLE_RETURN(VK_FRONT_FACE_COUNTER_CLOCKWISE);
6549 if (c.testFlag(QRhiGraphicsPipeline::R))
6550 f |= VK_COLOR_COMPONENT_R_BIT;
6551 if (c.testFlag(QRhiGraphicsPipeline::G))
6552 f |= VK_COLOR_COMPONENT_G_BIT;
6553 if (c.testFlag(QRhiGraphicsPipeline::B))
6554 f |= VK_COLOR_COMPONENT_B_BIT;
6555 if (c.testFlag(QRhiGraphicsPipeline::A))
6556 f |= VK_COLOR_COMPONENT_A_BIT;
6557 return VkColorComponentFlags(f);
6563 case QRhiGraphicsPipeline::Zero:
6564 return VK_BLEND_FACTOR_ZERO;
6565 case QRhiGraphicsPipeline::One:
6566 return VK_BLEND_FACTOR_ONE;
6567 case QRhiGraphicsPipeline::SrcColor:
6568 return VK_BLEND_FACTOR_SRC_COLOR;
6569 case QRhiGraphicsPipeline::OneMinusSrcColor:
6570 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
6571 case QRhiGraphicsPipeline::DstColor:
6572 return VK_BLEND_FACTOR_DST_COLOR;
6573 case QRhiGraphicsPipeline::OneMinusDstColor:
6574 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
6575 case QRhiGraphicsPipeline::SrcAlpha:
6576 return VK_BLEND_FACTOR_SRC_ALPHA;
6577 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6578 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
6579 case QRhiGraphicsPipeline::DstAlpha:
6580 return VK_BLEND_FACTOR_DST_ALPHA;
6581 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6582 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
6583 case QRhiGraphicsPipeline::ConstantColor:
6584 return VK_BLEND_FACTOR_CONSTANT_COLOR;
6585 case QRhiGraphicsPipeline::OneMinusConstantColor:
6586 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
6587 case QRhiGraphicsPipeline::ConstantAlpha:
6588 return VK_BLEND_FACTOR_CONSTANT_ALPHA;
6589 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6590 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
6591 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6592 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
6593 case QRhiGraphicsPipeline::Src1Color:
6594 return VK_BLEND_FACTOR_SRC1_COLOR;
6595 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6596 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
6597 case QRhiGraphicsPipeline::Src1Alpha:
6598 return VK_BLEND_FACTOR_SRC1_ALPHA;
6599 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6600 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
6602 Q_UNREACHABLE_RETURN(VK_BLEND_FACTOR_ZERO);
6609 case QRhiGraphicsPipeline::Add:
6610 return VK_BLEND_OP_ADD;
6611 case QRhiGraphicsPipeline::Subtract:
6612 return VK_BLEND_OP_SUBTRACT;
6613 case QRhiGraphicsPipeline::ReverseSubtract:
6614 return VK_BLEND_OP_REVERSE_SUBTRACT;
6615 case QRhiGraphicsPipeline::Min:
6616 return VK_BLEND_OP_MIN;
6617 case QRhiGraphicsPipeline::Max:
6618 return VK_BLEND_OP_MAX;
6620 Q_UNREACHABLE_RETURN(VK_BLEND_OP_ADD);
6627 case QRhiGraphicsPipeline::Never:
6628 return VK_COMPARE_OP_NEVER;
6629 case QRhiGraphicsPipeline::Less:
6630 return VK_COMPARE_OP_LESS;
6631 case QRhiGraphicsPipeline::Equal:
6632 return VK_COMPARE_OP_EQUAL;
6633 case QRhiGraphicsPipeline::LessOrEqual:
6634 return VK_COMPARE_OP_LESS_OR_EQUAL;
6635 case QRhiGraphicsPipeline::Greater:
6636 return VK_COMPARE_OP_GREATER;
6637 case QRhiGraphicsPipeline::NotEqual:
6638 return VK_COMPARE_OP_NOT_EQUAL;
6639 case QRhiGraphicsPipeline::GreaterOrEqual:
6640 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6641 case QRhiGraphicsPipeline::Always:
6642 return VK_COMPARE_OP_ALWAYS;
6644 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_ALWAYS);
6651 case QRhiGraphicsPipeline::StencilZero:
6652 return VK_STENCIL_OP_ZERO;
6653 case QRhiGraphicsPipeline::Keep:
6654 return VK_STENCIL_OP_KEEP;
6655 case QRhiGraphicsPipeline::Replace:
6656 return VK_STENCIL_OP_REPLACE;
6657 case QRhiGraphicsPipeline::IncrementAndClamp:
6658 return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
6659 case QRhiGraphicsPipeline::DecrementAndClamp:
6660 return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
6661 case QRhiGraphicsPipeline::Invert:
6662 return VK_STENCIL_OP_INVERT;
6663 case QRhiGraphicsPipeline::IncrementAndWrap:
6664 return VK_STENCIL_OP_INCREMENT_AND_WRAP;
6665 case QRhiGraphicsPipeline::DecrementAndWrap:
6666 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
6668 Q_UNREACHABLE_RETURN(VK_STENCIL_OP_KEEP);
6675 case QRhiGraphicsPipeline::Fill:
6676 return VK_POLYGON_MODE_FILL;
6677 case QRhiGraphicsPipeline::Line:
6678 return VK_POLYGON_MODE_LINE;
6680 Q_UNREACHABLE_RETURN(VK_POLYGON_MODE_FILL);
6686 dst->failOp = toVkStencilOp(src.failOp);
6687 dst->passOp = toVkStencilOp(src.passOp);
6688 dst->depthFailOp = toVkStencilOp(src.depthFailOp);
6689 dst->compareOp = toVkCompareOp(src.compareOp);
6695 case QRhiShaderResourceBinding::UniformBuffer:
6696 return b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
6697 : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
6699 case QRhiShaderResourceBinding::SampledTexture:
6700 return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6702 case QRhiShaderResourceBinding::Texture:
6703 return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
6705 case QRhiShaderResourceBinding::Sampler:
6706 return VK_DESCRIPTOR_TYPE_SAMPLER;
6708 case QRhiShaderResourceBinding::ImageLoad:
6709 case QRhiShaderResourceBinding::ImageStore:
6710 case QRhiShaderResourceBinding::ImageLoadStore:
6711 return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
6713 case QRhiShaderResourceBinding::BufferLoad:
6714 case QRhiShaderResourceBinding::BufferStore:
6715 case QRhiShaderResourceBinding::BufferLoadStore:
6716 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
6719 Q_UNREACHABLE_RETURN(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
6726 if (stage.testFlag(QRhiShaderResourceBinding::VertexStage))
6727 s |= VK_SHADER_STAGE_VERTEX_BIT;
6728 if (stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
6729 s |= VK_SHADER_STAGE_FRAGMENT_BIT;
6730 if (stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
6731 s |= VK_SHADER_STAGE_COMPUTE_BIT;
6732 if (stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage))
6733 s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
6734 if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
6735 s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
6736 if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
6737 s |= VK_SHADER_STAGE_GEOMETRY_BIT;
6738 return VkShaderStageFlags(s);
6744 case QRhiSampler::Never:
6745 return VK_COMPARE_OP_NEVER;
6746 case QRhiSampler::Less:
6747 return VK_COMPARE_OP_LESS;
6748 case QRhiSampler::Equal:
6749 return VK_COMPARE_OP_EQUAL;
6750 case QRhiSampler::LessOrEqual:
6751 return VK_COMPARE_OP_LESS_OR_EQUAL;
6752 case QRhiSampler::Greater:
6753 return VK_COMPARE_OP_GREATER;
6754 case QRhiSampler::NotEqual:
6755 return VK_COMPARE_OP_NOT_EQUAL;
6756 case QRhiSampler::GreaterOrEqual:
6757 return VK_COMPARE_OP_GREATER_OR_EQUAL;
6758 case QRhiSampler::Always:
6759 return VK_COMPARE_OP_ALWAYS;
6761 Q_UNREACHABLE_RETURN(VK_COMPARE_OP_NEVER);
6769 buffers[i] = stagingBuffers[i] = VK_NULL_HANDLE;
6789 e.buffer.buffers[i] = buffers[i];
6791 e.buffer.stagingBuffers[i] = stagingBuffers[i];
6794 buffers[i] = VK_NULL_HANDLE;
6796 stagingBuffers[i] = VK_NULL_HANDLE;
6798 pendingDynamicUpdates[i].clear();
6806 rhiD->releaseQueue.append(e);
6807 rhiD->unregisterResource(
this);
6816 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
6817 qWarning(
"StorageBuffer cannot be combined with Dynamic");
6821 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
6823 VkBufferCreateInfo bufferInfo = {};
6824 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
6825 bufferInfo.size = nonZeroSize;
6826 bufferInfo.usage = toVkBufferUsage(m_usage);
6828 VmaAllocationCreateInfo allocInfo = {};
6830 if (m_type == Dynamic) {
6835 allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
6838 allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
6840 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
6841 bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
6845 VkResult err = VK_SUCCESS;
6847 buffers[i] = VK_NULL_HANDLE;
6849 usageState[i].access = usageState[i].stage = 0;
6850 if (i == 0 || m_type == Dynamic) {
6851 VmaAllocation allocation;
6852 err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation,
nullptr);
6853 if (err != VK_SUCCESS)
6856 rhiD->setAllocationName(allocation, m_objectName, m_type == Dynamic ? i : -1);
6857 rhiD->setObjectName(uint64_t(buffers[i]), VK_OBJECT_TYPE_BUFFER, m_objectName,
6858 m_type == Dynamic ? i : -1);
6862 if (err != VK_SUCCESS) {
6863 qWarning(
"Failed to create buffer of size %u: %d", nonZeroSize, err);
6864 rhiD->printExtraErrorInfo(err);
6870 rhiD->registerResource(
this);
6876 if (m_type == Dynamic) {
6882 b.objects[i] = &buffers[i];
6887 return { { &buffers[0] }, 1 };
6897 Q_ASSERT(m_type == Dynamic);
6899 Q_ASSERT(rhiD->inFrame);
6900 const int slot = rhiD->currentFrameSlot;
6902 VmaAllocation a = toVmaAllocation(allocations[slot]);
6903 VkResult err = vmaMapMemory(toVmaAllocator(rhiD->allocator), a, &p);
6904 if (err != VK_SUCCESS) {
6905 qWarning(
"Failed to map buffer: %d", err);
6908 return static_cast<
char *>(p);
6914 const int slot = rhiD->currentFrameSlot;
6915 VmaAllocation a = toVmaAllocation(allocations[slot]);
6916 vmaFlushAllocation(toVmaAllocator(rhiD->allocator), a, 0, m_size);
6917 vmaUnmapMemory(toVmaAllocator(rhiD->allocator), a);
6921 int sampleCount, Flags flags,
6922 QRhiTexture::Format backingFormatHint)
6935 if (!memory && !backingTexture)
6942 e.renderBuffer.memory = memory;
6943 e.renderBuffer.image = image;
6944 e.renderBuffer.imageView = imageView;
6946 memory = VK_NULL_HANDLE;
6947 image = VK_NULL_HANDLE;
6948 imageView = VK_NULL_HANDLE;
6958 rhiD->releaseQueue.append(e);
6959 rhiD->unregisterResource(
this);
6965 if (memory || backingTexture)
6968 if (m_pixelSize.isEmpty())
6972 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
6975 case QRhiRenderBuffer::Color:
6978 backingTexture =
QRHI_RES(QVkTexture, rhiD->createTexture(backingFormat(),
6983 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
6985 backingTexture->setPixelSize(m_pixelSize);
6986 backingTexture->setSampleCount(m_sampleCount);
6988 backingTexture->setName(m_objectName);
6991 vkformat = backingTexture->vkformat;
6994 case QRhiRenderBuffer::DepthStencil:
6995 vkformat = rhiD->optimalDepthStencilFormat();
6996 if (!rhiD->createTransientImage(vkformat,
6998 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
6999 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
7008 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7017 rhiD->registerResource(
this);
7023 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
7024 return m_backingFormatHint;
7026 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
7030 int arraySize,
int sampleCount, Flags flags)
7034 stagingBuffers[i] = VK_NULL_HANDLE;
7037 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
7038 perLevelImageViews[i] = VK_NULL_HANDLE;
7055 e.texture.image = owns ? image : VK_NULL_HANDLE;
7056 e.texture.imageView = imageView;
7060 e.texture.stagingBuffers[i] = stagingBuffers[i];
7063 stagingBuffers[i] = VK_NULL_HANDLE;
7067 for (
int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
7068 e.texture.extraImageViews[i] = perLevelImageViews[i];
7069 perLevelImageViews[i] = VK_NULL_HANDLE;
7072 image = VK_NULL_HANDLE;
7073 imageView = VK_NULL_HANDLE;
7078 rhiD->releaseQueue.append(e);
7079 rhiD->unregisterResource(
this);
7089 vkformat = toVkTextureFormat(m_format, m_flags);
7090 if (m_writeViewFormat.format != UnknownFormat)
7091 viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
7093 viewFormat = vkformat;
7094 if (m_readViewFormat.format != UnknownFormat)
7095 viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
7097 viewFormatForSampling = vkformat;
7099 VkFormatProperties props;
7100 rhiD->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
7101 const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
7102 if (!canSampleOptimal) {
7103 qWarning(
"Texture sampling with optimal tiling for format %d not supported", vkformat);
7107 const bool isCube = m_flags.testFlag(CubeMap);
7108 const bool isArray = m_flags.testFlag(TextureArray);
7109 const bool is3D = m_flags.testFlag(ThreeDimensional);
7110 const bool is1D = m_flags.testFlag(OneDimensional);
7111 const bool hasMipMaps = m_flags.testFlag(MipMapped);
7113 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
7114 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
7116 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
7117 const int maxLevels = QRhi::MAX_MIP_LEVELS;
7118 if (mipLevelCount > maxLevels) {
7119 qWarning(
"Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
7120 mipLevelCount = maxLevels;
7122 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
7123 if (samples > VK_SAMPLE_COUNT_1_BIT) {
7125 qWarning(
"Cubemap texture cannot be multisample");
7129 qWarning(
"3D texture cannot be multisample");
7133 qWarning(
"Multisample texture cannot have mipmaps");
7137 if (isCube && is3D) {
7138 qWarning(
"Texture cannot be both cube and 3D");
7141 if (isArray && is3D) {
7142 qWarning(
"Texture cannot be both array and 3D");
7145 if (isCube && is1D) {
7146 qWarning(
"Texture cannot be both cube and 1D");
7150 qWarning(
"Texture cannot be both 1D and 3D");
7153 if (m_depth > 1 && !is3D) {
7154 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
7157 if (m_arraySize > 0 && !isArray) {
7158 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
7161 if (m_arraySize < 1 && isArray) {
7162 qWarning(
"Texture is an array but array size is %d", m_arraySize);
7166 usageState.layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7167 usageState.access = 0;
7168 usageState.stage = 0;
7171 *adjustedSize = size;
7180 const auto aspectMask = aspectMaskForTextureFormat(m_format);
7181 const bool isCube = m_flags.testFlag(CubeMap);
7182 const bool isArray = m_flags.testFlag(TextureArray);
7183 const bool is3D = m_flags.testFlag(ThreeDimensional);
7184 const bool is1D = m_flags.testFlag(OneDimensional);
7186 VkImageViewCreateInfo viewInfo = {};
7187 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7188 viewInfo.image = image;
7189 viewInfo.viewType = isCube
7190 ? VK_IMAGE_VIEW_TYPE_CUBE
7191 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7192 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7193 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7194 viewInfo.format = viewFormatForSampling;
7195 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7196 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7197 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7198 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7199 viewInfo.subresourceRange.aspectMask = aspectMask;
7202 viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
7203 viewInfo.subresourceRange.levelCount = mipLevelCount;
7204 if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
7205 viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
7206 viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
7208 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7211 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &imageView);
7212 if (err != VK_SUCCESS) {
7213 qWarning(
"Failed to create image view: %d", err);
7226 if (!prepareCreate(&size))
7230 const bool isRenderTarget = m_flags.testFlag(QRhiTexture::RenderTarget);
7231 const bool isDepth = isDepthTextureFormat(m_format);
7232 const bool isCube = m_flags.testFlag(CubeMap);
7233 const bool isArray = m_flags.testFlag(TextureArray);
7234 const bool is3D = m_flags.testFlag(ThreeDimensional);
7235 const bool is1D = m_flags.testFlag(OneDimensional);
7237 VkImageCreateInfo imageInfo = {};
7238 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7239 imageInfo.flags = 0;
7241 imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
7243 if (is3D && isRenderTarget) {
7249 if (!rhiD->caps.texture3DSliceAs2D)
7250 qWarning(
"QRhiVulkan: Rendering to 3D texture slice may not be functional without API 1.1 on the VkInstance");
7251#ifdef VK_VERSION_1_1
7252 imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
7254 imageInfo.flags |= 0x00000020;
7258 imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
7259 imageInfo.format = vkformat;
7260 imageInfo.extent.width = uint32_t(size.width());
7261 imageInfo.extent.height = uint32_t(size.height());
7262 imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
7263 imageInfo.mipLevels = mipLevelCount;
7264 imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7265 imageInfo.samples = samples;
7266 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
7267 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
7269 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
7270 if (isRenderTarget) {
7272 imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
7274 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
7276 if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
7277 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7278 if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
7279 imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
7280 if (m_flags.testFlag(QRhiTexture::UsedWithLoadStore))
7281 imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
7282#ifdef VK_KHR_fragment_shading_rate
7283 if (m_flags.testFlag(QRhiTexture::UsedAsShadingRateMap) && rhiD->caps.imageBasedShadingRate)
7284 imageInfo.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
7287 VmaAllocationCreateInfo allocInfo = {};
7288 allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
7290 VmaAllocation allocation;
7291 VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation,
nullptr);
7292 if (err != VK_SUCCESS) {
7293 qWarning(
"Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
7294 imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
7295 int(imageInfo.format),
7296 imageInfo.mipLevels,
7297 imageInfo.arrayLayers,
7298 int(imageInfo.samples),
7300 rhiD->printExtraErrorInfo(err);
7304 rhiD->setAllocationName(allocation, m_objectName);
7309 rhiD->setObjectName(uint64_t(image), VK_OBJECT_TYPE_IMAGE, m_objectName);
7312 rhiD->registerResource(
this);
7318 VkImage img = VkImage(src.object);
7322 if (!prepareCreate())
7330 usageState.layout = VkImageLayout(src.layout);
7334 rhiD->registerResource(
this);
7340 return {quint64(image), usageState.layout};
7345 usageState.layout = VkImageLayout(layout);
7350 Q_ASSERT(level >= 0 && level <
int(mipLevelCount));
7351 if (perLevelImageViews[level] != VK_NULL_HANDLE)
7352 return perLevelImageViews[level];
7354 const VkImageAspectFlags aspectMask = aspectMaskForTextureFormat(m_format);
7355 const bool isCube = m_flags.testFlag(CubeMap);
7356 const bool isArray = m_flags.testFlag(TextureArray);
7357 const bool is3D = m_flags.testFlag(ThreeDimensional);
7358 const bool is1D = m_flags.testFlag(OneDimensional);
7360 VkImageViewCreateInfo viewInfo = {};
7361 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7362 viewInfo.image = image;
7363 viewInfo.viewType = isCube
7364 ? VK_IMAGE_VIEW_TYPE_CUBE
7365 : (is3D ? VK_IMAGE_VIEW_TYPE_3D
7366 : (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
7367 : (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
7368 viewInfo.format = viewFormat;
7369 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7370 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7371 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7372 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7373 viewInfo.subresourceRange.aspectMask = aspectMask;
7374 viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
7375 viewInfo.subresourceRange.levelCount = 1;
7376 viewInfo.subresourceRange.baseArrayLayer = 0;
7377 viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
7379 VkImageView v = VK_NULL_HANDLE;
7381 VkResult err = rhiD
->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &v);
7382 if (err != VK_SUCCESS) {
7383 qWarning(
"Failed to create image view: %d", err);
7384 return VK_NULL_HANDLE;
7387 perLevelImageViews[level] = v;
7392 AddressMode u, AddressMode v, AddressMode w)
7411 e.sampler.sampler = sampler;
7412 sampler = VK_NULL_HANDLE;
7416 rhiD->releaseQueue.append(e);
7417 rhiD->unregisterResource(
this);
7426 VkSamplerCreateInfo samplerInfo = {};
7427 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
7428 samplerInfo.magFilter = toVkFilter(m_magFilter);
7429 samplerInfo.minFilter = toVkFilter(m_minFilter);
7430 samplerInfo.mipmapMode = toVkMipmapMode(m_mipmapMode);
7431 samplerInfo.addressModeU = toVkAddressMode(m_addressU);
7432 samplerInfo.addressModeV = toVkAddressMode(m_addressV);
7433 samplerInfo.addressModeW = toVkAddressMode(m_addressW);
7434 samplerInfo.maxAnisotropy = 1.0f;
7435 samplerInfo.compareEnable = m_compareOp != Never;
7436 samplerInfo.compareOp = toVkTextureCompareOp(m_compareOp);
7437 samplerInfo.maxLod = m_mipmapMode == None ? 0.25f : 1000.0f;
7440 VkResult err = rhiD->df->vkCreateSampler(rhiD->dev, &samplerInfo,
nullptr, &sampler);
7441 if (err != VK_SUCCESS) {
7442 qWarning(
"Failed to create sampler: %d", err);
7448 rhiD->registerResource(
this);
7455 serializedFormatData.reserve(64);
7469 rp = VK_NULL_HANDLE;
7477 e.renderPass.rp = rp;
7479 rp = VK_NULL_HANDLE;
7483 rhiD->releaseQueue.append(e);
7484 rhiD->unregisterResource(
this);
7490 return a.format == b.format
7491 && a.samples == b.samples
7492 && a.loadOp == b.loadOp
7493 && a.storeOp == b.storeOp
7494 && a.stencilLoadOp == b.stencilLoadOp
7495 && a.stencilStoreOp == b.stencilStoreOp
7496 && a.initialLayout == b.initialLayout
7497 && a.finalLayout == b.finalLayout;
7510 if (attDescs.size() != o->attDescs.size())
7512 if (colorRefs.size() != o->colorRefs.size())
7514 if (resolveRefs.size() != o->resolveRefs.size())
7520 if (multiViewCount != o->multiViewCount)
7525 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7526 const uint32_t attIdx = colorRefs[i].attachment;
7527 if (attIdx != o->colorRefs[i].attachment)
7529 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7534 const uint32_t attIdx = dsRef.attachment;
7535 if (attIdx != o->dsRef.attachment)
7537 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7541 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7542 const uint32_t attIdx = resolveRefs[i].attachment;
7543 if (attIdx != o->resolveRefs[i].attachment)
7545 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7550 const uint32_t attIdx = dsResolveRef.attachment;
7551 if (attIdx != o->dsResolveRef.attachment)
7553 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7558 const uint32_t attIdx = shadingRateRef.attachment;
7559 if (attIdx != o->shadingRateRef.attachment)
7561 if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
7572 serializedFormatData.clear();
7573 auto p = std::back_inserter(serializedFormatData);
7575 *p++ = attDescs.size();
7576 *p++ = colorRefs.size();
7577 *p++ = resolveRefs.size();
7581 *p++ = multiViewCount;
7583 auto serializeAttachmentData = [
this, &p](uint32_t attIdx) {
7584 const bool used = attIdx != VK_ATTACHMENT_UNUSED;
7585 const VkAttachmentDescription *a = used ? &attDescs[attIdx] :
nullptr;
7586 *p++ = used ? a->format : 0;
7587 *p++ = used ? a->samples : 0;
7588 *p++ = used ? a->loadOp : 0;
7589 *p++ = used ? a->storeOp : 0;
7590 *p++ = used ? a->stencilLoadOp : 0;
7591 *p++ = used ? a->stencilStoreOp : 0;
7592 *p++ = used ? a->initialLayout : 0;
7593 *p++ = used ? a->finalLayout : 0;
7596 for (
int i = 0, ie = colorRefs.size(); i != ie; ++i) {
7597 const uint32_t attIdx = colorRefs[i].attachment;
7599 serializeAttachmentData(attIdx);
7603 const uint32_t attIdx = dsRef.attachment;
7605 serializeAttachmentData(attIdx);
7608 for (
int i = 0, ie = resolveRefs.size(); i != ie; ++i) {
7609 const uint32_t attIdx = resolveRefs[i].attachment;
7611 serializeAttachmentData(attIdx);
7615 const uint32_t attIdx = dsResolveRef.attachment;
7617 serializeAttachmentData(attIdx);
7621 const uint32_t attIdx = shadingRateRef.attachment;
7623 serializeAttachmentData(attIdx);
7632 rpD->attDescs = attDescs;
7633 rpD->colorRefs = colorRefs;
7634 rpD->resolveRefs = resolveRefs;
7635 rpD->subpassDeps = subpassDeps;
7639 rpD->multiViewCount = multiViewCount;
7641 rpD->dsResolveRef = dsResolveRef;
7642 rpD->shadingRateRef = shadingRateRef;
7644 VkRenderPassCreateInfo rpInfo;
7645 VkSubpassDescription subpassDesc;
7646 fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
7650 if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
7655#ifdef VK_KHR_create_renderpass2
7656 if (rhiD->caps.renderPass2KHR) {
7658 VkRenderPassCreateInfo2KHR rpInfo2;
7659 RenderPass2SetupHelper rp2Helper(rhiD);
7660 if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount)) {
7664 VkResult err = rhiD->vkCreateRenderPass2KHR(rhiD->dev, &rpInfo2,
nullptr, &rpD->rp);
7665 if (err != VK_SUCCESS) {
7666 qWarning(
"Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
7673 VkResult err = rhiD
->df->vkCreateRenderPass(rhiD->dev, &rpInfo,
nullptr, &rpD->rp);
7674 if (err != VK_SUCCESS) {
7675 qWarning(
"Failed to create renderpass: %d", err);
7682 rhiD->registerResource(rpD);
7688 return serializedFormatData;
7693 nativeHandlesStruct.renderPass = rp;
7694 return &nativeHandlesStruct;
7720 texture =
QRHI_RES(QVkTexture, src);
7752 return d.sampleCount;
7756 const QRhiTextureRenderTargetDescription &desc,
7761 rtv[att] = VK_NULL_HANDLE;
7762 resrtv[att] = VK_NULL_HANDLE;
7780 e.textureRenderTarget.fb = d.fb;
7781 d.fb = VK_NULL_HANDLE;
7784 e.textureRenderTarget.rtv[att] = rtv[att];
7785 e.textureRenderTarget.resrtv[att] = resrtv[att];
7786 rtv[att] = VK_NULL_HANDLE;
7787 resrtv[att] = VK_NULL_HANDLE;
7790 e.textureRenderTarget.dsv = dsv;
7791 dsv = VK_NULL_HANDLE;
7792 e.textureRenderTarget.resdsv = resdsv;
7793 resdsv = VK_NULL_HANDLE;
7795 e.textureRenderTarget.shadingRateMapView = shadingRateMapView;
7796 shadingRateMapView = VK_NULL_HANDLE;
7800 rhiD->releaseQueue.append(e);
7801 rhiD->unregisterResource(
this);
7811 if (!rhiD->createOffscreenRenderPass(rp,
7812 m_desc.cbeginColorAttachments(),
7813 m_desc.cendColorAttachments(),
7814 m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
7815 m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
7816 m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
7817 m_desc.depthStencilBuffer(),
7818 m_desc.depthTexture(),
7819 m_desc.depthResolveTexture(),
7820 m_desc.shadingRateMap()))
7828 rhiD->registerResource(rp);
7837 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
7838 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
7839 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
7842 QVarLengthArray<VkImageView, 8> views;
7843 d.multiViewCount = 0;
7845 d.colorAttCount = 0;
7847 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
7848 d.colorAttCount += 1;
7851 Q_ASSERT(texD || rbD);
7853 Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
7854 const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
7855 const bool isMultiView = it->multiViewCount() >= 2;
7856 if (isMultiView && d.multiViewCount == 0)
7857 d.multiViewCount = it->multiViewCount();
7858 VkImageViewCreateInfo viewInfo = {};
7859 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7860 viewInfo.image = texD->image;
7861 viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
7862 : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
7863 : VK_IMAGE_VIEW_TYPE_2D);
7864 viewInfo.format = texD->viewFormat;
7865 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7866 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7867 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7868 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7869 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7870 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
7871 viewInfo.subresourceRange.levelCount = 1;
7872 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
7873 viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
7874 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &rtv[attIndex]);
7875 if (err != VK_SUCCESS) {
7876 qWarning(
"Failed to create render target image view: %d", err);
7879 views.append(rtv[attIndex]);
7880 if (attIndex == 0) {
7881 d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
7882 d.sampleCount = texD->samples;
7887 if (attIndex == 0) {
7888 d.pixelSize = rbD->pixelSize();
7889 d.sampleCount = rbD->samples;
7895 if (hasDepthStencil) {
7896 if (m_desc.depthTexture()) {
7899 VkImageViewCreateInfo viewInfo = {};
7900 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7901 viewInfo.image = depthTexD->image;
7902 viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
7903 viewInfo.format = depthTexD->viewFormat;
7904 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7905 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7906 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7907 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7908 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(depthTexD->format());
7909 viewInfo.subresourceRange.levelCount = 1;
7910 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
7911 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &dsv);
7912 if (err != VK_SUCCESS) {
7913 qWarning(
"Failed to create depth-stencil image view for rt: %d", err);
7917 if (d.colorAttCount == 0) {
7918 d.pixelSize = depthTexD->pixelSize();
7919 d.sampleCount = depthTexD->samples;
7923 views.append(depthRbD->imageView);
7924 if (d.colorAttCount == 0) {
7925 d.pixelSize = depthRbD->pixelSize();
7926 d.sampleCount = depthRbD->samples;
7934 d.resolveAttCount = 0;
7936 Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
7937 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
7938 if (it->resolveTexture()) {
7940 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
7941 d.resolveAttCount += 1;
7943 VkImageViewCreateInfo viewInfo = {};
7944 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7945 viewInfo.image = resTexD->image;
7946 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
7947 : VK_IMAGE_VIEW_TYPE_2D;
7948 viewInfo.format = resTexD->viewFormat;
7949 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7950 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7951 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7952 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7953 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7954 viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
7955 viewInfo.subresourceRange.levelCount = 1;
7956 viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
7957 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
7958 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resrtv[attIndex]);
7959 if (err != VK_SUCCESS) {
7960 qWarning(
"Failed to create render target resolve image view: %d", err);
7963 views.append(resrtv[attIndex]);
7967 if (m_desc.depthResolveTexture()) {
7969 Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
7971 VkImageViewCreateInfo viewInfo = {};
7972 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7973 viewInfo.image = resTexD->image;
7974 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
7975 : VK_IMAGE_VIEW_TYPE_2D;
7976 viewInfo.format = resTexD->viewFormat;
7977 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
7978 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
7979 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
7980 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
7981 viewInfo.subresourceRange.aspectMask = aspectMaskForTextureFormat(resTexD->format());
7982 viewInfo.subresourceRange.baseMipLevel = 0;
7983 viewInfo.subresourceRange.levelCount = 1;
7984 viewInfo.subresourceRange.baseArrayLayer = 0;
7985 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
7986 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &resdsv);
7987 if (err != VK_SUCCESS) {
7988 qWarning(
"Failed to create render target depth resolve image view: %d", err);
7991 views.append(resdsv);
7992 d.dsResolveAttCount = 1;
7994 d.dsResolveAttCount = 0;
7997 if (m_desc.shadingRateMap() && rhiD->caps.renderPass2KHR && rhiD->caps.imageBasedShadingRate) {
7999 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedAsShadingRateMap));
8001 VkImageViewCreateInfo viewInfo = {};
8002 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
8003 viewInfo.image = texD->image;
8004 viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
8005 : VK_IMAGE_VIEW_TYPE_2D;
8006 viewInfo.format = texD->viewFormat;
8007 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
8008 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
8009 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
8010 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
8011 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
8012 viewInfo.subresourceRange.baseMipLevel = 0;
8013 viewInfo.subresourceRange.levelCount = 1;
8014 viewInfo.subresourceRange.baseArrayLayer = 0;
8015 viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
8016 VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo,
nullptr, &shadingRateMapView);
8017 if (err != VK_SUCCESS) {
8018 qWarning(
"Failed to create render target shading rate map view: %d", err);
8021 views.append(shadingRateMapView);
8022 d.shadingRateAttCount = 1;
8024 d.shadingRateAttCount = 0;
8027 if (!m_renderPassDesc)
8028 qWarning(
"QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8030 d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8031 Q_ASSERT(d.rp && d.rp->rp);
8033 VkFramebufferCreateInfo fbInfo = {};
8034 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8035 fbInfo.renderPass = d.rp->rp;
8036 fbInfo.attachmentCount = uint32_t(views.count());
8037 fbInfo.pAttachments = views.constData();
8038 fbInfo.width = uint32_t(d.pixelSize.width());
8039 fbInfo.height = uint32_t(d.pixelSize.height());
8042 VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &d.fb);
8043 if (err != VK_SUCCESS) {
8044 qWarning(
"Failed to create framebuffer: %d", err);
8048 QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList);
8051 rhiD->registerResource(
this);
8057 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(m_desc, d.currentResIdList))
8070 return d.sampleCount;
8088 sortedBindings.clear();
8094 e.shaderResourceBindings.poolIndex =
poolIndex;
8095 e.shaderResourceBindings.layout = layout;
8098 layout = VK_NULL_HANDLE;
8099 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8100 descSets[i] = VK_NULL_HANDLE;
8104 rhiD->releaseQueue.append(e);
8105 rhiD->unregisterResource(
this);
8115 if (!rhiD->sanityCheckShaderResourceBindings(
this))
8118 rhiD->updateLayoutDesc(
this);
8120 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8121 descSets[i] = VK_NULL_HANDLE;
8123 sortedBindings.clear();
8124 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
8125 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8128 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8129 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8130 if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.buf) {
8131 if (b->u.ubuf.hasDynamicOffset)
8132 hasDynamicOffset =
true;
8136 QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
8137 for (
const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) {
8138 const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding);
8139 VkDescriptorSetLayoutBinding vkbinding = {};
8140 vkbinding.binding = uint32_t(b->binding);
8141 vkbinding.descriptorType = toVkDescriptorType(b);
8142 if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture)
8143 vkbinding.descriptorCount = b->u.stex.count;
8145 vkbinding.descriptorCount = 1;
8146 vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
8147 vkbindings.append(vkbinding);
8150 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
8151 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8152 layoutInfo.bindingCount = uint32_t(vkbindings.size());
8153 layoutInfo.pBindings = vkbindings.constData();
8155 VkResult err = rhiD->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo,
nullptr, &layout);
8156 if (err != VK_SUCCESS) {
8157 qWarning(
"Failed to create descriptor set layout: %d", err);
8161 VkDescriptorSetAllocateInfo allocInfo = {};
8162 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
8165 for (
int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
8166 layouts[i] = layout;
8167 allocInfo.pSetLayouts = layouts;
8168 if (!rhiD->allocateDescriptorSet(&allocInfo, descSets, &poolIndex))
8172 boundResourceData[i].resize(sortedBindings.size());
8173 for (BoundResourceData &bd : boundResourceData[i])
8174 memset(&bd, 0,
sizeof(BoundResourceData));
8179 rhiD->registerResource(
this);
8185 sortedBindings.clear();
8186 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
8187 if (!flags.testFlag(BindingsAreSorted))
8188 std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
8200 Q_ASSERT(boundResourceData[i].size() == sortedBindings.size());
8201 for (BoundResourceData &bd : boundResourceData[i])
8202 memset(&bd, 0,
sizeof(BoundResourceData));
8220 if (!pipeline && !layout)
8227 e.pipelineState.pipeline = pipeline;
8228 e.pipelineState.layout = layout;
8230 pipeline = VK_NULL_HANDLE;
8231 layout = VK_NULL_HANDLE;
8235 rhiD->releaseQueue.append(e);
8236 rhiD->unregisterResource(
this);
8246 rhiD->pipelineCreationStart();
8247 if (!rhiD->sanityCheckGraphicsPipeline(
this))
8250 if (!rhiD->ensurePipelineCache())
8253 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8254 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8255 pipelineLayoutInfo.setLayoutCount = 1;
8257 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8258 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8259 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8260 if (err != VK_SUCCESS) {
8261 qWarning(
"Failed to create pipeline layout: %d", err);
8265 VkGraphicsPipelineCreateInfo pipelineInfo = {};
8266 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
8268 QVarLengthArray<VkShaderModule, 4> shaders;
8269 QVarLengthArray<VkPipelineShaderStageCreateInfo, 4> shaderStageCreateInfos;
8270 for (
const QRhiShaderStage &shaderStage : m_shaderStages) {
8271 const QShader bakedShader = shaderStage.shader();
8272 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, shaderStage.shaderVariant() });
8273 if (spirv.shader().isEmpty()) {
8274 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8277 VkShaderModule shader = rhiD->createShader(spirv.shader());
8279 shaders.append(shader);
8280 VkPipelineShaderStageCreateInfo shaderInfo = {};
8281 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8282 shaderInfo.stage = toVkShaderStage(shaderStage.type());
8283 shaderInfo.module = shader;
8284 shaderInfo.pName = spirv.entryPoint().constData();
8285 shaderStageCreateInfos.append(shaderInfo);
8288 pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.size());
8289 pipelineInfo.pStages = shaderStageCreateInfos.constData();
8291 QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
8292#ifdef VK_EXT_vertex_attribute_divisor
8293 QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
8295 int bindingIndex = 0;
8296 for (
auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
8297 it != itEnd; ++it, ++bindingIndex)
8299 VkVertexInputBindingDescription bindingInfo = {
8300 uint32_t(bindingIndex),
8302 it->classification() == QRhiVertexInputBinding::PerVertex
8303 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
8305 if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
8306#ifdef VK_EXT_vertex_attribute_divisor
8307 if (rhiD->caps.vertexAttribDivisor) {
8308 nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
8312 qWarning(
"QRhiVulkan: Instance step rates other than 1 not supported without "
8313 "VK_EXT_vertex_attribute_divisor on the device and "
8314 "VK_KHR_get_physical_device_properties2 on the instance");
8317 vertexBindings.append(bindingInfo);
8319 QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
8320 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
8323 VkVertexInputAttributeDescription attributeInfo = {
8324 uint32_t(it->location()),
8325 uint32_t(it->binding()),
8326 toVkAttributeFormat(it->format()),
8329 vertexAttributes.append(attributeInfo);
8331 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
8332 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
8333 vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.size());
8334 vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
8335 vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
8336 vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
8337#ifdef VK_EXT_vertex_attribute_divisor
8338 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
8339 if (!nonOneStepRates.isEmpty()) {
8340 divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
8341 divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
8342 divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
8343 vertexInputInfo.pNext = &divisorInfo;
8346 pipelineInfo.pVertexInputState = &vertexInputInfo;
8348 QVarLengthArray<VkDynamicState, 8> dynEnable;
8349 dynEnable << VK_DYNAMIC_STATE_VIEWPORT;
8350 dynEnable << VK_DYNAMIC_STATE_SCISSOR;
8351 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesBlendConstants))
8352 dynEnable << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
8353 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef))
8354 dynEnable << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
8355#ifdef VK_KHR_fragment_shading_rate
8356 if (m_flags.testFlag(QRhiGraphicsPipeline::UsesShadingRate) && rhiD->caps.perDrawShadingRate)
8357 dynEnable << VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR;
8360 VkPipelineDynamicStateCreateInfo dynamicInfo = {};
8361 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
8362 dynamicInfo.dynamicStateCount = uint32_t(dynEnable.size());
8363 dynamicInfo.pDynamicStates = dynEnable.constData();
8364 pipelineInfo.pDynamicState = &dynamicInfo;
8366 VkPipelineViewportStateCreateInfo viewportInfo = {};
8367 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
8368 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
8369 pipelineInfo.pViewportState = &viewportInfo;
8371 VkPipelineInputAssemblyStateCreateInfo inputAsmInfo = {};
8372 inputAsmInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
8373 inputAsmInfo.topology = toVkTopology(m_topology);
8374 inputAsmInfo.primitiveRestartEnable = (m_topology == TriangleStrip || m_topology == LineStrip);
8375 pipelineInfo.pInputAssemblyState = &inputAsmInfo;
8377 VkPipelineTessellationStateCreateInfo tessInfo = {};
8378#ifdef VK_VERSION_1_1
8379 VkPipelineTessellationDomainOriginStateCreateInfo originInfo = {};
8381 if (m_topology == Patches) {
8382 tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
8383 tessInfo.patchControlPoints = uint32_t(qMax(1, m_patchControlPointCount));
8390#ifdef VK_VERSION_1_1
8391 if (rhiD->caps.apiVersion >= QVersionNumber(1, 1)) {
8392 originInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
8393 originInfo.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
8394 tessInfo.pNext = &originInfo;
8396 qWarning(
"Proper tessellation support requires Vulkan 1.1 or newer, leaving domain origin unset");
8399 qWarning(
"QRhi was built without Vulkan 1.1 headers, this is not sufficient for proper tessellation support");
8402 pipelineInfo.pTessellationState = &tessInfo;
8405 VkPipelineRasterizationStateCreateInfo rastInfo = {};
8406 rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
8407 if (m_depthClamp && rhiD->caps.depthClamp)
8408 rastInfo.depthClampEnable = m_depthClamp;
8409 rastInfo.cullMode = toVkCullMode(m_cullMode);
8410 rastInfo.frontFace = toVkFrontFace(m_frontFace);
8411 if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) {
8412 rastInfo.depthBiasEnable =
true;
8413 rastInfo.depthBiasConstantFactor =
float(m_depthBias);
8414 rastInfo.depthBiasSlopeFactor = m_slopeScaledDepthBias;
8416 rastInfo.lineWidth = rhiD->caps.wideLines ? m_lineWidth : 1.0f;
8417 rastInfo.polygonMode = toVkPolygonMode(m_polygonMode);
8418 pipelineInfo.pRasterizationState = &rastInfo;
8420 VkPipelineMultisampleStateCreateInfo msInfo = {};
8421 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
8422 msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
8423 pipelineInfo.pMultisampleState = &msInfo;
8425 VkPipelineDepthStencilStateCreateInfo dsInfo = {};
8426 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
8427 dsInfo.depthTestEnable = m_depthTest;
8428 dsInfo.depthWriteEnable = m_depthWrite;
8429 dsInfo.depthCompareOp = toVkCompareOp(m_depthOp);
8430 dsInfo.stencilTestEnable = m_stencilTest;
8431 if (m_stencilTest) {
8432 fillVkStencilOpState(&dsInfo.front, m_stencilFront);
8433 dsInfo.front.compareMask = m_stencilReadMask;
8434 dsInfo.front.writeMask = m_stencilWriteMask;
8435 fillVkStencilOpState(&dsInfo.back, m_stencilBack);
8436 dsInfo.back.compareMask = m_stencilReadMask;
8437 dsInfo.back.writeMask = m_stencilWriteMask;
8439 pipelineInfo.pDepthStencilState = &dsInfo;
8441 VkPipelineColorBlendStateCreateInfo blendInfo = {};
8442 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
8443 QVarLengthArray<VkPipelineColorBlendAttachmentState, 4> vktargetBlends;
8444 for (
const QRhiGraphicsPipeline::TargetBlend &b : std::as_const(m_targetBlends)) {
8445 VkPipelineColorBlendAttachmentState blend = {};
8446 blend.blendEnable = b.enable;
8447 blend.srcColorBlendFactor = toVkBlendFactor(b.srcColor);
8448 blend.dstColorBlendFactor = toVkBlendFactor(b.dstColor);
8449 blend.colorBlendOp = toVkBlendOp(b.opColor);
8450 blend.srcAlphaBlendFactor = toVkBlendFactor(b.srcAlpha);
8451 blend.dstAlphaBlendFactor = toVkBlendFactor(b.dstAlpha);
8452 blend.alphaBlendOp = toVkBlendOp(b.opAlpha);
8453 blend.colorWriteMask = toVkColorComponents(b.colorWrite);
8454 vktargetBlends.append(blend);
8456 if (vktargetBlends.isEmpty()) {
8457 VkPipelineColorBlendAttachmentState blend = {};
8458 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
8459 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
8460 vktargetBlends.append(blend);
8462 blendInfo.attachmentCount = uint32_t(vktargetBlends.size());
8463 blendInfo.pAttachments = vktargetBlends.constData();
8464 pipelineInfo.pColorBlendState = &blendInfo;
8466 pipelineInfo.layout = layout;
8468 Q_ASSERT(m_renderPassDesc &&
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp);
8469 pipelineInfo.renderPass =
QRHI_RES(
const QVkRenderPassDescriptor, m_renderPassDesc)->rp;
8471 err = rhiD->df->vkCreateGraphicsPipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8473 for (VkShaderModule shader : shaders)
8474 rhiD->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8476 if (err != VK_SUCCESS) {
8477 qWarning(
"Failed to create graphics pipeline: %d", err);
8481 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8483 rhiD->pipelineCreationEnd();
8486 rhiD->registerResource(
this);
8502 if (!pipeline && !layout)
8509 e.pipelineState.pipeline = pipeline;
8510 e.pipelineState.layout = layout;
8512 pipeline = VK_NULL_HANDLE;
8513 layout = VK_NULL_HANDLE;
8517 rhiD->releaseQueue.append(e);
8518 rhiD->unregisterResource(
this);
8528 rhiD->pipelineCreationStart();
8529 if (!rhiD->ensurePipelineCache())
8532 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
8533 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8534 pipelineLayoutInfo.setLayoutCount = 1;
8536 Q_ASSERT(m_shaderResourceBindings && srbD->layout);
8537 pipelineLayoutInfo.pSetLayouts = &srbD->layout;
8538 VkResult err = rhiD->df->vkCreatePipelineLayout(rhiD->dev, &pipelineLayoutInfo,
nullptr, &layout);
8539 if (err != VK_SUCCESS) {
8540 qWarning(
"Failed to create pipeline layout: %d", err);
8544 VkComputePipelineCreateInfo pipelineInfo = {};
8545 pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8546 pipelineInfo.layout = layout;
8548 if (m_shaderStage.type() != QRhiShaderStage::Compute) {
8549 qWarning(
"Compute pipeline requires a compute shader stage");
8552 const QShader bakedShader = m_shaderStage.shader();
8553 const QShaderCode spirv = bakedShader.shader({ QShader::SpirvShader, 100, m_shaderStage.shaderVariant() });
8554 if (spirv.shader().isEmpty()) {
8555 qWarning() <<
"No SPIR-V 1.0 shader code found in baked shader" << bakedShader;
8558 if (bakedShader.stage() != QShader::ComputeStage) {
8559 qWarning() << bakedShader <<
"is not a compute shader";
8562 VkShaderModule shader = rhiD->createShader(spirv.shader());
8563 VkPipelineShaderStageCreateInfo shaderInfo = {};
8564 shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8565 shaderInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8566 shaderInfo.module = shader;
8567 shaderInfo.pName = spirv.entryPoint().constData();
8568 pipelineInfo.stage = shaderInfo;
8570 err = rhiD->df->vkCreateComputePipelines(rhiD->dev, rhiD->pipelineCache, 1, &pipelineInfo,
nullptr, &pipeline);
8571 rhiD
->df->vkDestroyShaderModule(rhiD->dev, shader,
nullptr);
8572 if (err != VK_SUCCESS) {
8573 qWarning(
"Failed to create graphics pipeline: %d", err);
8577 rhiD->setObjectName(uint64_t(pipeline), VK_OBJECT_TYPE_PIPELINE, m_objectName);
8579 rhiD->pipelineCreationEnd();
8582 rhiD->registerResource(
this);
8611 nativeHandlesStruct.commandBuffer = cb;
8613 if (passUsesSecondaryCb && !activeSecondaryCbStack.isEmpty())
8614 nativeHandlesStruct.commandBuffer = activeSecondaryCbStack.last();
8616 nativeHandlesStruct.commandBuffer = cb;
8619 return &nativeHandlesStruct;
8637 if (sc == VK_NULL_HANDLE)
8642 rhiD->swapchains.remove(
this);
8648 frame.cmdBuf = VK_NULL_HANDLE;
8652 surface = lastConnectedSurface = VK_NULL_HANDLE;
8655 rhiD->unregisterResource(
this);
8670 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
8680 VkSurfaceCapabilitiesKHR surfaceCaps = {};
8682 rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
8683 VkExtent2D bufferSize = surfaceCaps.currentExtent;
8684 if (bufferSize.width == uint32_t(-1)) {
8685 Q_ASSERT(bufferSize.height == uint32_t(-1));
8686 return m_window->size() * m_window->devicePixelRatio();
8688 return QSize(
int(bufferSize.width),
int(bufferSize.height));
8694 case QRhiSwapChain::HDRExtendedSrgbLinear:
8695 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8696 && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
8697 case QRhiSwapChain::HDR10:
8698 return (s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || s.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32)
8699 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
8700 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
8701 return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
8702 && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
8715 qWarning(
"Attempted to call isFormatSupported() without a window set");
8720 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8723 uint32_t formatCount = 0;
8724 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount,
nullptr);
8725 QVarLengthArray<VkSurfaceFormatKHR, 8> formats(formatCount);
8727 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surf, &formatCount, formats.data());
8728 for (uint32_t i = 0; i < formatCount; ++i) {
8729 if (hdrFormatMatchesVkSurfaceFormat(f, formats[i]))
8741 QRHI_RES_RHI(QRhiVulkan);
8743 if (m_window && rhiD->adapterLuidValid)
8744 info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window);
8758 if (!rhiD->createDefaultRenderPass(rp,
8759 m_depthStencil !=
nullptr,
8770 rhiD->registerResource(rp);
8777 case VK_FORMAT_R8_SRGB:
8778 case VK_FORMAT_R8G8_SRGB:
8779 case VK_FORMAT_R8G8B8_SRGB:
8780 case VK_FORMAT_B8G8R8_SRGB:
8781 case VK_FORMAT_R8G8B8A8_SRGB:
8782 case VK_FORMAT_B8G8R8A8_SRGB:
8783 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
8798 VkSurfaceKHR surf = QVulkanInstance::surfaceForWindow(m_window);
8800 qWarning(
"Failed to get surface for window");
8803 if (surface == surf)
8809 if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
8810 qWarning(
"Presenting not supported on this window");
8814 quint32 formatCount = 0;
8815 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount,
nullptr);
8816 QList<VkSurfaceFormatKHR> formats(formatCount);
8818 rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, formats.data());
8822 const bool srgbRequested = m_flags.testFlag(sRGB);
8823 for (
int i = 0; i <
int(formatCount); ++i) {
8824 if (formats[i].format != VK_FORMAT_UNDEFINED) {
8825 bool ok = srgbRequested == isSrgbFormat(formats[i].format);
8826 if (m_format != SDR)
8827 ok &= hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
8829 colorFormat = formats[i].format;
8830 colorSpace = formats[i].colorSpace;
8831#if QT_CONFIG(wayland)
8836 const bool hasPassThrough = std::any_of(formats.begin(), formats.end(), [
this](
const VkSurfaceFormatKHR &fmt) {
8837 return fmt.format == colorFormat && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
8839 if (hasPassThrough) {
8840 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
8848 samples = rhiD->effectiveSampleCountBits(m_sampleCount);
8850 quint32 presModeCount = 0;
8851 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
nullptr);
8852 supportedPresentationModes.resize(presModeCount);
8853 rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount,
8854 supportedPresentationModes.data());
8862 const bool needsRegistration = !window || window != m_window;
8869 if (window && window != m_window)
8873 m_currentPixelSize = surfacePixelSize();
8874 pixelSize = m_currentPixelSize;
8877 qWarning(
"Failed to create new swapchain");
8881 if (needsRegistration || !rhiD->swapchains.contains(
this))
8882 rhiD->swapchains.insert(
this);
8884 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
8885 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
8886 m_depthStencil->sampleCount(), m_sampleCount);
8888 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
8889 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
8890 m_depthStencil->setPixelSize(pixelSize);
8891 if (!m_depthStencil->create())
8892 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
8893 pixelSize.width(), pixelSize.height());
8895 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
8896 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
8897 pixelSize.width(), pixelSize.height());
8901 if (!m_renderPassDesc)
8902 qWarning(
"QVkSwapChain: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
8904 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
8905 rtWrapper.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8906 Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
8908 rtWrapper.d.pixelSize = pixelSize;
8909 rtWrapper.d.dpr =
float(window->devicePixelRatio());
8910 rtWrapper.d.sampleCount = samples;
8911 rtWrapper.d.colorAttCount = 1;
8912 if (m_depthStencil) {
8913 rtWrapper.d.dsAttCount = 1;
8914 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
8916 rtWrapper.d.dsAttCount = 0;
8919 rtWrapper.d.dsResolveAttCount = 0;
8920 if (samples > VK_SAMPLE_COUNT_1_BIT)
8921 rtWrapper.d.resolveAttCount = 1;
8923 rtWrapper.d.resolveAttCount = 0;
8925 if (shadingRateMapView)
8926 rtWrapper.d.shadingRateAttCount = 1;
8928 rtWrapper.d.shadingRateAttCount = 0;
8933 QVarLengthArray<VkImageView, 4> views;
8934 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
8936 views.append(
ds->imageView);
8937 if (samples > VK_SAMPLE_COUNT_1_BIT)
8938 views.append(image.imageView);
8939 if (shadingRateMapView)
8940 views.append(shadingRateMapView);
8942 VkFramebufferCreateInfo fbInfo = {};
8943 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8944 fbInfo.renderPass = rtWrapper.d.rp->rp;
8945 fbInfo.attachmentCount = uint32_t(views.count());
8946 fbInfo.pAttachments = views.constData();
8947 fbInfo.width = uint32_t(pixelSize.width());
8948 fbInfo.height = uint32_t(pixelSize.height());
8951 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
8952 if (err != VK_SUCCESS) {
8953 qWarning(
"Failed to create framebuffer: %d", err);
8959 rtWrapperRight.setRenderPassDescriptor(
8961 rtWrapperRight.d.rp =
QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
8962 Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
8964 rtWrapperRight.d.pixelSize = pixelSize;
8965 rtWrapperRight.d.dpr =
float(window->devicePixelRatio());
8966 rtWrapperRight.d.sampleCount = samples;
8967 rtWrapperRight.d.colorAttCount = 1;
8968 if (m_depthStencil) {
8969 rtWrapperRight.d.dsAttCount = 1;
8970 ds =
QRHI_RES(QVkRenderBuffer, m_depthStencil);
8972 rtWrapperRight.d.dsAttCount = 0;
8975 rtWrapperRight.d.dsResolveAttCount = 0;
8976 if (samples > VK_SAMPLE_COUNT_1_BIT)
8977 rtWrapperRight.d.resolveAttCount = 1;
8979 rtWrapperRight.d.resolveAttCount = 0;
8984 QVarLengthArray<VkImageView, 4> views;
8985 views.append(samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView);
8987 views.append(
ds->imageView);
8988 if (samples > VK_SAMPLE_COUNT_1_BIT)
8989 views.append(image.imageView);
8990 if (shadingRateMapView)
8991 views.append(shadingRateMapView);
8993 VkFramebufferCreateInfo fbInfo = {};
8994 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
8995 fbInfo.renderPass = rtWrapperRight.d.rp->rp;
8996 fbInfo.attachmentCount = uint32_t(views.count());
8997 fbInfo.pAttachments = views.constData();
8998 fbInfo.width = uint32_t(pixelSize.width());
8999 fbInfo.height = uint32_t(pixelSize.height());
9002 VkResult err = rhiD
->df->vkCreateFramebuffer(rhiD->dev, &fbInfo,
nullptr, &image.fb);
9003 if (err != VK_SUCCESS) {
9004 qWarning(
"Failed to create framebuffer: %d", err);
9012 if (needsRegistration)
9013 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
Combined button and popup list for selecting options.
static VkPolygonMode toVkPolygonMode(QRhiGraphicsPipeline::PolygonMode mode)
static VkCullModeFlags toVkCullMode(QRhiGraphicsPipeline::CullMode c)
static bool accessIsWrite(VkAccessFlags access)
static VkCompareOp toVkTextureCompareOp(QRhiSampler::CompareOp op)
static QVulkanInstance * globalVulkanInstance
static VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
static QRhiTexture::Format swapchainReadbackTextureFormat(VkFormat format, QRhiTexture::Flags *flags)
static VkStencilOp toVkStencilOp(QRhiGraphicsPipeline::StencilOp op)
static bool qvk_debug_filter(QVulkanInstance::DebugMessageSeverityFlags severity, QVulkanInstance::DebugMessageTypeFlags type, const void *callbackData)
static QVkBuffer::UsageState toVkBufferUsageState(QRhiPassResourceTracker::UsageState usage)
static bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b)
static bool isSrgbFormat(VkFormat format)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::TextureStage stage)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::BufferAccess access)
static VkImageLayout toVkLayout(QRhiPassResourceTracker::TextureAccess access)
static VkFormat toVkAttributeFormat(QRhiVertexInputAttribute::Format format)
static QVkTexture::UsageState toVkTextureUsageState(QRhiPassResourceTracker::UsageState usage)
static VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::BufferStage stage)
static QRhiDriverInfo::DeviceType toRhiDeviceType(VkPhysicalDeviceType type)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkBuffer::UsageState &bufUsage)
static VkColorComponentFlags toVkColorComponents(QRhiGraphicsPipeline::ColorMask c)
static VkFilter toVkFilter(QRhiSampler::Filter f)
static VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t)
static void qrhivk_releaseTexture(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df, void *allocator)
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
static VkAccessFlags toVkAccess(QRhiPassResourceTracker::TextureAccess access)
static VmaAllocator toVmaAllocator(QVkAllocator a)
static VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
static constexpr bool isDepthTextureFormat(QRhiTexture::Format format)
static void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphicsPipeline::StencilOpState &src)
VkSampleCountFlagBits mask
static VkShaderStageFlags toVkShaderStageFlags(QRhiShaderResourceBinding::StageFlags stage)
static constexpr VkImageAspectFlags aspectMaskForTextureFormat(QRhiTexture::Format format)
static VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
static VkBlendFactor toVkBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
static void fillDriverInfo(QRhiDriverInfo *info, const VkPhysicalDeviceProperties &physDevProperties)
static VkBlendOp toVkBlendOp(QRhiGraphicsPipeline::BlendOp op)
static void qrhivk_releaseRenderBuffer(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static VkFrontFace toVkFrontFace(QRhiGraphicsPipeline::FrontFace f)
void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource, QRhiShaderResourceBinding::Type bindingType, int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
static VkFormat toVkTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
static VkCompareOp toVkCompareOp(QRhiGraphicsPipeline::CompareOp op)
static void fillRenderPassCreateInfo(VkRenderPassCreateInfo *rpInfo, VkSubpassDescription *subpassDesc, QVkRenderPassDescriptor *rpD)
static VkSamplerMipmapMode toVkMipmapMode(QRhiSampler::Filter f)
static bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, const VkSurfaceFormatKHR &s)
static void qrhivk_releaseSampler(const QRhiVulkan::DeferredReleaseEntry &e, VkDevice dev, QVulkanDeviceFunctions *df)
static constexpr bool isStencilTextureFormat(QRhiTexture::Format format)
static QVkRenderTargetData * maybeRenderTargetData(QVkCommandBuffer *cbD)
static QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const QVkTexture::UsageState &texUsage)
static VmaAllocation toVmaAllocation(QVkAlloc a)
static void addToChain(T *head, void *entry)
static VkShaderStageFlagBits toVkShaderStage(QRhiShaderStage::Type type)
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS
static const int QVK_DESC_SETS_PER_POOL
static const int QVK_FRAMES_IN_FLIGHT
bool prepare(VkRenderPassCreateInfo *rpInfo, int multiViewCount, bool multiViewCap)
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
QRhiBuffer::NativeBuffer nativeBuffer() override
bool create() override
Creates the corresponding native graphics resources.
char * beginFullDynamicBufferUpdateForCurrentFrame() override
@ TransitionPassResources
QVkCommandBuffer(QRhiImplementation *rhi)
const QRhiNativeHandles * nativeHandles()
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
int currentPassResTrackerIndex
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkComputePipeline(QRhiImplementation *rhi)
QVkGraphicsPipeline(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags, QRhiTexture::Format backingFormatHint)
QRhiTexture::Format backingFormat() const override
bool create() override
Creates the corresponding native graphics resources.
QVkTexture * backingTexture
const QRhiNativeHandles * nativeHandles() override
void updateSerializedFormat()
bool hasDepthStencilResolve
~QVkRenderPassDescriptor()
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVector< quint32 > serializedFormat() const override
QVkRenderPassDescriptor(QRhiImplementation *rhi)
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QVkRenderPassDescriptor * rp
static const int MAX_COLOR_ATTACHMENTS
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
void updateResources(UpdateFlags flags) override
QVkShaderResourceBindings(QRhiImplementation *rhi)
bool create() override
Creates the corresponding resource binding set.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
~QVkShaderResourceBindings()
bool createFrom(QRhiTexture *src) override
Sets up the shading rate map to use the texture src as the image containing the per-tile shading rate...
QVkShadingRateMap(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QSize pixelSize() const override
int sampleCount() const override
float devicePixelRatio() const override
~QVkSwapChainRenderTarget()
QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
@ ScImageUseTransferSource
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QRhiRenderTarget * currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override
bool isFormatSupported(Format f) override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
QVkSwapChain(QRhiImplementation *rhi)
QSize surfacePixelSize() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderTarget * currentFrameRenderTarget() override
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::limitsType
QRhiCommandBuffer * currentFrameCommandBuffer() override
QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
~QVkTextureRenderTarget()
float devicePixelRatio() const override
bool create() override
Creates the corresponding native graphics resources.
int sampleCount() const override
QSize pixelSize() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
VkImageView perLevelImageViewForLoadStore(int level)
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT]
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
void setNativeLayout(int layout) override
With some graphics APIs, such as Vulkan, integrating custom rendering code that uses the graphics API...
QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
NativeTexture nativeTexture() override
bool prepareCreate(QSize *adjustedSize=nullptr)