27#include <d3d12sdklayers.h>
31#include "D3D12MemAlloc.h"
39#ifdef __ID3D12Device2_INTERFACE_DEFINED__
40#define QRHI_D3D12_AVAILABLE
44#ifdef __ID3D12GraphicsCommandList5_INTERFACE_DEFINED__
45#define QRHI_D3D12_CL5_AVAILABLE
46using D3D12GraphicsCommandList = ID3D12GraphicsCommandList5;
48using D3D12GraphicsCommandList = ID3D12GraphicsCommandList1;
53static const int QD3D12_FRAMES_IN_FLIGHT = 2;
57struct QD3D12Descriptor
59 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
60 D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
62 bool isValid()
const {
return cpuHandle.ptr != 0; }
65struct QD3D12ReleaseQueue;
67struct QD3D12DescriptorHeap
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);
78 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
80 QD3D12Descriptor get(quint32 count);
81 QD3D12Descriptor at(quint32 index)
const;
82 quint32 remainingCapacity()
const {
return capacity - head; }
84 QD3D12Descriptor incremented(
const QD3D12Descriptor &descriptor, quint32 offsetInDescriptors)
const
86 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.cpuHandle;
87 cpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
88 D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = descriptor.gpuHandle;
90 gpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
91 return { cpuHandle, gpuHandle };
94 ID3D12DescriptorHeap *heap =
nullptr;
96 QD3D12Descriptor heapStart;
98 quint32 descriptorByteSize = 0;
99 D3D12_DESCRIPTOR_HEAP_TYPE heapType;
100 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags;
103struct QD3D12CpuDescriptorPool
105 bool isValid()
const {
return !heaps.isEmpty(); }
106 bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName =
"");
109 QD3D12Descriptor allocate(quint32 count);
110 void release(
const QD3D12Descriptor &descriptor, quint32 count);
112 static const int DESCRIPTORS_PER_HEAP = 256;
115 QD3D12DescriptorHeap heap;
117 static HeapWithMap init(
const QD3D12DescriptorHeap &heap, quint32 descriptorCount) {
120 result.map.resize(descriptorCount);
125 ID3D12Device *device;
126 quint32 descriptorByteSize;
127 QVector<HeapWithMap> heaps;
128 const char *debugName;
131struct QD3D12QueryHeap
133 bool isValid()
const {
return heap && capacity; }
134 bool create(ID3D12Device *device,
136 D3D12_QUERY_HEAP_TYPE heapType);
139 ID3D12QueryHeap *heap =
nullptr;
140 quint32 capacity = 0;
143struct QD3D12StagingArea
145 static const quint32 ALIGNMENT = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
149 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = 0;
150 ID3D12Resource *buffer =
nullptr;
151 quint32 bufferOffset = 0;
152 bool isValid()
const {
return p !=
nullptr; }
155 bool isValid()
const {
return allocation && mem.isValid(); }
156 bool create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType);
158 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
160 Allocation get(quint32 byteSize);
162 quint32 remainingCapacity()
const
164 return capacity - head;
167 static quint32 allocSizeForArray(quint32 size,
int count = 1)
169 return count * ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
173 ID3D12Resource *resource =
nullptr;
174 D3D12MA::Allocation *allocation =
nullptr;
179struct QD3D12ObjectHandle
182 quint32 generation = 0;
185 bool isNull()
const {
return index == 0 && generation == 0; }
188inline bool operator==(
const QD3D12ObjectHandle &a,
const QD3D12ObjectHandle &b)
noexcept
190 return a.index == b.index && a.generation == b.generation;
193inline bool operator!=(
const QD3D12ObjectHandle &a,
const QD3D12ObjectHandle &b)
noexcept
199struct QD3D12ObjectPool
201 void create(
const char *debugName =
"")
203 this->debugName = debugName;
204 Q_ASSERT(data.isEmpty());
210 for (Data &d : data) {
211 if (d.object.has_value()) {
213 d.object->releaseResources();
219 static bool leakCheck =
true;
222 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
226 qWarning(
"QD3D12ObjectPool::destroy(): Pool %p '%s' had %d unreleased objects",
227 this, debugName, leakCount);
232 bool isValid(
const QD3D12ObjectHandle &handle)
const
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();
241 T lookup(
const QD3D12ObjectHandle &handle)
const
243 return isValid(handle) ? *data[handle.index].object : T();
246 const T *lookupRef(
const QD3D12ObjectHandle &handle)
const
248 return isValid(handle) ? &*data[handle.index].object :
nullptr;
251 T *lookupRef(
const QD3D12ObjectHandle &handle)
253 return isValid(handle) ? &*data[handle.index].object :
nullptr;
256 QD3D12ObjectHandle add(
const T &object)
258 Q_ASSERT(!data.isEmpty());
259 const quint32 count = quint32(data.count());
261 for (; index < count; ++index) {
262 if (!data[index].object.has_value())
266 data[index].object = object;
267 quint32 &generation = data[index].generation;
269 return { index, generation };
271 data.append({ object, 1 });
276 void remove(
const QD3D12ObjectHandle &handle)
278 if (T *object = lookupRef(handle)) {
279 object->releaseResources();
280 data[handle.index].object.reset();
284 const char *debugName;
286 std::optional<T> object;
287 quint32 generation = 0;
294 ID3D12Resource *resource;
295 D3D12_RESOURCE_STATES state;
296 D3D12_RESOURCE_DESC desc;
297 D3D12MA::Allocation *allocation;
299 enum { UavUsageRead = 0x01, UavUsageWrite = 0x02 };
305 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
306 ID3D12Resource *resource,
307 D3D12_RESOURCE_STATES state,
308 D3D12MA::Allocation *allocation =
nullptr,
309 void *cpuMapPtr =
nullptr)
312 return pool->add({ resource, state, resource->GetDesc(), allocation, cpuMapPtr, 0,
true });
316 static QD3D12ObjectHandle addNonOwningToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
317 ID3D12Resource *resource,
318 D3D12_RESOURCE_STATES state)
321 return pool->add({ resource, state, resource->GetDesc(),
nullptr,
nullptr, 0,
false });
324 void releaseResources()
330 allocation->Release();
342 ID3D12PipelineState *pso;
344 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Pipeline> *pool,
346 ID3D12PipelineState *pso)
348 return pool->add({ type, pso });
351 void releaseResources()
357struct QD3D12RootSignature
359 ID3D12RootSignature *rootSig;
361 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12RootSignature> *pool,
362 ID3D12RootSignature *rootSig)
364 return pool->add({ rootSig });
367 void releaseResources()
373struct QD3D12ReleaseQueue
375 void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool,
376 QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool,
377 QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool)
379 this->resourcePool = resourcePool;
380 this->pipelinePool = pipelinePool;
381 this->rootSignaturePool = rootSignaturePool;
384 void deferredReleaseResource(
const QD3D12ObjectHandle &handle);
385 void deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
386 QD3D12CpuDescriptorPool *pool,
387 const QD3D12Descriptor &viewsStart,
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,
399 void activatePendingDeferredReleaseRequests(
int frameSlot);
400 void executeDeferredReleases(
int frameSlot,
bool forced =
false);
403 struct DeferredReleaseEntry {
409 ResourceAndAllocation,
413 Type type = Resource;
414 std::optional<
int> frameSlotToBeReleasedIn;
415 QD3D12ObjectHandle handle;
416 QD3D12CpuDescriptorPool *poolForViews =
nullptr;
417 QD3D12Descriptor viewsStart;
419 std::function<
void(
void*)> callback =
nullptr;
420 void *callbackUserData =
nullptr;
421 std::pair<ID3D12Resource *, D3D12MA::Allocation *> resourceAndAllocation = {};
422 ID3D12DescriptorHeap *descriptorHeap =
nullptr;
424 QVector<DeferredReleaseEntry> queue;
425 QD3D12ObjectPool<QD3D12Resource> *resourcePool =
nullptr;
426 QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool =
nullptr;
427 QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool =
nullptr;
430struct QD3D12CommandBuffer;
432struct QD3D12ResourceBarrierGenerator
434 static const int PREALLOC = 16;
436 void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool)
438 this->resourcePool = resourcePool;
441 void addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle, D3D12_RESOURCE_STATES stateAfter);
442 void enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD);
443 void enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
444 const QD3D12ObjectHandle &resourceHandle,
446 D3D12_RESOURCE_STATES stateBefore,
447 D3D12_RESOURCE_STATES stateAfter);
448 void enqueueUavBarrier(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &resourceHandle);
450 struct TransitionResourceBarrier {
451 QD3D12ObjectHandle resourceHandle;
452 D3D12_RESOURCE_STATES stateBefore;
453 D3D12_RESOURCE_STATES stateAfter;
455 QVarLengthArray<TransitionResourceBarrier, PREALLOC> transitionResourceBarriers;
456 QD3D12ObjectPool<QD3D12Resource> *resourcePool =
nullptr;
459struct QD3D12ShaderBytecodeCache
463 Shader(
const QByteArray &bytecode,
const QShader::NativeResourceBindingMap &rbm)
464 : bytecode(bytecode), nativeResourceBindingMap(rbm)
467 QShader::NativeResourceBindingMap nativeResourceBindingMap;
470 QHash<QRhiShaderStage, Shader> data;
472 void insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s);
475struct QD3D12ShaderVisibleDescriptorHeap
477 bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type, quint32 perFrameDescriptorCount);
479 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
481 QD3D12DescriptorHeap heap;
482 QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
486struct Q_D3D12_SAMPLER_DESC
488 D3D12_SAMPLER_DESC desc;
490 friend bool operator==(
const Q_D3D12_SAMPLER_DESC &lhs,
const Q_D3D12_SAMPLER_DESC &rhs)
noexcept
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
500 && lhs.desc.MinLOD == rhs.desc.MinLOD
501 && lhs.desc.MaxLOD == rhs.desc.MaxLOD;
504 friend bool operator!=(
const Q_D3D12_SAMPLER_DESC &lhs,
const Q_D3D12_SAMPLER_DESC &rhs)
noexcept
506 return !(lhs == rhs);
509 friend size_t qHash(
const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0)
noexcept
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);
520 seed = hash(seed, key.desc.MinLOD);
521 seed = hash(seed, key.desc.MaxLOD);
526struct QD3D12SamplerManager
528 const quint32 MAX_SAMPLERS = 512;
530 bool create(ID3D12Device *device);
533 QD3D12Descriptor getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc);
535 ID3D12Device *device =
nullptr;
536 QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
537 QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
540enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };
542static inline QD3D12Stage qd3d12_stage(QRhiShaderStage::Type type)
545 case QRhiShaderStage::Vertex:
547 case QRhiShaderStage::TessellationControl:
549 case QRhiShaderStage::TessellationEvaluation:
551 case QRhiShaderStage::Geometry:
553 case QRhiShaderStage::Fragment:
555 case QRhiShaderStage::Compute:
558 Q_UNREACHABLE_RETURN(VS);
561static inline D3D12_SHADER_VISIBILITY qd3d12_stageToVisibility(QD3D12Stage s)
565 return D3D12_SHADER_VISIBILITY_VERTEX;
567 return D3D12_SHADER_VISIBILITY_HULL;
569 return D3D12_SHADER_VISIBILITY_DOMAIN;
571 return D3D12_SHADER_VISIBILITY_GEOMETRY;
573 return D3D12_SHADER_VISIBILITY_PIXEL;
575 return D3D12_SHADER_VISIBILITY_ALL;
577 Q_UNREACHABLE_RETURN(D3D12_SHADER_VISIBILITY_ALL);
580static inline QRhiShaderResourceBinding::StageFlag qd3d12_stageToSrb(QD3D12Stage s)
584 return QRhiShaderResourceBinding::VertexStage;
586 return QRhiShaderResourceBinding::TessellationControlStage;
588 return QRhiShaderResourceBinding::TessellationEvaluationStage;
590 return QRhiShaderResourceBinding::GeometryStage;
592 return QRhiShaderResourceBinding::FragmentStage;
594 return QRhiShaderResourceBinding::ComputeStage;
596 Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::VertexStage);
599struct QD3D12ShaderStageData
602 QD3D12Stage stage = VS;
603 QShader::NativeResourceBindingMap nativeResourceBindingMap;
606struct QD3D12ShaderResourceBindings;
608struct QD3D12ShaderResourceVisitor
610 enum StorageOp { Load = 0, Store, LoadStore };
612 QD3D12ShaderResourceVisitor(
const QD3D12ShaderResourceBindings *srb,
613 const QD3D12ShaderStageData *stageData,
616 stageData(stageData),
617 stageCount(stageCount)
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;
629 const QD3D12ShaderResourceBindings *srb;
630 const QD3D12ShaderStageData *stageData;
638 QRhiReadbackResult *result =
nullptr;
639 QD3D12StagingArea staging;
640 quint32 byteSize = 0;
642 quint32 bytesPerLine = 0;
644 QRhiTexture::Format format = QRhiTexture::UnknownFormat;
645 quint32 stagingRowPitch = 0;
648struct QD3D12MipmapGenerator
650 bool create(QRhiD3D12 *rhiD);
652 void generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle);
655 QD3D12ObjectHandle rootSigHandle;
656 QD3D12ObjectHandle pipelineHandle;
659struct QD3D12MipmapGenerator3D
661 bool create(QRhiD3D12 *rhiD);
663 void generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle);
666 QD3D12ObjectHandle rootSigHandle;
667 QD3D12ObjectHandle pipelineHandle;
670struct QD3D12MemoryAllocator
672 bool create(ID3D12Device *device, IDXGIAdapter1 *adapter);
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,
683 void getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget);
685 bool isUsingD3D12MA()
const {
return allocator !=
nullptr; }
687 ID3D12Device *device =
nullptr;
688 D3D12MA::Allocator *allocator =
nullptr;
691struct QD3D12Buffer :
public QRhiBuffer
693 QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
696 void destroy() override;
697 bool create() override;
698 QRhiBuffer::NativeBuffer nativeBuffer() override;
699 char *beginFullDynamicBufferUpdateForCurrentFrame() override;
700 void endFullDynamicBufferUpdateForCurrentFrame() override;
702 void executeHostWritesForFrameSlot(
int frameSlot);
704 QD3D12ObjectHandle handles[QD3D12_FRAMES_IN_FLIGHT] = {};
709 QVarLengthArray<HostWrite, 16> pendingHostWrites[QD3D12_FRAMES_IN_FLIGHT];
710 friend class QRhiD3D12;
711 friend struct QD3D12CommandBuffer;
714struct QD3D12RenderBuffer :
public QRhiRenderBuffer
716 QD3D12RenderBuffer(QRhiImplementation *rhi,
718 const QSize &pixelSize,
721 QRhiTexture::Format backingFormatHint);
722 ~QD3D12RenderBuffer();
723 void destroy() override;
724 bool create() override;
725 QRhiTexture::Format backingFormat()
const override;
727 static const DXGI_FORMAT DS_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT;
729 QD3D12ObjectHandle handle;
730 QD3D12Descriptor rtv;
731 QD3D12Descriptor dsv;
732 DXGI_FORMAT dxgiFormat;
733 DXGI_SAMPLE_DESC sampleDesc;
735 friend class QRhiD3D12;
738struct QD3D12Texture :
public QRhiTexture
740 QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
741 int arraySize,
int sampleCount, Flags flags);
743 void destroy() override;
744 bool create() override;
745 bool createFrom(NativeTexture src) override;
746 NativeTexture nativeTexture() override;
747 void setNativeLayout(
int layout) override;
749 bool prepareCreate(QSize *adjustedSize =
nullptr);
752 QD3D12ObjectHandle handle;
753 QD3D12Descriptor srv;
754 DXGI_FORMAT dxgiFormat;
755 DXGI_FORMAT srvFormat;
756 DXGI_FORMAT rtFormat;
758 DXGI_SAMPLE_DESC sampleDesc;
760 friend class QRhiD3D12;
761 friend struct QD3D12CommandBuffer;
764struct QD3D12Sampler :
public QRhiSampler
766 QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
767 AddressMode u, AddressMode v, AddressMode w);
769 void destroy() override;
770 bool create() override;
772 QD3D12Descriptor lookupOrCreateShaderVisibleDescriptor();
774 D3D12_SAMPLER_DESC desc = {};
775 QD3D12Descriptor shaderVisibleDescriptor;
778struct QD3D12ShadingRateMap :
public QRhiShadingRateMap
780 QD3D12ShadingRateMap(QRhiImplementation *rhi);
781 ~QD3D12ShadingRateMap();
782 void destroy() override;
783 bool createFrom(QRhiTexture *src) override;
785 QD3D12ObjectHandle handle;
786 friend class QRhiD3D12;
789struct QD3D12RenderPassDescriptor :
public QRhiRenderPassDescriptor
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;
798 void updateSerializedFormat();
800 static const int MAX_COLOR_ATTACHMENTS = 8;
801 int colorAttachmentCount = 0;
802 bool hasDepthStencil =
false;
803 int colorFormat[MAX_COLOR_ATTACHMENTS];
805 bool hasShadingRateMap =
false;
806 QVector<quint32> serializedFormatData;
809struct QD3D12RenderTargetData
811 QD3D12RenderTargetData(QRhiImplementation *) { }
813 QD3D12RenderPassDescriptor *rp =
nullptr;
817 int colorAttCount = 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;
825struct QD3D12SwapChainRenderTarget :
public QRhiSwapChainRenderTarget
827 QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
828 ~QD3D12SwapChainRenderTarget();
829 void destroy() override;
831 QSize pixelSize()
const override;
832 float devicePixelRatio()
const override;
833 int sampleCount()
const override;
835 QD3D12RenderTargetData d;
838struct QD3D12TextureRenderTarget :
public QRhiTextureRenderTarget
840 QD3D12TextureRenderTarget(QRhiImplementation *rhi,
841 const QRhiTextureRenderTargetDescription &desc,
843 ~QD3D12TextureRenderTarget();
844 void destroy() override;
846 QSize pixelSize()
const override;
847 float devicePixelRatio()
const override;
848 int sampleCount()
const override;
850 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
851 bool create() override;
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;
861struct QD3D12GraphicsPipeline;
862struct QD3D12ComputePipeline;
864struct QD3D12ShaderResourceBindings :
public QRhiShaderResourceBindings
866 QD3D12ShaderResourceBindings(QRhiImplementation *rhi);
867 ~QD3D12ShaderResourceBindings();
868 void destroy() override;
869 bool create() override;
870 void updateResources(UpdateFlags flags) override;
872 QD3D12ObjectHandle createRootSignature(
const QD3D12ShaderStageData *stageData,
int stageCount);
875 QVarLengthArray<D3D12_ROOT_PARAMETER1, 2> cbParams[6];
877 D3D12_ROOT_PARAMETER1 srvTables[6] = {};
878 QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> srvRanges[6];
879 quint32 currentSrvRangeOffset[6] = {};
881 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> samplerTables[6];
882 std::array<D3D12_DESCRIPTOR_RANGE1, 16> samplerRanges[6] = {};
883 int samplerRangeHeads[6] = {};
885 D3D12_ROOT_PARAMETER1 uavTables[6] = {};
886 QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> uavRanges[6];
887 quint32 currentUavRangeOffset[6] = {};
891 void visitUniformBuffer(QD3D12Stage s,
892 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
895 void visitTexture(QD3D12Stage s,
896 const QRhiShaderResourceBinding::TextureAndSampler &d,
898 void visitSampler(QD3D12Stage s,
899 const QRhiShaderResourceBinding::TextureAndSampler &d,
901 void visitStorageBuffer(QD3D12Stage s,
902 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
903 QD3D12ShaderResourceVisitor::StorageOp op,
905 void visitStorageImage(QD3D12Stage s,
906 const QRhiShaderResourceBinding::Data::StorageImageData &d,
907 QD3D12ShaderResourceVisitor::StorageOp op,
910 bool hasDynamicOffset =
false;
912 QD3D12GraphicsPipeline *lastUsedGraphicsPipeline =
nullptr;
913 QD3D12ComputePipeline *lastUsedComputePipeline =
nullptr;
915 friend class QRhiD3D12;
916 friend struct QD3D12ShaderResourceVisitor;
919struct QD3D12GraphicsPipeline :
public QRhiGraphicsPipeline
921 QD3D12GraphicsPipeline(QRhiImplementation *rhi);
922 ~QD3D12GraphicsPipeline();
923 void destroy() override;
924 bool create() override;
926 QD3D12ObjectHandle handle;
927 QD3D12ObjectHandle rootSigHandle;
928 std::array<QD3D12ShaderStageData, 5> stageData;
929 D3D12_PRIMITIVE_TOPOLOGY topology;
930 UINT viewInstanceMask = 0;
932 friend class QRhiD3D12;
935struct QD3D12ComputePipeline :
public QRhiComputePipeline
937 QD3D12ComputePipeline(QRhiImplementation *rhi);
938 ~QD3D12ComputePipeline();
939 void destroy() override;
940 bool create() override;
942 QD3D12ObjectHandle handle;
943 QD3D12ObjectHandle rootSigHandle;
944 QD3D12ShaderStageData stageData;
946 friend class QRhiD3D12;
949struct QD3D12CommandBuffer :
public QRhiCommandBuffer
951 QD3D12CommandBuffer(QRhiImplementation *rhi);
952 ~QD3D12CommandBuffer();
953 void destroy() override;
955 const QRhiNativeHandles *nativeHandles();
957 D3D12GraphicsCommandList *cmdList =
nullptr;
958 QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
968 recordingPass = NoPass;
969 currentTarget =
nullptr;
974 void resetPerPassState()
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;
992 PassType recordingPass;
993 QRhiRenderTarget *currentTarget;
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;
1011 double lastGpuTime = 0;
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];
1021 void visitUniformBuffer(QD3D12Stage s,
1022 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
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);
1043struct QD3D12SwapChain :
public QRhiSwapChain
1045 QD3D12SwapChain(QRhiImplementation *rhi);
1047 void destroy() override;
1049 QRhiCommandBuffer *currentFrameCommandBuffer() override;
1050 QRhiRenderTarget *currentFrameRenderTarget() override;
1051 QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
1053 QSize surfacePixelSize() override;
1054 bool isFormatSupported(Format f) override;
1055 QRhiSwapChainHdrInfo hdrInfo() override;
1057 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
1058 bool createOrResize() override;
1060 void releaseBuffers();
1061 void waitCommandCompletionForFrameSlot(
int frameSlot);
1062 void addCommandCompletionSignalForCurrentFrameSlot();
1063 void chooseFormats();
1065 QWindow *window =
nullptr;
1066 IDXGISwapChain1 *sourceSwapChain1 =
nullptr;
1067 IDXGISwapChain3 *swapChain =
nullptr;
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;
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];
1098 int currentFrameSlot = 0;
1099 int lastFrameLatencyWaitSlot = -1;
1102template<
typename T, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type>
1103struct alignas(
void*) QD3D12PipelineStateSubObject
1105 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type = Type;
1109class QD3D12Adapter :
public QRhiAdapter
1112 QRhiDriverInfo info()
const override;
1115 QRhiDriverInfo adapterInfo;
1118class QRhiD3D12 :
public QRhiImplementation
1123 static const quint32 SMALL_STAGING_AREA_BYTES_PER_FRAME = 16 * 1024 * 1024;
1125 static const quint32 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE = 16384;
1127 QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importDevice =
nullptr);
1129 bool create(QRhi::Flags flags) override;
1130 void destroy() override;
1131 QRhi::AdapterList enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const override;
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,
1142 QRhiRenderBuffer::Flags flags,
1143 QRhiTexture::Format backingFormatHint) override;
1144 QRhiTexture *createTexture(QRhiTexture::Format format,
1145 const QSize &pixelSize,
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;
1157 QRhiTextureRenderTarget *createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1158 QRhiTextureRenderTarget::Flags flags) override;
1160 QRhiShadingRateMap *createShadingRateMap() override;
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;
1169 void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
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;
1179 void setGraphicsPipeline(QRhiCommandBuffer *cb,
1180 QRhiGraphicsPipeline *ps) override;
1182 void setShaderResources(QRhiCommandBuffer *cb,
1183 QRhiShaderResourceBindings *srb,
1184 int dynamicOffsetCount,
1185 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
1187 void setVertexInput(QRhiCommandBuffer *cb,
1188 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1189 QRhiBuffer *indexBuf, quint32 indexOffset,
1190 QRhiCommandBuffer::IndexFormat indexFormat) override;
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;
1198 void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1199 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
1201 void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1202 quint32 instanceCount, quint32 firstIndex,
1203 qint32 vertexOffset, quint32 firstInstance) override;
1205 void debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name) override;
1206 void debugMarkEnd(QRhiCommandBuffer *cb) override;
1207 void debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg) override;
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;
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;
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;
1239 QByteArray pipelineCacheData() override;
1240 void setPipelineCacheData(
const QByteArray &data) override;
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,
1251 quint32 neededDescriptorCount,
1253 void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
1255 bool debugLayer =
false;
1256 UINT maxFrameLatency = 2;
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;
1301 bool multiView =
false;
1302 bool textureViewFormat =
false;
1304 bool vrsMap =
false;
1305 bool vrsAdditionalRates =
false;