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