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