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