1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QRHIVULKAN_P_H
5#define QRHIVULKAN_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qrhi_p.h"
19
20#ifdef Q_OS_WIN
21#include "qdxgihdrinfo_p.h"
22#endif
23
24QT_BEGIN_NAMESPACE
25
26class QVulkanFunctions;
27class QVulkanDeviceFunctions;
28
29static const int QVK_FRAMES_IN_FLIGHT = 2;
30
31static const int QVK_DESC_SETS_PER_POOL = 128;
32static const int QVK_UNIFORM_BUFFERS_PER_POOL = 256;
33static const int QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL = 256;
34static const int QVK_STORAGE_BUFFERS_PER_POOL = 128;
35static const int QVK_STORAGE_IMAGES_PER_POOL = 128;
36
37static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS = 16;
38
39// no vk_mem_alloc.h available here, void* is good enough
40typedef void * QVkAlloc;
41typedef void * QVkAllocator;
42
43struct QVkBuffer : public QRhiBuffer
44{
45 QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
46 ~QVkBuffer();
47 void destroy() override;
48 bool create() override;
49 QRhiBuffer::NativeBuffer nativeBuffer() override;
50 char *beginFullDynamicBufferUpdateForCurrentFrame() override;
51 void endFullDynamicBufferUpdateForCurrentFrame() override;
52
53 VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
54 QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
55 struct DynamicUpdate {
56 quint32 offset;
57 QRhiBufferData data;
58 };
59 QVarLengthArray<DynamicUpdate, 16> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
60 VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
61 QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
62 struct UsageState {
63 VkAccessFlags access = 0;
64 VkPipelineStageFlags stage = 0;
65 };
66 UsageState usageState[QVK_FRAMES_IN_FLIGHT];
67 int lastActiveFrameSlot = -1;
68 uint generation = 0;
69 friend class QRhiVulkan;
70};
71
72Q_DECLARE_TYPEINFO(QVkBuffer::DynamicUpdate, Q_RELOCATABLE_TYPE);
73
74struct QVkTexture;
75
76struct QVkRenderBuffer : public QRhiRenderBuffer
77{
78 QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
79 int sampleCount, Flags flags,
80 QRhiTexture::Format backingFormatHint);
81 ~QVkRenderBuffer();
82 void destroy() override;
83 bool create() override;
84 QRhiTexture::Format backingFormat() const override;
85
86 VkDeviceMemory memory = VK_NULL_HANDLE;
87 VkImage image = VK_NULL_HANDLE;
88 VkImageView imageView = VK_NULL_HANDLE;
89 VkSampleCountFlagBits samples;
90 QVkTexture *backingTexture = nullptr;
91 VkFormat vkformat;
92 int lastActiveFrameSlot = -1;
93 uint generation = 0;
94 friend class QRhiVulkan;
95};
96
97struct QVkTexture : public QRhiTexture
98{
99 QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
100 int arraySize, int sampleCount, Flags flags);
101 ~QVkTexture();
102 void destroy() override;
103 bool create() override;
104 bool createFrom(NativeTexture src) override;
105 NativeTexture nativeTexture() override;
106 void setNativeLayout(int layout) override;
107
108 bool prepareCreate(QSize *adjustedSize = nullptr);
109 bool finishCreate();
110 VkImageView perLevelImageViewForLoadStore(int level);
111
112 VkImage image = VK_NULL_HANDLE;
113 VkImageView imageView = VK_NULL_HANDLE;
114 QVkAlloc imageAlloc = nullptr;
115 VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
116 QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
117 VkImageView perLevelImageViews[QRhi::MAX_MIP_LEVELS];
118 bool owns = true;
119 struct UsageState {
120 // no tracking of subresource layouts (some operations can keep
121 // subresources in different layouts for some time, but that does not
122 // need to be kept track of)
123 VkImageLayout layout;
124 VkAccessFlags access;
125 VkPipelineStageFlags stage;
126 };
127 UsageState usageState;
128 VkFormat vkformat;
129 uint mipLevelCount = 0;
130 VkSampleCountFlagBits samples;
131 VkFormat viewFormat;
132 VkFormat viewFormatForSampling;
133 int lastActiveFrameSlot = -1;
134 uint generation = 0;
135 friend class QRhiVulkan;
136};
137
138struct QVkSampler : public QRhiSampler
139{
140 QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
141 AddressMode u, AddressMode v, AddressMode w);
142 ~QVkSampler();
143 void destroy() override;
144 bool create() override;
145
146 VkSampler sampler = VK_NULL_HANDLE;
147 int lastActiveFrameSlot = -1;
148 uint generation = 0;
149 friend class QRhiVulkan;
150};
151
152struct QVkShadingRateMap : public QRhiShadingRateMap
153{
154 QVkShadingRateMap(QRhiImplementation *rhi);
155 ~QVkShadingRateMap();
156 void destroy() override;
157 bool createFrom(QRhiTexture *src) override;
158
159 QVkTexture *texture = nullptr; // not owned
160 friend class QRhiVulkan;
161};
162
163struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor
164{
165 QVkRenderPassDescriptor(QRhiImplementation *rhi);
166 ~QVkRenderPassDescriptor();
167 void destroy() override;
168 bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
169 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
170 QVector<quint32> serializedFormat() const override;
171 const QRhiNativeHandles *nativeHandles() override;
172
173 void updateSerializedFormat();
174
175 VkRenderPass rp = VK_NULL_HANDLE;
176 bool ownsRp = false;
177 QVarLengthArray<VkAttachmentDescription, 8> attDescs;
178 QVarLengthArray<VkAttachmentReference, 8> colorRefs;
179 QVarLengthArray<VkAttachmentReference, 8> resolveRefs;
180 QVarLengthArray<VkSubpassDependency, 2> subpassDeps;
181 bool hasDepthStencil = false;
182 bool hasDepthStencilResolve = false;
183 bool hasShadingRateMap = false;
184 uint32_t multiViewCount = 0;
185 VkAttachmentReference dsRef;
186 VkAttachmentReference dsResolveRef;
187 VkAttachmentReference shadingRateRef;
188 QVector<quint32> serializedFormatData;
189 QRhiVulkanRenderPassNativeHandles nativeHandlesStruct;
190 int lastActiveFrameSlot = -1;
191};
192
193struct QVkRenderTargetData
194{
195 VkFramebuffer fb = VK_NULL_HANDLE;
196 QVkRenderPassDescriptor *rp = nullptr;
197 QSize pixelSize;
198 float dpr = 1;
199 int sampleCount = 1;
200 int colorAttCount = 0;
201 int dsAttCount = 0;
202 int resolveAttCount = 0;
203 int dsResolveAttCount = 0;
204 int shadingRateAttCount = 0;
205 int multiViewCount = 0;
206 QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
207 static const int MAX_COLOR_ATTACHMENTS = 8;
208};
209
210struct QVkSwapChainRenderTarget : public QRhiSwapChainRenderTarget
211{
212 QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
213 ~QVkSwapChainRenderTarget();
214 void destroy() override;
215
216 QSize pixelSize() const override;
217 float devicePixelRatio() const override;
218 int sampleCount() const override;
219
220 QVkRenderTargetData d;
221};
222
223struct QVkTextureRenderTarget : public QRhiTextureRenderTarget
224{
225 QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
226 ~QVkTextureRenderTarget();
227 void destroy() override;
228
229 QSize pixelSize() const override;
230 float devicePixelRatio() const override;
231 int sampleCount() const override;
232
233 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
234 bool create() override;
235
236 QVkRenderTargetData d;
237 VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
238 VkImageView dsv = VK_NULL_HANDLE;
239 VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
240 VkImageView resdsv = VK_NULL_HANDLE;
241 VkImageView shadingRateMapView = VK_NULL_HANDLE;
242 int lastActiveFrameSlot = -1;
243 friend class QRhiVulkan;
244};
245
246struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
247{
248 QVkShaderResourceBindings(QRhiImplementation *rhi);
249 ~QVkShaderResourceBindings();
250 void destroy() override;
251 bool create() override;
252 void updateResources(UpdateFlags flags) override;
253
254 QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
255 bool hasDynamicOffset = false;
256 int poolIndex = -1;
257 VkDescriptorSetLayout layout = VK_NULL_HANDLE;
258 VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
259 int lastActiveFrameSlot = -1;
260 uint generation = 0;
261
262 // Keep track of the generation number of each referenced QRhi* to be able
263 // to detect that the underlying descriptor set became out of date and they
264 // need to be written again with the up-to-date VkBuffer etc. objects.
265 struct BoundUniformBufferData {
266 quint64 id;
267 uint generation;
268 };
269 struct BoundSampledTextureData {
270 int count;
271 struct {
272 quint64 texId;
273 uint texGeneration;
274 quint64 samplerId;
275 uint samplerGeneration;
276 } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
277 };
278 struct BoundStorageImageData {
279 quint64 id;
280 uint generation;
281 };
282 struct BoundStorageBufferData {
283 quint64 id;
284 uint generation;
285 };
286 struct BoundResourceData {
287 union {
288 BoundUniformBufferData ubuf;
289 BoundSampledTextureData stex;
290 BoundStorageImageData simage;
291 BoundStorageBufferData sbuf;
292 };
293 };
294 QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
295
296 friend class QRhiVulkan;
297};
298
299Q_DECLARE_TYPEINFO(QVkShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
300
301struct QVkGraphicsPipeline : public QRhiGraphicsPipeline
302{
303 QVkGraphicsPipeline(QRhiImplementation *rhi);
304 ~QVkGraphicsPipeline();
305 void destroy() override;
306 bool create() override;
307
308 VkPipelineLayout layout = VK_NULL_HANDLE;
309 VkPipeline pipeline = VK_NULL_HANDLE;
310 int lastActiveFrameSlot = -1;
311 uint generation = 0;
312 friend class QRhiVulkan;
313};
314
315struct QVkComputePipeline : public QRhiComputePipeline
316{
317 QVkComputePipeline(QRhiImplementation *rhi);
318 ~QVkComputePipeline();
319 void destroy() override;
320 bool create() override;
321
322 VkPipelineLayout layout = VK_NULL_HANDLE;
323 VkPipeline pipeline = VK_NULL_HANDLE;
324 int lastActiveFrameSlot = -1;
325 uint generation = 0;
326 friend class QRhiVulkan;
327};
328
329struct QVkCommandBuffer : public QRhiCommandBuffer
330{
331 QVkCommandBuffer(QRhiImplementation *rhi);
332 ~QVkCommandBuffer();
333 void destroy() override;
334
335 const QRhiNativeHandles *nativeHandles();
336
337 VkCommandBuffer cb = VK_NULL_HANDLE; // primary
338 QRhiVulkanCommandBufferNativeHandles nativeHandlesStruct;
339
340 enum PassType {
341 NoPass,
342 RenderPass,
343 ComputePass
344 };
345
346 void resetState() {
347 recordingPass = NoPass;
348 passUsesSecondaryCb = false;
349 lastGpuTime = 0;
350 currentTarget = nullptr;
351 activeSecondaryCbStack.clear();
352 resetCommands();
353 resetPerPassState();
354 }
355
356 void resetPerPassState() {
357 currentGraphicsPipeline = nullptr;
358 currentComputePipeline = nullptr;
359 currentPipelineGeneration = 0;
360 currentGraphicsSrb = nullptr;
361 currentComputeSrb = nullptr;
362 currentSrbGeneration = 0;
363 currentDescSetSlot = -1;
364 currentIndexBuffer = VK_NULL_HANDLE;
365 currentIndexOffset = 0;
366 currentIndexFormat = VK_INDEX_TYPE_UINT16;
367 memset(s: currentVertexBuffers, c: 0, n: sizeof(currentVertexBuffers));
368 memset(s: currentVertexOffsets, c: 0, n: sizeof(currentVertexOffsets));
369 inExternal = false;
370 hasShadingRateSet = false;
371 }
372
373 PassType recordingPass;
374 bool passUsesSecondaryCb;
375 double lastGpuTime = 0;
376 QRhiRenderTarget *currentTarget;
377 QRhiGraphicsPipeline *currentGraphicsPipeline;
378 QRhiComputePipeline *currentComputePipeline;
379 uint currentPipelineGeneration;
380 QRhiShaderResourceBindings *currentGraphicsSrb;
381 QRhiShaderResourceBindings *currentComputeSrb;
382 uint currentSrbGeneration;
383 int currentDescSetSlot;
384 VkBuffer currentIndexBuffer;
385 quint32 currentIndexOffset;
386 VkIndexType currentIndexFormat;
387 static const int VERTEX_INPUT_RESOURCE_SLOT_COUNT = 32;
388 VkBuffer currentVertexBuffers[VERTEX_INPUT_RESOURCE_SLOT_COUNT];
389 quint32 currentVertexOffsets[VERTEX_INPUT_RESOURCE_SLOT_COUNT];
390 QVarLengthArray<VkCommandBuffer, 4> activeSecondaryCbStack;
391 bool inExternal;
392 bool hasShadingRateSet;
393
394 struct {
395 QHash<QRhiResource *, std::pair<VkAccessFlags, bool> > writtenResources;
396 void reset() {
397 writtenResources.clear();
398 }
399 } computePassState;
400
401 struct Command {
402 enum Cmd {
403 CopyBuffer,
404 CopyBufferToImage,
405 CopyImage,
406 CopyImageToBuffer,
407 ImageBarrier,
408 BufferBarrier,
409 BlitImage,
410 BeginRenderPass,
411 EndRenderPass,
412 BindPipeline,
413 BindDescriptorSet,
414 BindVertexBuffer,
415 BindIndexBuffer,
416 SetViewport,
417 SetScissor,
418 SetBlendConstants,
419 SetStencilRef,
420 Draw,
421 DrawIndexed,
422 DebugMarkerBegin,
423 DebugMarkerEnd,
424 DebugMarkerInsert,
425 TransitionPassResources,
426 Dispatch,
427 ExecuteSecondary,
428 SetShadingRate
429 };
430 Cmd cmd;
431
432 union Args {
433 struct {
434 VkBuffer src;
435 VkBuffer dst;
436 VkBufferCopy desc;
437 } copyBuffer;
438 struct {
439 VkBuffer src;
440 VkImage dst;
441 VkImageLayout dstLayout;
442 int count;
443 int bufferImageCopyIndex;
444 } copyBufferToImage;
445 struct {
446 VkImage src;
447 VkImageLayout srcLayout;
448 VkImage dst;
449 VkImageLayout dstLayout;
450 VkImageCopy desc;
451 } copyImage;
452 struct {
453 VkImage src;
454 VkImageLayout srcLayout;
455 VkBuffer dst;
456 VkBufferImageCopy desc;
457 } copyImageToBuffer;
458 struct {
459 VkPipelineStageFlags srcStageMask;
460 VkPipelineStageFlags dstStageMask;
461 int count;
462 int index;
463 } imageBarrier;
464 struct {
465 VkPipelineStageFlags srcStageMask;
466 VkPipelineStageFlags dstStageMask;
467 int count;
468 int index;
469 } bufferBarrier;
470 struct {
471 VkImage src;
472 VkImageLayout srcLayout;
473 VkImage dst;
474 VkImageLayout dstLayout;
475 VkFilter filter;
476 VkImageBlit desc;
477 } blitImage;
478 struct {
479 VkRenderPassBeginInfo desc;
480 int clearValueIndex;
481 bool useSecondaryCb;
482 } beginRenderPass;
483 struct {
484 } endRenderPass;
485 struct {
486 VkPipelineBindPoint bindPoint;
487 VkPipeline pipeline;
488 } bindPipeline;
489 struct {
490 VkPipelineBindPoint bindPoint;
491 VkPipelineLayout pipelineLayout;
492 VkDescriptorSet descSet;
493 int dynamicOffsetCount;
494 int dynamicOffsetIndex;
495 } bindDescriptorSet;
496 struct {
497 int startBinding;
498 int count;
499 int vertexBufferIndex;
500 int vertexBufferOffsetIndex;
501 } bindVertexBuffer;
502 struct {
503 VkBuffer buf;
504 VkDeviceSize ofs;
505 VkIndexType type;
506 } bindIndexBuffer;
507 struct {
508 VkViewport viewport;
509 } setViewport;
510 struct {
511 VkRect2D scissor;
512 } setScissor;
513 struct {
514 float c[4];
515 } setBlendConstants;
516 struct {
517 uint32_t ref;
518 } setStencilRef;
519 struct {
520 uint32_t vertexCount;
521 uint32_t instanceCount;
522 uint32_t firstVertex;
523 uint32_t firstInstance;
524 } draw;
525 struct {
526 uint32_t indexCount;
527 uint32_t instanceCount;
528 uint32_t firstIndex;
529 int32_t vertexOffset;
530 uint32_t firstInstance;
531 } drawIndexed;
532 struct {
533#ifdef VK_EXT_debug_utils
534 VkDebugUtilsLabelEXT label;
535 int labelNameIndex;
536#endif
537 } debugMarkerBegin;
538 struct {
539 } debugMarkerEnd;
540 struct {
541#ifdef VK_EXT_debug_utils
542 VkDebugUtilsLabelEXT label;
543 int labelNameIndex;
544#endif
545 } debugMarkerInsert;
546 struct {
547 int trackerIndex;
548 } transitionResources;
549 struct {
550 int x, y, z;
551 } dispatch;
552 struct {
553 VkCommandBuffer cb;
554 } executeSecondary;
555 struct {
556 uint32_t w;
557 uint32_t h;
558 } setShadingRate;
559 } args;
560 };
561
562 QRhiBackendCommandList<Command> commands;
563 QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers;
564 int currentPassResTrackerIndex;
565
566 void resetCommands() {
567 commands.reset();
568 resetPools();
569
570 passResTrackers.clear();
571 currentPassResTrackerIndex = -1;
572 }
573
574 void resetPools() {
575 pools.clearValue.clear();
576 pools.bufferImageCopy.clear();
577 pools.dynamicOffset.clear();
578 pools.vertexBuffer.clear();
579 pools.vertexBufferOffset.clear();
580 pools.debugMarkerData.clear();
581 pools.imageBarrier.clear();
582 pools.bufferBarrier.clear();
583 }
584
585 struct {
586 QVarLengthArray<VkClearValue, 4> clearValue;
587 QVarLengthArray<VkBufferImageCopy, 16> bufferImageCopy;
588 QVarLengthArray<uint32_t, 4> dynamicOffset;
589 QVarLengthArray<VkBuffer, 4> vertexBuffer;
590 QVarLengthArray<VkDeviceSize, 4> vertexBufferOffset;
591 QVarLengthArray<QByteArray, 4> debugMarkerData;
592 QVarLengthArray<VkImageMemoryBarrier, 8> imageBarrier;
593 QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarrier;
594 } pools;
595
596 friend class QRhiVulkan;
597};
598
599struct QVkSwapChain : public QRhiSwapChain
600{
601 QVkSwapChain(QRhiImplementation *rhi);
602 ~QVkSwapChain();
603 void destroy() override;
604
605 QRhiCommandBuffer *currentFrameCommandBuffer() override;
606 QRhiRenderTarget *currentFrameRenderTarget() override;
607 QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
608
609 QSize surfacePixelSize() override;
610 bool isFormatSupported(Format f) override;
611 QRhiSwapChainHdrInfo hdrInfo() override;
612
613 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
614 bool createOrResize() override;
615
616 bool ensureSurface();
617
618 static const quint32 EXPECTED_MAX_BUFFER_COUNT = 4;
619
620 QWindow *window = nullptr;
621 QSize pixelSize;
622 bool supportsReadback = false;
623 bool stereo = false;
624 VkSwapchainKHR sc = VK_NULL_HANDLE;
625 int bufferCount = 0;
626 VkSurfaceKHR surface = VK_NULL_HANDLE;
627 VkSurfaceKHR lastConnectedSurface = VK_NULL_HANDLE;
628 VkFormat colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
629 VkColorSpaceKHR colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
630 QVkRenderBuffer *ds = nullptr;
631 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
632 QVarLengthArray<VkPresentModeKHR, 8> supportedPresentationModes;
633 VkDeviceMemory msaaImageMem = VK_NULL_HANDLE;
634 QVkSwapChainRenderTarget rtWrapper;
635 QVkSwapChainRenderTarget rtWrapperRight;
636 QVkCommandBuffer cbWrapper;
637 VkImageView shadingRateMapView = VK_NULL_HANDLE;
638
639 struct ImageResources {
640 VkImage image = VK_NULL_HANDLE;
641 VkImageView imageView = VK_NULL_HANDLE;
642 VkFramebuffer fb = VK_NULL_HANDLE;
643 VkImage msaaImage = VK_NULL_HANDLE;
644 VkImageView msaaImageView = VK_NULL_HANDLE;
645 VkSemaphore drawSem = VK_NULL_HANDLE;
646 enum LastUse {
647 ScImageUseNone,
648 ScImageUseRender,
649 ScImageUseTransferSource
650 };
651 LastUse lastUse = ScImageUseNone;
652 };
653 QVarLengthArray<ImageResources, EXPECTED_MAX_BUFFER_COUNT> imageRes;
654
655 struct FrameResources {
656 VkSemaphore imageSem = VK_NULL_HANDLE;
657 bool imageAcquired = false;
658 bool imageSemWaitable = false;
659 VkFence cmdFence = VK_NULL_HANDLE;
660 bool cmdFenceWaitable = false;
661 VkCommandBuffer cmdBuf = VK_NULL_HANDLE; // primary
662 int timestampQueryIndex = -1;
663 } frameRes[QVK_FRAMES_IN_FLIGHT];
664
665 quint32 currentImageIndex = 0; // index in imageRes
666 quint32 currentFrameSlot = 0; // index in frameRes
667 int frameCount = 0;
668
669 friend class QRhiVulkan;
670};
671
672class QVulkanAdapter : public QRhiAdapter
673{
674public:
675 QRhiDriverInfo info() const override;
676
677 VkPhysicalDevice physDev;
678 QRhiDriverInfo adapterInfo;
679};
680
681class QRhiVulkan : public QRhiImplementation
682{
683public:
684 QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams = nullptr);
685
686 bool create(QRhi::Flags flags) override;
687 void destroy() override;
688 QRhi::AdapterList enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles) const override;
689
690 QRhiGraphicsPipeline *createGraphicsPipeline() override;
691 QRhiComputePipeline *createComputePipeline() override;
692 QRhiShaderResourceBindings *createShaderResourceBindings() override;
693 QRhiBuffer *createBuffer(QRhiBuffer::Type type,
694 QRhiBuffer::UsageFlags usage,
695 quint32 size) override;
696 QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
697 const QSize &pixelSize,
698 int sampleCount,
699 QRhiRenderBuffer::Flags flags,
700 QRhiTexture::Format backingFormatHint) override;
701 QRhiTexture *createTexture(QRhiTexture::Format format,
702 const QSize &pixelSize,
703 int depth,
704 int arraySize,
705 int sampleCount,
706 QRhiTexture::Flags flags) override;
707 QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
708 QRhiSampler::Filter minFilter,
709 QRhiSampler::Filter mipmapMode,
710 QRhiSampler:: AddressMode u,
711 QRhiSampler::AddressMode v,
712 QRhiSampler::AddressMode w) override;
713
714 QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
715 QRhiTextureRenderTarget::Flags flags) override;
716
717 QRhiShadingRateMap *createShadingRateMap() override;
718
719 QRhiSwapChain *createSwapChain() override;
720 QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
721 QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
722 QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
723 QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
724 QRhi::FrameOpResult finish() override;
725
726 void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
727
728 void beginPass(QRhiCommandBuffer *cb,
729 QRhiRenderTarget *rt,
730 const QColor &colorClearValue,
731 const QRhiDepthStencilClearValue &depthStencilClearValue,
732 QRhiResourceUpdateBatch *resourceUpdates,
733 QRhiCommandBuffer::BeginPassFlags flags) override;
734 void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
735
736 void setGraphicsPipeline(QRhiCommandBuffer *cb,
737 QRhiGraphicsPipeline *ps) override;
738
739 void setShaderResources(QRhiCommandBuffer *cb,
740 QRhiShaderResourceBindings *srb,
741 int dynamicOffsetCount,
742 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
743
744 void setVertexInput(QRhiCommandBuffer *cb,
745 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
746 QRhiBuffer *indexBuf, quint32 indexOffset,
747 QRhiCommandBuffer::IndexFormat indexFormat) override;
748
749 void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
750 void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
751 void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
752 void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
753 void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override;
754
755 void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
756 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
757
758 void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
759 quint32 instanceCount, quint32 firstIndex,
760 qint32 vertexOffset, quint32 firstInstance) override;
761
762 void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
763 void debugMarkEnd(QRhiCommandBuffer *cb) override;
764 void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
765
766 void beginComputePass(QRhiCommandBuffer *cb,
767 QRhiResourceUpdateBatch *resourceUpdates,
768 QRhiCommandBuffer::BeginPassFlags flags) override;
769 void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
770 void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
771 void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
772
773 const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
774 void beginExternal(QRhiCommandBuffer *cb) override;
775 void endExternal(QRhiCommandBuffer *cb) override;
776 double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
777
778 QList<int> supportedSampleCounts() const override;
779 QList<QSize> supportedShadingRates(int sampleCount) const override;
780 int ubufAlignment() const override;
781 bool isYUpInFramebuffer() const override;
782 bool isYUpInNDC() const override;
783 bool isClipDepthZeroToOne() const override;
784 QMatrix4x4 clipSpaceCorrMatrix() const override;
785 bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
786 bool isFeatureSupported(QRhi::Feature feature) const override;
787 int resourceLimit(QRhi::ResourceLimit limit) const override;
788 const QRhiNativeHandles *nativeHandles() override;
789 QRhiDriverInfo driverInfo() const override;
790 QRhiStats statistics() override;
791 bool makeThreadLocalNativeContextCurrent() override;
792 void setQueueSubmitParams(QRhiNativeHandles *params) override;
793 void releaseCachedResources() override;
794 bool isDeviceLost() const override;
795
796 QByteArray pipelineCacheData() override;
797 void setPipelineCacheData(const QByteArray &data) override;
798
799 VkResult createDescriptorPool(VkDescriptorPool *pool);
800 bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex);
801 uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex);
802 bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage,
803 VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples,
804 VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count);
805
806 bool recreateSwapChain(QRhiSwapChain *swapChain);
807 void releaseSwapChainResources(QRhiSwapChain *swapChain);
808
809 VkFormat optimalDepthStencilFormat();
810 VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount);
811 bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD,
812 bool hasDepthStencil,
813 VkSampleCountFlagBits samples,
814 VkFormat colorFormat,
815 QRhiShadingRateMap *shadingRateMap);
816 bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
817 const QRhiColorAttachment *colorAttachmentsBegin,
818 const QRhiColorAttachment *colorAttachmentsEnd,
819 bool preserveColor,
820 bool preserveDs,
821 bool storeDs,
822 QRhiRenderBuffer *depthStencilBuffer,
823 QRhiTexture *depthTexture,
824 QRhiTexture *depthResolveTexture,
825 QRhiShadingRateMap *shadingRateMap);
826 bool ensurePipelineCache(const void *initialData = nullptr, size_t initialDataSize = 0);
827 VkShaderModule createShader(const QByteArray &spirv);
828
829 void prepareNewFrame(QRhiCommandBuffer *cb);
830 VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD = nullptr);
831 void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD);
832 QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb);
833 QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence,
834 VkSemaphore *waitSem, VkSemaphore *signalSem);
835 QRhi::FrameOpResult waitCommandCompletion(int frameSlot);
836 VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
837 using BufferImageCopyList = QVarLengthArray<VkBufferImageCopy, 16>;
838 void prepareUploadSubres(QVkTexture *texD, int layer, int level,
839 const QRhiTextureSubresourceUploadDescription &subresDesc,
840 size_t *curOfs, void *mp,
841 BufferImageCopyList *copyInfos);
842 void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
843 void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot);
844 void enqueueTransitionPassResources(QVkCommandBuffer *cbD);
845 void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD);
846 void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
847 QVkBuffer *bufD,
848 int slot,
849 QRhiPassResourceTracker::BufferAccess access,
850 QRhiPassResourceTracker::BufferStage stage);
851 void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker,
852 QVkTexture *texD,
853 QRhiPassResourceTracker::TextureAccess access,
854 QRhiPassResourceTracker::TextureStage stage);
855 void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker);
856 void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD);
857 void executeDeferredReleases(bool forced = false);
858 void finishActiveReadbacks(bool forced = false);
859
860 void setAllocationName(QVkAlloc allocation, const QByteArray &name, int slot = -1);
861 void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot = -1);
862 void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot,
863 VkAccessFlags access, VkPipelineStageFlags stage);
864 void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD,
865 VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage);
866 void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD);
867 void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image,
868 VkImageLayout oldLayout, VkImageLayout newLayout,
869 VkAccessFlags srcAccess, VkAccessFlags dstAccess,
870 VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
871 int startLayer, int layerCount,
872 int startLevel, int levelCount);
873 void updateShaderResourceBindings(QRhiShaderResourceBindings *srb);
874 void ensureCommandPoolForNewFrame();
875 double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok);
876 void printExtraErrorInfo(VkResult err);
877
878 QVulkanInstance *inst = nullptr;
879 QWindow *maybeWindow = nullptr;
880 QByteArrayList requestedDeviceExtensions;
881 bool importedDevice = false;
882 VkPhysicalDevice physDev = VK_NULL_HANDLE;
883 VkDevice dev = VK_NULL_HANDLE;
884 VkCommandPool cmdPool[QVK_FRAMES_IN_FLIGHT] = {};
885 quint32 gfxQueueFamilyIdx = 0;
886 quint32 gfxQueueIdx = 0;
887 VkQueue gfxQueue = VK_NULL_HANDLE;
888 quint32 timestampValidBits = 0;
889 bool importedAllocator = false;
890 QVkAllocator allocator = nullptr;
891 QVulkanFunctions *f = nullptr;
892 QVulkanDeviceFunctions *df = nullptr;
893 QRhi::Flags rhiFlags;
894 VkPhysicalDeviceFeatures physDevFeatures;
895#ifdef VK_VERSION_1_1
896 VkPhysicalDeviceMultiviewFeatures multiviewFeaturesIfApi11;
897#endif
898#ifdef VK_VERSION_1_2
899 VkPhysicalDeviceVulkan11Features physDevFeatures11IfApi12OrNewer;
900 VkPhysicalDeviceVulkan12Features physDevFeatures12;
901#endif
902#ifdef VK_VERSION_1_3
903 VkPhysicalDeviceVulkan13Features physDevFeatures13;
904#endif
905 VkPhysicalDeviceProperties physDevProperties;
906 VkDeviceSize ubufAlign;
907 VkDeviceSize texbufAlign;
908 bool deviceLost = false;
909 bool releaseCachedResourcesCalledBeforeFrameStart = false;
910
911#ifdef Q_OS_WIN
912 bool adapterLuidValid = false;
913 LUID adapterLuid;
914 QDxgiHdrInfo *dxgiHdrInfo = nullptr;
915#endif
916
917#ifdef VK_EXT_debug_utils
918 PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = nullptr;
919 PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;
920 PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr;
921 PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT = nullptr;
922#endif
923
924 PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
925 PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
926 PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
927 PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
928 PFN_vkQueuePresentKHR vkQueuePresentKHR;
929 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
930 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
931 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
932
933#ifdef VK_KHR_create_renderpass2
934 PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
935#endif
936
937 struct {
938 bool compute = false;
939 bool wideLines = false;
940 bool debugUtils = false;
941 bool vertexAttribDivisor = false;
942 bool texture3DSliceAs2D = false;
943 bool tessellation = false;
944 bool geometryShader = false;
945 bool nonFillPolygonMode = false;
946 bool multiView = false;
947 bool renderPass2KHR = false;
948 bool depthStencilResolveKHR = false;
949 bool perDrawShadingRate = false;
950 bool imageBasedShadingRate = false;
951 QVersionNumber apiVersion;
952 int imageBasedShadingRateTileSize = 0;
953 } caps;
954
955 VkPipelineCache pipelineCache = VK_NULL_HANDLE;
956 struct DescriptorPoolData {
957 DescriptorPoolData() { }
958 DescriptorPoolData(VkDescriptorPool pool_)
959 : pool(pool_)
960 { }
961 VkDescriptorPool pool = VK_NULL_HANDLE;
962 int refCount = 0;
963 int allocedDescSets = 0;
964 };
965 QVarLengthArray<DescriptorPoolData, 8> descriptorPools;
966 QVarLengthArray<VkCommandBuffer, 4> freeSecondaryCbs[QVK_FRAMES_IN_FLIGHT];
967
968 VkQueryPool timestampQueryPool = VK_NULL_HANDLE;
969 QBitArray timestampQueryPoolMap;
970
971 VkFormat optimalDsFormat = VK_FORMAT_UNDEFINED;
972 QMatrix4x4 clipCorrectMatrix;
973
974 QVkSwapChain *currentSwapChain = nullptr;
975 QSet<QVkSwapChain *> swapchains;
976 QRhiVulkanNativeHandles nativeHandlesStruct;
977 QRhiDriverInfo driverInfoStruct;
978
979 struct OffscreenFrame {
980 OffscreenFrame(QRhiImplementation *rhi)
981 {
982 for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
983 cbWrapper[i] = new QVkCommandBuffer(rhi);
984 }
985 ~OffscreenFrame()
986 {
987 for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
988 delete cbWrapper[i];
989 }
990 bool active = false;
991 QVkCommandBuffer *cbWrapper[QVK_FRAMES_IN_FLIGHT];
992 VkFence cmdFence = VK_NULL_HANDLE;
993 int timestampQueryIndex = -1;
994 } ofr;
995
996 struct TextureReadback {
997 int activeFrameSlot = -1;
998 QRhiReadbackDescription desc;
999 QRhiReadbackResult *result;
1000 VkBuffer stagingBuf;
1001 QVkAlloc stagingAlloc;
1002 quint32 byteSize;
1003 QRect rect;
1004 QRhiTexture::Format format;
1005 };
1006 QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
1007 struct BufferReadback {
1008 int activeFrameSlot = -1;
1009 QRhiReadbackResult *result;
1010 quint32 byteSize;
1011 VkBuffer stagingBuf;
1012 QVkAlloc stagingAlloc;
1013 };
1014 QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
1015
1016 struct DeferredReleaseEntry {
1017 enum Type {
1018 Pipeline,
1019 ShaderResourceBindings,
1020 Buffer,
1021 RenderBuffer,
1022 Texture,
1023 Sampler,
1024 TextureRenderTarget,
1025 RenderPass,
1026 StagingBuffer,
1027 SecondaryCommandBuffer
1028 };
1029 Type type;
1030 int lastActiveFrameSlot; // -1 if not used otherwise 0..FRAMES_IN_FLIGHT-1
1031 union {
1032 struct {
1033 VkPipeline pipeline;
1034 VkPipelineLayout layout;
1035 } pipelineState;
1036 struct {
1037 int poolIndex;
1038 VkDescriptorSetLayout layout;
1039 } shaderResourceBindings;
1040 struct {
1041 VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
1042 QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
1043 VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
1044 QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
1045 } buffer;
1046 struct {
1047 VkDeviceMemory memory;
1048 VkImage image;
1049 VkImageView imageView;
1050 } renderBuffer;
1051 struct {
1052 VkImage image;
1053 VkImageView imageView;
1054 QVkAlloc allocation;
1055 VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
1056 QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
1057 VkImageView extraImageViews[QRhi::MAX_MIP_LEVELS];
1058 } texture;
1059 struct {
1060 VkSampler sampler;
1061 } sampler;
1062 struct {
1063 VkFramebuffer fb;
1064 VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
1065 VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
1066 VkImageView dsv;
1067 VkImageView resdsv;
1068 VkImageView shadingRateMapView;
1069 } textureRenderTarget;
1070 struct {
1071 VkRenderPass rp;
1072 } renderPass;
1073 struct {
1074 VkBuffer stagingBuffer;
1075 QVkAlloc stagingAllocation;
1076 } stagingBuffer;
1077 struct {
1078 VkCommandBuffer cb;
1079 } secondaryCommandBuffer;
1080 };
1081 };
1082 QList<DeferredReleaseEntry> releaseQueue;
1083
1084#ifdef VK_KHR_fragment_shading_rate
1085 QVarLengthArray<VkPhysicalDeviceFragmentShadingRateKHR, 8> fragmentShadingRates;
1086 PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR = nullptr;
1087#endif
1088
1089 QVarLengthArray<VkSemaphore, 4> waitSemaphoresForQueueSubmit;
1090 QVarLengthArray<VkPipelineStageFlags, 4> semaphoresWaitMasksForQueueSubmit;
1091 QVarLengthArray<VkSemaphore, 4> signalSemaphoresForQueueSubmit;
1092 QVarLengthArray<VkSemaphore, 4> waitSemaphoresForPresent;
1093};
1094
1095Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_RELOCATABLE_TYPE);
1096Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_RELOCATABLE_TYPE);
1097Q_DECLARE_TYPEINFO(QRhiVulkan::TextureReadback, Q_RELOCATABLE_TYPE);
1098Q_DECLARE_TYPEINFO(QRhiVulkan::BufferReadback, Q_RELOCATABLE_TYPE);
1099
1100QT_END_NAMESPACE
1101
1102#endif
1103

source code of qtbase/src/gui/rhi/qrhivulkan_p.h