Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qrhid3d12_p.h
Go to the documentation of this file.
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 QRHID3D12_P_H
5#define QRHID3D12_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#include <QWindow>
20#include <QBitArray>
21
22#include <optional>
23#include <array>
24
25#include <d3d12.h>
26#include <d3d12sdklayers.h>
27#include <dxgi1_6.h>
28#include <dcomp.h>
29
30#include "D3D12MemAlloc.h"
31
32// ID3D12Device2 and ID3D12GraphicsCommandList1 and types and enums introduced
33// with those are hard requirements now. These should be declared in any
34// moderately recent d3d12.h, but if it is an SDK from before Windows 10
35// version 1703 then these types could be missing. In the absence of other
36// options, handle this by skipping all the code and making QRhi::create() fail
37// in such builds.
38#ifdef __ID3D12Device2_INTERFACE_DEFINED__
39#define QRHI_D3D12_AVAILABLE
40
41// Will use ID3D12GraphicsCommandList5 as long as the d3d12.h is new enough.
42// Otherwise, some features (VRS) will not be available.
43#ifdef __ID3D12GraphicsCommandList5_INTERFACE_DEFINED__
44#define QRHI_D3D12_CL5_AVAILABLE
45using D3D12GraphicsCommandList = ID3D12GraphicsCommandList5;
46#else
47using D3D12GraphicsCommandList = ID3D12GraphicsCommandList1;
48#endif
49
50QT_BEGIN_NAMESPACE
51
52static const int QD3D12_FRAMES_IN_FLIGHT = 2;
53
54class QRhiD3D12;
55
56struct QD3D12Descriptor
57{
58 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
59 D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
60
61 bool isValid() const { return cpuHandle.ptr != 0; }
62};
63
64struct QD3D12ReleaseQueue;
65
66struct QD3D12DescriptorHeap
67{
68 bool isValid() const { return heap && capacity; }
69 bool create(ID3D12Device *device,
70 quint32 descriptorCount,
71 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
72 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags);
73 void createWithExisting(const QD3D12DescriptorHeap &other,
74 quint32 offsetInDescriptors,
75 quint32 descriptorCount);
76 void destroy();
77 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
78
79 QD3D12Descriptor get(quint32 count);
80 QD3D12Descriptor at(quint32 index) const;
81 quint32 remainingCapacity() const { return capacity - head; }
82
83 QD3D12Descriptor incremented(const QD3D12Descriptor &descriptor, quint32 offsetInDescriptors) const
84 {
85 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.cpuHandle;
86 cpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
87 D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = descriptor.gpuHandle;
88 if (gpuHandle.ptr)
89 gpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
90 return { cpuHandle, gpuHandle };
91 }
92
93 ID3D12DescriptorHeap *heap = nullptr;
94 quint32 capacity = 0;
95 QD3D12Descriptor heapStart;
96 quint32 head = 0;
97 quint32 descriptorByteSize = 0;
98 D3D12_DESCRIPTOR_HEAP_TYPE heapType;
99 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags;
100};
101
102struct QD3D12CpuDescriptorPool
103{
104 bool isValid() const { return !heaps.isEmpty(); }
105 bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType, const char *debugName = "");
106 void destroy();
107
108 QD3D12Descriptor allocate(quint32 count);
109 void release(const QD3D12Descriptor &descriptor, quint32 count);
110
111 static const int DESCRIPTORS_PER_HEAP = 256;
112
113 struct HeapWithMap {
114 QD3D12DescriptorHeap heap;
115 QBitArray map;
116 static HeapWithMap init(const QD3D12DescriptorHeap &heap, quint32 descriptorCount) {
117 HeapWithMap result;
118 result.heap = heap;
119 result.map.resize(descriptorCount);
120 return result;
121 }
122 };
123
124 ID3D12Device *device;
125 quint32 descriptorByteSize;
126 QVector<HeapWithMap> heaps;
127 const char *debugName;
128};
129
130struct QD3D12QueryHeap
131{
132 bool isValid() const { return heap && capacity; }
133 bool create(ID3D12Device *device,
134 quint32 queryCount,
135 D3D12_QUERY_HEAP_TYPE heapType);
136 void destroy();
137
138 ID3D12QueryHeap *heap = nullptr;
139 quint32 capacity = 0;
140};
141
142struct QD3D12StagingArea
143{
144 static const quint32 ALIGNMENT = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; // 512 so good enough both for cb and texdata
145
146 struct Allocation {
147 quint8 *p = nullptr;
148 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = 0;
149 ID3D12Resource *buffer = nullptr;
150 quint32 bufferOffset = 0;
151 bool isValid() const { return p != nullptr; }
152 };
153
154 bool isValid() const { return allocation && mem.isValid(); }
155 bool create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType);
156 void destroy();
157 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
158
159 Allocation get(quint32 byteSize);
160
161 quint32 remainingCapacity() const
162 {
163 return capacity - head;
164 }
165
166 static quint32 allocSizeForArray(quint32 size, int count = 1)
167 {
168 return count * ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
169 }
170
171 Allocation mem;
172 ID3D12Resource *resource = nullptr;
173 D3D12MA::Allocation *allocation = nullptr;
174 quint32 head;
175 quint32 capacity;
176};
177
178struct QD3D12ObjectHandle
179{
180 quint32 index = 0;
181 quint32 generation = 0;
182
183 // the default, null handle is guaranteed to give ObjectPool::isValid() == false
184 bool isNull() const { return index == 0 && generation == 0; }
185};
186
187inline bool operator==(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
188{
189 return a.index == b.index && a.generation == b.generation;
190}
191
192inline bool operator!=(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
193{
194 return !(a == b);
195}
196
197template<typename T>
198struct QD3D12ObjectPool
199{
200 void create(const char *debugName = "")
201 {
202 this->debugName = debugName;
203 Q_ASSERT(data.isEmpty());
204 data.append(Data()); // index 0 is always invalid
205 }
206
207 void destroy() {
208 int leakCount = 0; // will nicely destroy everything here, but warn about it if enabled
209 for (Data &d : data) {
210 if (d.object.has_value()) {
211 leakCount += 1;
212 d.object->releaseResources();
213 }
214 }
215 data.clear();
216#ifndef QT_NO_DEBUG
217 // debug builds: just do it always
218 static bool leakCheck = true;
219#else
220 // release builds: opt-in
221 static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK");
222#endif
223 if (leakCheck) {
224 if (leakCount > 0) {
225 qWarning("QD3D12ObjectPool::destroy(): Pool %p '%s' had %d unreleased objects",
226 this, debugName, leakCount);
227 }
228 }
229 }
230
231 bool isValid(const QD3D12ObjectHandle &handle) const
232 {
233 return handle.index > 0
234 && handle.index < quint32(data.count())
235 && handle.generation > 0
236 && handle.generation == data[handle.index].generation
237 && data[handle.index].object.has_value();
238 }
239
240 T lookup(const QD3D12ObjectHandle &handle) const
241 {
242 return isValid(handle) ? *data[handle.index].object : T();
243 }
244
245 const T *lookupRef(const QD3D12ObjectHandle &handle) const
246 {
247 return isValid(handle) ? &*data[handle.index].object : nullptr;
248 }
249
250 T *lookupRef(const QD3D12ObjectHandle &handle)
251 {
252 return isValid(handle) ? &*data[handle.index].object : nullptr;
253 }
254
255 QD3D12ObjectHandle add(const T &object)
256 {
257 Q_ASSERT(!data.isEmpty());
258 const quint32 count = quint32(data.count());
259 quint32 index = 1; // index 0 is always invalid
260 for (; index < count; ++index) {
261 if (!data[index].object.has_value())
262 break;
263 }
264 if (index < count) {
265 data[index].object = object;
266 quint32 &generation = data[index].generation;
267 generation += 1u;
268 return { index, generation };
269 } else {
270 data.append({ object, 1 });
271 return { count, 1 };
272 }
273 }
274
275 void remove(const QD3D12ObjectHandle &handle)
276 {
277 if (T *object = lookupRef(handle)) {
278 object->releaseResources();
279 data[handle.index].object.reset();
280 }
281 }
282
283 const char *debugName;
284 struct Data {
285 std::optional<T> object;
286 quint32 generation = 0;
287 };
288 QVector<Data> data;
289};
290
291struct QD3D12Resource
292{
293 ID3D12Resource *resource;
294 D3D12_RESOURCE_STATES state;
295 D3D12_RESOURCE_DESC desc;
296 D3D12MA::Allocation *allocation;
297 void *cpuMapPtr;
298 enum { UavUsageRead = 0x01, UavUsageWrite = 0x02 };
299 int uavUsage;
300 bool owns;
301
302 // note that this assumes the allocation (if there is one) and the resource
303 // are separately releaseable, see D3D12MemAlloc docs
304 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
305 ID3D12Resource *resource,
306 D3D12_RESOURCE_STATES state,
307 D3D12MA::Allocation *allocation = nullptr,
308 void *cpuMapPtr = nullptr)
309 {
310 Q_ASSERT(resource);
311 return pool->add({ resource, state, resource->GetDesc(), allocation, cpuMapPtr, 0, true });
312 }
313
314 // for QRhiTexture::createFrom() where the ID3D12Resource is not owned by us
315 static QD3D12ObjectHandle addNonOwningToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
316 ID3D12Resource *resource,
317 D3D12_RESOURCE_STATES state)
318 {
319 Q_ASSERT(resource);
320 return pool->add({ resource, state, resource->GetDesc(), nullptr, nullptr, 0, false });
321 }
322
323 void releaseResources()
324 {
325 if (owns) {
326 // order matters: resource first, then the allocation
327 resource->Release();
328 if (allocation)
329 allocation->Release();
330 }
331 }
332};
333
334struct QD3D12Pipeline
335{
336 enum Type {
337 Graphics,
338 Compute
339 };
340 Type type;
341 ID3D12PipelineState *pso;
342
343 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Pipeline> *pool,
344 Type type,
345 ID3D12PipelineState *pso)
346 {
347 return pool->add({ type, pso });
348 }
349
350 void releaseResources()
351 {
352 pso->Release();
353 }
354};
355
356struct QD3D12RootSignature
357{
358 ID3D12RootSignature *rootSig;
359
360 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12RootSignature> *pool,
361 ID3D12RootSignature *rootSig)
362 {
363 return pool->add({ rootSig });
364 }
365
366 void releaseResources()
367 {
368 rootSig->Release();
369 }
370};
371
372struct QD3D12ReleaseQueue
373{
374 void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool,
375 QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool,
376 QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool)
377 {
378 this->resourcePool = resourcePool;
379 this->pipelinePool = pipelinePool;
380 this->rootSignaturePool = rootSignaturePool;
381 }
382
383 void deferredReleaseResource(const QD3D12ObjectHandle &handle);
384 void deferredReleaseResourceWithViews(const QD3D12ObjectHandle &handle,
385 QD3D12CpuDescriptorPool *pool,
386 const QD3D12Descriptor &viewsStart,
387 int viewCount);
388 void deferredReleasePipeline(const QD3D12ObjectHandle &handle);
389 void deferredReleaseRootSignature(const QD3D12ObjectHandle &handle);
390 void deferredReleaseCallback(std::function<void(void*)> callback, void *userData);
391 void deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
392 D3D12MA::Allocation *allocation);
393 void deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap);
394 void deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
395 const QD3D12Descriptor &viewsStart,
396 int viewCount);
397
398 void activatePendingDeferredReleaseRequests(int frameSlot);
399 void executeDeferredReleases(int frameSlot, bool forced = false);
400 void releaseAll();
401
402 struct DeferredReleaseEntry {
403 enum Type {
404 Resource,
405 Pipeline,
406 RootSignature,
407 Callback,
408 ResourceAndAllocation,
409 DescriptorHeap,
410 Views
411 };
412 Type type = Resource;
413 std::optional<int> frameSlotToBeReleasedIn;
414 QD3D12ObjectHandle handle;
415 QD3D12CpuDescriptorPool *poolForViews = nullptr;
416 QD3D12Descriptor viewsStart;
417 int viewCount = 0;
418 std::function<void(void*)> callback = nullptr;
419 void *callbackUserData = nullptr;
420 std::pair<ID3D12Resource *, D3D12MA::Allocation *> resourceAndAllocation = {};
421 ID3D12DescriptorHeap *descriptorHeap = nullptr;
422 };
423 QVector<DeferredReleaseEntry> queue;
424 QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
425 QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool = nullptr;
426 QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool = nullptr;
427};
428
429struct QD3D12CommandBuffer;
430
431struct QD3D12ResourceBarrierGenerator
432{
433 static const int PREALLOC = 16;
434
435 void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool)
436 {
437 this->resourcePool = resourcePool;
438 }
439
440 void addTransitionBarrier(const QD3D12ObjectHandle &resourceHandle, D3D12_RESOURCE_STATES stateAfter);
441 void enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD);
442 void enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
443 const QD3D12ObjectHandle &resourceHandle,
444 UINT subresource,
445 D3D12_RESOURCE_STATES stateBefore,
446 D3D12_RESOURCE_STATES stateAfter);
447 void enqueueUavBarrier(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &resourceHandle);
448
449 struct TransitionResourceBarrier {
450 QD3D12ObjectHandle resourceHandle;
451 D3D12_RESOURCE_STATES stateBefore;
452 D3D12_RESOURCE_STATES stateAfter;
453 };
454 QVarLengthArray<TransitionResourceBarrier, PREALLOC> transitionResourceBarriers;
455 QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
456};
457
458struct QD3D12ShaderBytecodeCache
459{
460 struct Shader {
461 Shader() = default;
462 Shader(const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
463 : bytecode(bytecode), nativeResourceBindingMap(rbm)
464 { }
465 QByteArray bytecode;
466 QShader::NativeResourceBindingMap nativeResourceBindingMap;
467 };
468
469 QHash<QRhiShaderStage, Shader> data;
470
471 void insertWithCapacityLimit(const QRhiShaderStage &key, const Shader &s);
472};
473
474struct QD3D12ShaderVisibleDescriptorHeap
475{
476 bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type, quint32 perFrameDescriptorCount);
477 void destroy();
478 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
479
480 QD3D12DescriptorHeap heap;
481 QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
482};
483
484// wrap foreign struct so we can legally supply equality operators and qHash:
485struct Q_D3D12_SAMPLER_DESC
486{
487 D3D12_SAMPLER_DESC desc;
488
489 friend bool operator==(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
490 {
491 return lhs.desc.Filter == rhs.desc.Filter
492 && lhs.desc.AddressU == rhs.desc.AddressU
493 && lhs.desc.AddressV == rhs.desc.AddressV
494 && lhs.desc.AddressW == rhs.desc.AddressW
495 && lhs.desc.MipLODBias == rhs.desc.MipLODBias
496 && lhs.desc.MaxAnisotropy == rhs.desc.MaxAnisotropy
497 && lhs.desc.ComparisonFunc == rhs.desc.ComparisonFunc
498 // BorderColor is never used, skip it
499 && lhs.desc.MinLOD == rhs.desc.MinLOD
500 && lhs.desc.MaxLOD == rhs.desc.MaxLOD;
501 }
502
503 friend bool operator!=(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
504 {
505 return !(lhs == rhs);
506 }
507
508 friend size_t qHash(const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0) noexcept
509 {
510 QtPrivate::QHashCombine hash(seed);
511 seed = hash(seed, key.desc.Filter);
512 seed = hash(seed, key.desc.AddressU);
513 seed = hash(seed, key.desc.AddressV);
514 seed = hash(seed, key.desc.AddressW);
515 seed = hash(seed, key.desc.MipLODBias);
516 seed = hash(seed, key.desc.MaxAnisotropy);
517 seed = hash(seed, key.desc.ComparisonFunc);
518 // BorderColor is never used, skip it
519 seed = hash(seed, key.desc.MinLOD);
520 seed = hash(seed, key.desc.MaxLOD);
521 return seed;
522 }
523};
524
525struct QD3D12SamplerManager
526{
527 const quint32 MAX_SAMPLERS = 512;
528
529 bool create(ID3D12Device *device);
530 void destroy();
531
532 QD3D12Descriptor getShaderVisibleDescriptor(const D3D12_SAMPLER_DESC &desc);
533
534 ID3D12Device *device = nullptr;
535 QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
536 QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
537};
538
539enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };
540
541static inline QD3D12Stage qd3d12_stage(QRhiShaderStage::Type type)
542{
543 switch (type) {
544 case QRhiShaderStage::Vertex:
545 return VS;
546 case QRhiShaderStage::TessellationControl:
547 return HS;
548 case QRhiShaderStage::TessellationEvaluation:
549 return DS;
550 case QRhiShaderStage::Geometry:
551 return GS;
552 case QRhiShaderStage::Fragment:
553 return PS;
554 case QRhiShaderStage::Compute:
555 return CS;
556 }
557 Q_UNREACHABLE_RETURN(VS);
558}
559
560static inline D3D12_SHADER_VISIBILITY qd3d12_stageToVisibility(QD3D12Stage s)
561{
562 switch (s) {
563 case VS:
564 return D3D12_SHADER_VISIBILITY_VERTEX;
565 case HS:
566 return D3D12_SHADER_VISIBILITY_HULL;
567 case DS:
568 return D3D12_SHADER_VISIBILITY_DOMAIN;
569 case GS:
570 return D3D12_SHADER_VISIBILITY_GEOMETRY;
571 case PS:
572 return D3D12_SHADER_VISIBILITY_PIXEL;
573 case CS:
574 return D3D12_SHADER_VISIBILITY_ALL;
575 }
576 Q_UNREACHABLE_RETURN(D3D12_SHADER_VISIBILITY_ALL);
577}
578
579static inline QRhiShaderResourceBinding::StageFlag qd3d12_stageToSrb(QD3D12Stage s)
580{
581 switch (s) {
582 case VS:
583 return QRhiShaderResourceBinding::VertexStage;
584 case HS:
585 return QRhiShaderResourceBinding::TessellationControlStage;
586 case DS:
587 return QRhiShaderResourceBinding::TessellationEvaluationStage;
588 case GS:
589 return QRhiShaderResourceBinding::GeometryStage;
590 case PS:
591 return QRhiShaderResourceBinding::FragmentStage;
592 case CS:
593 return QRhiShaderResourceBinding::ComputeStage;
594 }
595 Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::VertexStage);
596}
597
598struct QD3D12ShaderStageData
599{
600 bool valid = false; // to allow simple arrays where unused stages are indicated by !valid
601 QD3D12Stage stage = VS;
602 QShader::NativeResourceBindingMap nativeResourceBindingMap;
603};
604
605struct QD3D12ShaderResourceBindings;
606
607struct QD3D12ShaderResourceVisitor
608{
609 enum StorageOp { Load = 0, Store, LoadStore };
610
611 QD3D12ShaderResourceVisitor(const QD3D12ShaderResourceBindings *srb,
612 const QD3D12ShaderStageData *stageData,
613 int stageCount)
614 : srb(srb),
615 stageData(stageData),
616 stageCount(stageCount)
617 {
618 }
619
620 std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::UniformBufferData &, int, int)> uniformBuffer = nullptr;
621 std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> texture = nullptr;
622 std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> sampler = nullptr;
623 std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageImageData &, StorageOp, int)> storageImage = nullptr;
624 std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageBufferData &, StorageOp, int)> storageBuffer = nullptr;
625
626 void visit();
627
628 const QD3D12ShaderResourceBindings *srb;
629 const QD3D12ShaderStageData *stageData;
630 int stageCount;
631};
632
633struct QD3D12Readback
634{
635 // common
636 int frameSlot = -1;
637 QRhiReadbackResult *result = nullptr;
638 QD3D12StagingArea staging;
639 quint32 byteSize = 0;
640 // textures
641 quint32 bytesPerLine = 0;
642 QSize pixelSize;
643 QRhiTexture::Format format = QRhiTexture::UnknownFormat;
644 quint32 stagingRowPitch = 0;
645};
646
647struct QD3D12MipmapGenerator
648{
649 bool create(QRhiD3D12 *rhiD);
650 void destroy();
651 void generate(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &textureHandle);
652
653 QRhiD3D12 *rhiD;
654 QD3D12ObjectHandle rootSigHandle;
655 QD3D12ObjectHandle pipelineHandle;
656};
657
658struct QD3D12MipmapGenerator3D
659{
660 bool create(QRhiD3D12 *rhiD);
661 void destroy();
662 void generate(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &textureHandle);
663
664 QRhiD3D12 *rhiD;
665 QD3D12ObjectHandle rootSigHandle;
666 QD3D12ObjectHandle pipelineHandle;
667};
668
669struct QD3D12MemoryAllocator
670{
671 bool create(ID3D12Device *device, IDXGIAdapter1 *adapter);
672 void destroy();
673
674 HRESULT createResource(D3D12_HEAP_TYPE heapType,
675 const D3D12_RESOURCE_DESC *resourceDesc,
676 D3D12_RESOURCE_STATES initialState,
677 const D3D12_CLEAR_VALUE *optimizedClearValue,
678 D3D12MA::Allocation **maybeAllocation,
679 REFIID riidResource,
680 void **ppvResource);
681
682 void getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget);
683
684 bool isUsingD3D12MA() const { return allocator != nullptr; }
685
686 ID3D12Device *device = nullptr;
687 D3D12MA::Allocator *allocator = nullptr;
688};
689
690struct QD3D12Buffer : public QRhiBuffer
691{
692 QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
693 ~QD3D12Buffer();
694
695 void destroy() override;
696 bool create() override;
697 QRhiBuffer::NativeBuffer nativeBuffer() override;
698 char *beginFullDynamicBufferUpdateForCurrentFrame() override;
699 void endFullDynamicBufferUpdateForCurrentFrame() override;
700
701 void executeHostWritesForFrameSlot(int frameSlot);
702
703 QD3D12ObjectHandle handles[QD3D12_FRAMES_IN_FLIGHT] = {};
704 struct HostWrite {
705 quint32 offset;
706 QRhiBufferData data;
707 };
708 QVarLengthArray<HostWrite, 16> pendingHostWrites[QD3D12_FRAMES_IN_FLIGHT];
709 friend class QRhiD3D12;
710 friend struct QD3D12CommandBuffer;
711};
712
713struct QD3D12RenderBuffer : public QRhiRenderBuffer
714{
715 QD3D12RenderBuffer(QRhiImplementation *rhi,
716 Type type,
717 const QSize &pixelSize,
718 int sampleCount,
719 Flags flags,
720 QRhiTexture::Format backingFormatHint);
721 ~QD3D12RenderBuffer();
722 void destroy() override;
723 bool create() override;
724 QRhiTexture::Format backingFormat() const override;
725
726 static const DXGI_FORMAT DS_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT;
727
728 QD3D12ObjectHandle handle;
729 QD3D12Descriptor rtv;
730 QD3D12Descriptor dsv;
731 DXGI_FORMAT dxgiFormat;
732 DXGI_SAMPLE_DESC sampleDesc;
733 uint generation = 0;
734 friend class QRhiD3D12;
735};
736
737struct QD3D12Texture : public QRhiTexture
738{
739 QD3D12Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
740 int arraySize, int sampleCount, Flags flags);
741 ~QD3D12Texture();
742 void destroy() override;
743 bool create() override;
744 bool createFrom(NativeTexture src) override;
745 NativeTexture nativeTexture() override;
746 void setNativeLayout(int layout) override;
747
748 bool prepareCreate(QSize *adjustedSize = nullptr);
749 bool finishCreate();
750
751 QD3D12ObjectHandle handle;
752 QD3D12Descriptor srv;
753 DXGI_FORMAT dxgiFormat;
754 DXGI_FORMAT srvFormat;
755 DXGI_FORMAT rtFormat; // RTV/DSV/UAV
756 uint mipLevelCount;
757 DXGI_SAMPLE_DESC sampleDesc;
758 uint generation = 0;
759 friend class QRhiD3D12;
760 friend struct QD3D12CommandBuffer;
761};
762
763struct QD3D12Sampler : public QRhiSampler
764{
765 QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
766 AddressMode u, AddressMode v, AddressMode w);
767 ~QD3D12Sampler();
768 void destroy() override;
769 bool create() override;
770
771 QD3D12Descriptor lookupOrCreateShaderVisibleDescriptor();
772
773 D3D12_SAMPLER_DESC desc = {};
774 QD3D12Descriptor shaderVisibleDescriptor;
775};
776
777struct QD3D12ShadingRateMap : public QRhiShadingRateMap
778{
779 QD3D12ShadingRateMap(QRhiImplementation *rhi);
780 ~QD3D12ShadingRateMap();
781 void destroy() override;
782 bool createFrom(QRhiTexture *src) override;
783
784 QD3D12ObjectHandle handle; // just copied from the texture
785 friend class QRhiD3D12;
786};
787
788struct QD3D12RenderPassDescriptor : public QRhiRenderPassDescriptor
789{
790 QD3D12RenderPassDescriptor(QRhiImplementation *rhi);
791 ~QD3D12RenderPassDescriptor();
792 void destroy() override;
793 bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
794 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
795 QVector<quint32> serializedFormat() const override;
796
797 void updateSerializedFormat();
798
799 static const int MAX_COLOR_ATTACHMENTS = 8;
800 int colorAttachmentCount = 0;
801 bool hasDepthStencil = false;
802 int colorFormat[MAX_COLOR_ATTACHMENTS];
803 int dsFormat;
804 bool hasShadingRateMap = false;
805 QVector<quint32> serializedFormatData;
806};
807
808struct QD3D12RenderTargetData
809{
810 QD3D12RenderTargetData(QRhiImplementation *) { }
811
812 QD3D12RenderPassDescriptor *rp = nullptr;
813 QSize pixelSize;
814 float dpr = 1;
815 int sampleCount = 1;
816 int colorAttCount = 0;
817 int dsAttCount = 0;
818 QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
819 static const int MAX_COLOR_ATTACHMENTS = QD3D12RenderPassDescriptor::MAX_COLOR_ATTACHMENTS;
820 D3D12_CPU_DESCRIPTOR_HANDLE rtv[MAX_COLOR_ATTACHMENTS];
821 D3D12_CPU_DESCRIPTOR_HANDLE dsv;
822};
823
824struct QD3D12SwapChainRenderTarget : public QRhiSwapChainRenderTarget
825{
826 QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
827 ~QD3D12SwapChainRenderTarget();
828 void destroy() override;
829
830 QSize pixelSize() const override;
831 float devicePixelRatio() const override;
832 int sampleCount() const override;
833
834 QD3D12RenderTargetData d;
835};
836
837struct QD3D12TextureRenderTarget : public QRhiTextureRenderTarget
838{
839 QD3D12TextureRenderTarget(QRhiImplementation *rhi,
840 const QRhiTextureRenderTargetDescription &desc,
841 Flags flags);
842 ~QD3D12TextureRenderTarget();
843 void destroy() override;
844
845 QSize pixelSize() const override;
846 float devicePixelRatio() const override;
847 int sampleCount() const override;
848
849 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
850 bool create() override;
851
852 QD3D12RenderTargetData d;
853 bool ownsRtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
854 QD3D12Descriptor rtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
855 bool ownsDsv = false;
856 QD3D12Descriptor dsv;
857 friend class QRhiD3D12;
858};
859
860struct QD3D12GraphicsPipeline;
861struct QD3D12ComputePipeline;
862
863struct QD3D12ShaderResourceBindings : public QRhiShaderResourceBindings
864{
865 QD3D12ShaderResourceBindings(QRhiImplementation *rhi);
866 ~QD3D12ShaderResourceBindings();
867 void destroy() override;
868 bool create() override;
869 void updateResources(UpdateFlags flags) override;
870
871 QD3D12ObjectHandle createRootSignature(const QD3D12ShaderStageData *stageData, int stageCount);
872
873 struct VisitorData {
874 QVarLengthArray<D3D12_ROOT_PARAMETER1, 2> cbParams[6];
875
876 D3D12_ROOT_PARAMETER1 srvTables[6] = {};
877 QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> srvRanges[6];
878 quint32 currentSrvRangeOffset[6] = {};
879
880 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> samplerTables[6];
881 std::array<D3D12_DESCRIPTOR_RANGE1, 16> samplerRanges[6] = {};
882 int samplerRangeHeads[6] = {};
883
884 D3D12_ROOT_PARAMETER1 uavTables[6] = {};
885 QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> uavRanges[6];
886 quint32 currentUavRangeOffset[6] = {};
887 } visitorData;
888
889
890 void visitUniformBuffer(QD3D12Stage s,
891 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
892 int shaderRegister,
893 int binding);
894 void visitTexture(QD3D12Stage s,
895 const QRhiShaderResourceBinding::TextureAndSampler &d,
896 int shaderRegister);
897 void visitSampler(QD3D12Stage s,
898 const QRhiShaderResourceBinding::TextureAndSampler &d,
899 int shaderRegister);
900 void visitStorageBuffer(QD3D12Stage s,
901 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
902 QD3D12ShaderResourceVisitor::StorageOp op,
903 int shaderRegister);
904 void visitStorageImage(QD3D12Stage s,
905 const QRhiShaderResourceBinding::Data::StorageImageData &d,
906 QD3D12ShaderResourceVisitor::StorageOp op,
907 int shaderRegister);
908
909 bool hasDynamicOffset = false;
910 uint generation = 0;
911 QD3D12GraphicsPipeline *lastUsedGraphicsPipeline = nullptr;
912 QD3D12ComputePipeline *lastUsedComputePipeline = nullptr;
913
914 friend class QRhiD3D12;
915 friend struct QD3D12ShaderResourceVisitor;
916};
917
918struct QD3D12GraphicsPipeline : public QRhiGraphicsPipeline
919{
920 QD3D12GraphicsPipeline(QRhiImplementation *rhi);
921 ~QD3D12GraphicsPipeline();
922 void destroy() override;
923 bool create() override;
924
925 QD3D12ObjectHandle handle;
926 QD3D12ObjectHandle rootSigHandle;
927 std::array<QD3D12ShaderStageData, 5> stageData;
928 D3D12_PRIMITIVE_TOPOLOGY topology;
929 UINT viewInstanceMask = 0;
930 uint generation = 0;
931 friend class QRhiD3D12;
932};
933
934struct QD3D12ComputePipeline : public QRhiComputePipeline
935{
936 QD3D12ComputePipeline(QRhiImplementation *rhi);
937 ~QD3D12ComputePipeline();
938 void destroy() override;
939 bool create() override;
940
941 QD3D12ObjectHandle handle;
942 QD3D12ObjectHandle rootSigHandle;
943 QD3D12ShaderStageData stageData;
944 uint generation = 0;
945 friend class QRhiD3D12;
946};
947
948struct QD3D12CommandBuffer : public QRhiCommandBuffer
949{
950 QD3D12CommandBuffer(QRhiImplementation *rhi);
951 ~QD3D12CommandBuffer();
952 void destroy() override;
953
954 const QRhiNativeHandles *nativeHandles();
955
956 D3D12GraphicsCommandList *cmdList = nullptr; // not owned
957 QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
958
959 enum PassType {
960 NoPass,
961 RenderPass,
962 ComputePass
963 };
964
965 void resetState()
966 {
967 recordingPass = NoPass;
968 currentTarget = nullptr;
969
970 resetPerPassState();
971 }
972
973 void resetPerPassState()
974 {
975 currentGraphicsPipeline = nullptr;
976 currentComputePipeline = nullptr;
977 currentPipelineGeneration = 0;
978 currentGraphicsSrb = nullptr;
979 currentComputeSrb = nullptr;
980 currentSrbGeneration = 0;
981 currentIndexBuffer = {};
982 currentIndexOffset = 0;
983 currentIndexFormat = DXGI_FORMAT_R16_UINT;
984 currentVertexBuffers = {};
985 currentVertexOffsets = {};
986 hasShadingRateSet = false;
987 hasShadingRateMapSet = false;
988 }
989
990 // per-frame
991 PassType recordingPass;
992 QRhiRenderTarget *currentTarget;
993
994 // per-pass
995 QD3D12GraphicsPipeline *currentGraphicsPipeline;
996 QD3D12ComputePipeline *currentComputePipeline;
997 uint currentPipelineGeneration;
998 QRhiShaderResourceBindings *currentGraphicsSrb;
999 QRhiShaderResourceBindings *currentComputeSrb;
1000 uint currentSrbGeneration;
1001 QD3D12ObjectHandle currentIndexBuffer;
1002 quint32 currentIndexOffset;
1003 DXGI_FORMAT currentIndexFormat;
1004 std::array<QD3D12ObjectHandle, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexBuffers;
1005 std::array<quint32, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexOffsets;
1006 bool hasShadingRateSet;
1007 bool hasShadingRateMapSet;
1008
1009 // global
1010 double lastGpuTime = 0;
1011
1012 // per-setShaderResources
1013 struct VisitorData {
1014 QVarLengthArray<std::pair<QD3D12ObjectHandle, quint32>, 4> cbufs[6];
1015 QVarLengthArray<QD3D12Descriptor, 8> srvs[6];
1016 QVarLengthArray<QD3D12Descriptor, 8> samplers[6];
1017 QVarLengthArray<std::pair<QD3D12ObjectHandle, D3D12_UNORDERED_ACCESS_VIEW_DESC>, 4> uavs[6];
1018 } visitorData;
1019
1020 void visitUniformBuffer(QD3D12Stage s,
1021 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1022 int shaderRegister,
1023 int binding,
1024 int dynamicOffsetCount,
1025 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets);
1026 void visitTexture(QD3D12Stage s,
1027 const QRhiShaderResourceBinding::TextureAndSampler &d,
1028 int shaderRegister);
1029 void visitSampler(QD3D12Stage s,
1030 const QRhiShaderResourceBinding::TextureAndSampler &d,
1031 int shaderRegister);
1032 void visitStorageBuffer(QD3D12Stage s,
1033 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1034 QD3D12ShaderResourceVisitor::StorageOp op,
1035 int shaderRegister);
1036 void visitStorageImage(QD3D12Stage s,
1037 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1038 QD3D12ShaderResourceVisitor::StorageOp op,
1039 int shaderRegister);
1040};
1041
1042struct QD3D12SwapChain : public QRhiSwapChain
1043{
1044 QD3D12SwapChain(QRhiImplementation *rhi);
1045 ~QD3D12SwapChain();
1046 void destroy() override;
1047
1048 QRhiCommandBuffer *currentFrameCommandBuffer() override;
1049 QRhiRenderTarget *currentFrameRenderTarget() override;
1050 QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
1051
1052 QSize surfacePixelSize() override;
1053 bool isFormatSupported(Format f) override;
1054 QRhiSwapChainHdrInfo hdrInfo() override;
1055
1056 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
1057 bool createOrResize() override;
1058
1059 void releaseBuffers();
1060 void waitCommandCompletionForFrameSlot(int frameSlot);
1061 void addCommandCompletionSignalForCurrentFrameSlot();
1062 void chooseFormats();
1063
1064 QWindow *window = nullptr;
1065 IDXGISwapChain1 *sourceSwapChain1 = nullptr;
1066 IDXGISwapChain3 *swapChain = nullptr;
1067 QSize pixelSize;
1068 UINT swapInterval = 1;
1069 UINT swapChainFlags = 0;
1070 BOOL stereo = false;
1071 DXGI_FORMAT colorFormat;
1072 DXGI_FORMAT srgbAdjustedColorFormat;
1073 DXGI_COLOR_SPACE_TYPE hdrColorSpace;
1074 IDCompositionTarget *dcompTarget = nullptr;
1075 IDCompositionVisual *dcompVisual = nullptr;
1076 static const UINT BUFFER_COUNT = 3;
1077 QD3D12ObjectHandle colorBuffers[BUFFER_COUNT];
1078 QD3D12Descriptor rtvs[BUFFER_COUNT];
1079 QD3D12Descriptor rtvsRight[BUFFER_COUNT];
1080 DXGI_SAMPLE_DESC sampleDesc;
1081 QD3D12ObjectHandle msaaBuffers[BUFFER_COUNT];
1082 QD3D12Descriptor msaaRtvs[BUFFER_COUNT];
1083 QD3D12RenderBuffer *ds = nullptr;
1084 UINT currentBackBufferIndex = 0;
1085 QD3D12SwapChainRenderTarget rtWrapper;
1086 QD3D12SwapChainRenderTarget rtWrapperRight;
1087 QD3D12CommandBuffer cbWrapper;
1088 HANDLE frameLatencyWaitableObject = nullptr;
1089
1090 struct FrameResources {
1091 ID3D12Fence *fence = nullptr;
1092 HANDLE fenceEvent = nullptr;
1093 UINT64 fenceCounter = 0;
1094 D3D12GraphicsCommandList *cmdList = nullptr;
1095 } frameRes[QD3D12_FRAMES_IN_FLIGHT];
1096
1097 int currentFrameSlot = 0; // index in frameRes
1098 int lastFrameLatencyWaitSlot = -1;
1099};
1100
1101template<typename T, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type>
1102struct alignas(void*) QD3D12PipelineStateSubObject
1103{
1104 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type = Type;
1105 T object = {};
1106};
1107
1108class QD3D12Adapter : public QRhiAdapter
1109{
1110public:
1111 QRhiDriverInfo info() const override;
1112
1113 LUID luid;
1114 QRhiDriverInfo adapterInfo;
1115};
1116
1117class QRhiD3D12 : public QRhiImplementation
1118{
1119public:
1120 // 16MB * QD3D12_FRAMES_IN_FLIGHT; buffer and texture upload staging data that
1121 // gets no space from this will get their own temporary staging areas.
1122 static const quint32 SMALL_STAGING_AREA_BYTES_PER_FRAME = 16 * 1024 * 1024;
1123
1124 static const quint32 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE = 16384;
1125
1126 QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importDevice = nullptr);
1127
1128 bool create(QRhi::Flags flags) override;
1129 void destroy() override;
1130 QRhi::AdapterList enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles) const override;
1131
1132 QRhiGraphicsPipeline *createGraphicsPipeline() override;
1133 QRhiComputePipeline *createComputePipeline() override;
1134 QRhiShaderResourceBindings *createShaderResourceBindings() override;
1135 QRhiBuffer *createBuffer(QRhiBuffer::Type type,
1136 QRhiBuffer::UsageFlags usage,
1137 quint32 size) override;
1138 QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
1139 const QSize &pixelSize,
1140 int sampleCount,
1141 QRhiRenderBuffer::Flags flags,
1142 QRhiTexture::Format backingFormatHint) override;
1143 QRhiTexture *createTexture(QRhiTexture::Format format,
1144 const QSize &pixelSize,
1145 int depth,
1146 int arraySize,
1147 int sampleCount,
1148 QRhiTexture::Flags flags) override;
1149 QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
1150 QRhiSampler::Filter minFilter,
1151 QRhiSampler::Filter mipmapMode,
1152 QRhiSampler:: AddressMode u,
1153 QRhiSampler::AddressMode v,
1154 QRhiSampler::AddressMode w) override;
1155
1156 QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
1157 QRhiTextureRenderTarget::Flags flags) override;
1158
1159 QRhiShadingRateMap *createShadingRateMap() override;
1160
1161 QRhiSwapChain *createSwapChain() override;
1162 QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
1163 QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
1164 QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
1165 QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
1166 QRhi::FrameOpResult finish() override;
1167
1168 void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
1169
1170 void beginPass(QRhiCommandBuffer *cb,
1171 QRhiRenderTarget *rt,
1172 const QColor &colorClearValue,
1173 const QRhiDepthStencilClearValue &depthStencilClearValue,
1174 QRhiResourceUpdateBatch *resourceUpdates,
1175 QRhiCommandBuffer::BeginPassFlags flags) override;
1176 void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
1177
1178 void setGraphicsPipeline(QRhiCommandBuffer *cb,
1179 QRhiGraphicsPipeline *ps) override;
1180
1181 void setShaderResources(QRhiCommandBuffer *cb,
1182 QRhiShaderResourceBindings *srb,
1183 int dynamicOffsetCount,
1184 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
1185
1186 void setVertexInput(QRhiCommandBuffer *cb,
1187 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
1188 QRhiBuffer *indexBuf, quint32 indexOffset,
1189 QRhiCommandBuffer::IndexFormat indexFormat) override;
1190
1191 void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
1192 void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
1193 void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
1194 void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
1195 void setShadingRate(QRhiCommandBuffer *cb, const QSize &coarsePixelSize) override;
1196
1197 void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1198 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
1199
1200 void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1201 quint32 instanceCount, quint32 firstIndex,
1202 qint32 vertexOffset, quint32 firstInstance) override;
1203
1204 void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
1205 void debugMarkEnd(QRhiCommandBuffer *cb) override;
1206 void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
1207
1208 void beginComputePass(QRhiCommandBuffer *cb,
1209 QRhiResourceUpdateBatch *resourceUpdates,
1210 QRhiCommandBuffer::BeginPassFlags flags) override;
1211 void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
1212 void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
1213 void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
1214
1215 const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
1216 void beginExternal(QRhiCommandBuffer *cb) override;
1217 void endExternal(QRhiCommandBuffer *cb) override;
1218 double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
1219
1220 QList<int> supportedSampleCounts() const override;
1221 QList<QSize> supportedShadingRates(int sampleCount) const override;
1222 int ubufAlignment() const override;
1223 bool isYUpInFramebuffer() const override;
1224 bool isYUpInNDC() const override;
1225 bool isClipDepthZeroToOne() const override;
1226 QMatrix4x4 clipSpaceCorrMatrix() const override;
1227 bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
1228 bool isFeatureSupported(QRhi::Feature feature) const override;
1229 int resourceLimit(QRhi::ResourceLimit limit) const override;
1230 const QRhiNativeHandles *nativeHandles() override;
1231 QRhiDriverInfo driverInfo() const override;
1232 QRhiStats statistics() override;
1233 bool makeThreadLocalNativeContextCurrent() override;
1234 void setQueueSubmitParams(QRhiNativeHandles *params) override;
1235 void releaseCachedResources() override;
1236 bool isDeviceLost() const override;
1237
1238 QByteArray pipelineCacheData() override;
1239 void setPipelineCacheData(const QByteArray &data) override;
1240
1241 void waitGpu();
1242 DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount, DXGI_FORMAT format) const;
1243 bool ensureDirectCompositionDevice();
1244 bool startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList);
1245 void enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
1246 void finishActiveReadbacks(bool forced = false);
1247 bool ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
1248 D3D12_DESCRIPTOR_HEAP_TYPE type,
1249 int frameSlot,
1250 quint32 neededDescriptorCount,
1251 bool *gotNew);
1252 void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
1253
1254 bool debugLayer = false;
1255 UINT maxFrameLatency = 2; // 1-3, use 2 to keep CPU-GPU parallelism while reducing lag compared to tripple buffering
1256 ID3D12Device2 *dev = nullptr;
1257 D3D_FEATURE_LEVEL minimumFeatureLevel = D3D_FEATURE_LEVEL(0);
1258 LUID adapterLuid = {};
1259 bool importedDevice = false;
1260 bool importedCommandQueue = false;
1261 QRhi::Flags rhiFlags;
1262 IDXGIFactory2 *dxgiFactory = nullptr;
1263 bool supportsAllowTearing = false;
1264 IDXGIAdapter1 *activeAdapter = nullptr;
1265 QRhiDriverInfo driverInfoStruct;
1266 QRhiD3D12NativeHandles nativeHandlesStruct;
1267 bool deviceLost = false;
1268 ID3D12CommandQueue *cmdQueue = nullptr;
1269 ID3D12Fence *fullFence = nullptr;
1270 HANDLE fullFenceEvent = nullptr;
1271 UINT64 fullFenceCounter = 0;
1272 ID3D12CommandAllocator *cmdAllocators[QD3D12_FRAMES_IN_FLIGHT] = {};
1273 QD3D12MemoryAllocator vma;
1274 QD3D12CpuDescriptorPool rtvPool;
1275 QD3D12CpuDescriptorPool dsvPool;
1276 QD3D12CpuDescriptorPool cbvSrvUavPool;
1277 QD3D12ObjectPool<QD3D12Resource> resourcePool;
1278 QD3D12ObjectPool<QD3D12Pipeline> pipelinePool;
1279 QD3D12ObjectPool<QD3D12RootSignature> rootSignaturePool;
1280 QD3D12ReleaseQueue releaseQueue;
1281 QD3D12ResourceBarrierGenerator barrierGen;
1282 QD3D12SamplerManager samplerMgr;
1283 QD3D12MipmapGenerator mipmapGen;
1284 QD3D12MipmapGenerator3D mipmapGen3D;
1285 QD3D12StagingArea smallStagingAreas[QD3D12_FRAMES_IN_FLIGHT];
1286 QD3D12ShaderVisibleDescriptorHeap shaderVisibleCbvSrvUavHeap;
1287 UINT64 timestampTicksPerSecond = 0;
1288 QD3D12QueryHeap timestampQueryHeap;
1289 QD3D12StagingArea timestampReadbackArea;
1290 IDCompositionDevice *dcompDevice = nullptr;
1291 QD3D12SwapChain *currentSwapChain = nullptr;
1292 QSet<QD3D12SwapChain *> swapchains;
1293 QD3D12ShaderBytecodeCache shaderBytecodeCache;
1294 QVarLengthArray<QD3D12Readback, 4> activeReadbacks;
1295 bool offscreenActive = false;
1296 QD3D12CommandBuffer *offscreenCb[QD3D12_FRAMES_IN_FLIGHT] = {};
1297 UINT shadingRateImageTileSize = 0;
1298
1299 struct {
1300 bool multiView = false;
1301 bool textureViewFormat = false;
1302 bool vrs = false;
1303 bool vrsMap = false;
1304 bool vrsAdditionalRates = false;
1305 } caps;
1306};
1307
1308QT_END_NAMESPACE
1309
1310#endif // __ID3D12Device2_INTERFACE_DEFINED__
1311
1312#endif
#define __has_include(x)