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 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | class QVulkanFunctions; |
57 | class QVulkanDeviceFunctions; |
58 | |
59 | static const int QVK_FRAMES_IN_FLIGHT = 2; |
60 | |
61 | static const int QVK_DESC_SETS_PER_POOL = 128; |
62 | static const int QVK_UNIFORM_BUFFERS_PER_POOL = 256; |
63 | static const int QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL = 256; |
64 | static const int QVK_STORAGE_BUFFERS_PER_POOL = 128; |
65 | static const int QVK_STORAGE_IMAGES_PER_POOL = 128; |
66 | |
67 | static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS = 16; |
68 | |
69 | // no vk_mem_alloc.h available here, void* is good enough |
70 | typedef void * QVkAlloc; |
71 | typedef void * QVkAllocator; |
72 | |
73 | struct 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 | |
102 | Q_DECLARE_TYPEINFO(QVkBuffer::DynamicUpdate, Q_MOVABLE_TYPE); |
103 | |
104 | struct QVkTexture; |
105 | |
106 | struct 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 | |
126 | struct 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 | |
165 | struct 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 | |
179 | struct 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 | |
198 | struct 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 | |
211 | struct 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 | |
224 | struct 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 | |
244 | struct 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 | |
297 | Q_DECLARE_TYPEINFO(QVkShaderResourceBindings::BoundResourceData, Q_MOVABLE_TYPE); |
298 | |
299 | struct 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 | |
313 | struct 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 | |
327 | struct 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 | |
584 | struct 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 | |
653 | class QRhiVulkan : public QRhiImplementation |
654 | { |
655 | public: |
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 [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 | |
994 | Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_MOVABLE_TYPE); |
995 | Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_MOVABLE_TYPE); |
996 | Q_DECLARE_TYPEINFO(QRhiVulkan::TextureReadback, Q_MOVABLE_TYPE); |
997 | Q_DECLARE_TYPEINFO(QRhiVulkan::BufferReadback, Q_MOVABLE_TYPE); |
998 | |
999 | QT_END_NAMESPACE |
1000 | |
1001 | #endif |
1002 | |