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