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