26#include <d3d12sdklayers.h>
30#include "D3D12MemAlloc.h"
38#ifdef __ID3D12Device2_INTERFACE_DEFINED__
39#define QRHI_D3D12_AVAILABLE
43#ifdef __ID3D12GraphicsCommandList5_INTERFACE_DEFINED__
44#define QRHI_D3D12_CL5_AVAILABLE
45using D3D12GraphicsCommandList = ID3D12GraphicsCommandList5;
47using D3D12GraphicsCommandList = ID3D12GraphicsCommandList1;
52static const int QD3D12_FRAMES_IN_FLIGHT = 2;
56struct QD3D12Descriptor
58 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
59 D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
61 bool isValid()
const {
return cpuHandle.ptr != 0; }
64struct QD3D12ReleaseQueue;
66struct QD3D12DescriptorHeap
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);
77 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
79 QD3D12Descriptor get(quint32 count);
80 QD3D12Descriptor at(quint32 index)
const;
81 quint32 remainingCapacity()
const {
return capacity - head; }
83 QD3D12Descriptor incremented(
const QD3D12Descriptor &descriptor, quint32 offsetInDescriptors)
const
85 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.cpuHandle;
86 cpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
87 D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = descriptor.gpuHandle;
89 gpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
90 return { cpuHandle, gpuHandle };
93 ID3D12DescriptorHeap *heap =
nullptr;
95 QD3D12Descriptor heapStart;
97 quint32 descriptorByteSize = 0;
98 D3D12_DESCRIPTOR_HEAP_TYPE heapType;
99 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags;
102struct QD3D12CpuDescriptorPool
104 bool isValid()
const {
return !heaps.isEmpty(); }
105 bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName =
"");
108 QD3D12Descriptor allocate(quint32 count);
109 void release(
const QD3D12Descriptor &descriptor, quint32 count);
111 static const int DESCRIPTORS_PER_HEAP = 256;
114 QD3D12DescriptorHeap heap;
116 static HeapWithMap init(
const QD3D12DescriptorHeap &heap, quint32 descriptorCount) {
119 result.map.resize(descriptorCount);
124 ID3D12Device *device;
125 quint32 descriptorByteSize;
126 QVector<HeapWithMap> heaps;
127 const char *debugName;
130struct QD3D12QueryHeap
132 bool isValid()
const {
return heap && capacity; }
133 bool create(ID3D12Device *device,
135 D3D12_QUERY_HEAP_TYPE heapType);
138 ID3D12QueryHeap *heap =
nullptr;
139 quint32 capacity = 0;
142struct QD3D12StagingArea
144 static const quint32 ALIGNMENT = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
148 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = 0;
149 ID3D12Resource *buffer =
nullptr;
150 quint32 bufferOffset = 0;
151 bool isValid()
const {
return p !=
nullptr; }
154 bool isValid()
const {
return allocation && mem.isValid(); }
155 bool create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType);
157 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
159 Allocation get(quint32 byteSize);
161 quint32 remainingCapacity()
const
163 return capacity - head;
166 static quint32 allocSizeForArray(quint32 size,
int count = 1)
168 return count * ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
172 ID3D12Resource *resource =
nullptr;
173 D3D12MA::Allocation *allocation =
nullptr;
178struct QD3D12ObjectHandle
181 quint32 generation = 0;
184 bool isNull()
const {
return index == 0 && generation == 0; }
187inline bool operator==(
const QD3D12ObjectHandle &a,
const QD3D12ObjectHandle &b)
noexcept
189 return a.index == b.index && a.generation == b.generation;
192inline bool operator!=(
const QD3D12ObjectHandle &a,
const QD3D12ObjectHandle &b)
noexcept
198struct QD3D12ObjectPool
200 void create(
const char *debugName =
"")
202 this->debugName = debugName;
203 Q_ASSERT(data.isEmpty());
209 for (Data &d : data) {
210 if (d.object.has_value()) {
212 d.object->releaseResources();
218 static bool leakCheck =
true;
221 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
225 qWarning(
"QD3D12ObjectPool::destroy(): Pool %p '%s' had %d unreleased objects",
226 this, debugName, leakCount);
231 bool isValid(
const QD3D12ObjectHandle &handle)
const
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();
240 T lookup(
const QD3D12ObjectHandle &handle)
const
242 return isValid(handle) ? *data[handle.index].object : T();
245 const T *lookupRef(
const QD3D12ObjectHandle &handle)
const
247 return isValid(handle) ? &*data[handle.index].object :
nullptr;
250 T *lookupRef(
const QD3D12ObjectHandle &handle)
252 return isValid(handle) ? &*data[handle.index].object :
nullptr;
255 QD3D12ObjectHandle add(
const T &object)
257 Q_ASSERT(!data.isEmpty());
258 const quint32 count = quint32(data.count());
260 for (; index < count; ++index) {
261 if (!data[index].object.has_value())
265 data[index].object = object;
266 quint32 &generation = data[index].generation;
268 return { index, generation };
270 data.append({ object, 1 });
275 void remove(
const QD3D12ObjectHandle &handle)
277 if (T *object = lookupRef(handle)) {
278 object->releaseResources();
279 data[handle.index].object.reset();
283 const char *debugName;
285 std::optional<T> object;
286 quint32 generation = 0;
293 ID3D12Resource *resource;
294 D3D12_RESOURCE_STATES state;
295 D3D12_RESOURCE_DESC desc;
296 D3D12MA::Allocation *allocation;
298 enum { UavUsageRead = 0x01, UavUsageWrite = 0x02 };
304 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
305 ID3D12Resource *resource,
306 D3D12_RESOURCE_STATES state,
307 D3D12MA::Allocation *allocation =
nullptr,
308 void *cpuMapPtr =
nullptr)
311 return pool->add({ resource, state, resource->GetDesc(), allocation, cpuMapPtr, 0,
true });
315 static QD3D12ObjectHandle addNonOwningToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
316 ID3D12Resource *resource,
317 D3D12_RESOURCE_STATES state)
320 return pool->add({ resource, state, resource->GetDesc(),
nullptr,
nullptr, 0,
false });
323 void releaseResources()
329 allocation->Release();
341 ID3D12PipelineState *pso;
343 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Pipeline> *pool,
345 ID3D12PipelineState *pso)
347 return pool->add({ type, pso });
350 void releaseResources()
356struct QD3D12RootSignature
358 ID3D12RootSignature *rootSig;
360 static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12RootSignature> *pool,
361 ID3D12RootSignature *rootSig)
363 return pool->add({ rootSig });
366 void releaseResources()
372struct QD3D12ReleaseQueue
374 void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool,
375 QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool,
376 QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool)
378 this->resourcePool = resourcePool;
379 this->pipelinePool = pipelinePool;
380 this->rootSignaturePool = rootSignaturePool;
383 void deferredReleaseResource(
const QD3D12ObjectHandle &handle);
384 void deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
385 QD3D12CpuDescriptorPool *pool,
386 const QD3D12Descriptor &viewsStart,
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,
398 void activatePendingDeferredReleaseRequests(
int frameSlot);
399 void executeDeferredReleases(
int frameSlot,
bool forced =
false);
402 struct DeferredReleaseEntry {
408 ResourceAndAllocation,
412 Type type = Resource;
413 std::optional<
int> frameSlotToBeReleasedIn;
414 QD3D12ObjectHandle handle;
415 QD3D12CpuDescriptorPool *poolForViews =
nullptr;
416 QD3D12Descriptor viewsStart;
418 std::function<
void(
void*)> callback =
nullptr;
419 void *callbackUserData =
nullptr;
420 std::pair<ID3D12Resource *, D3D12MA::Allocation *> resourceAndAllocation = {};
421 ID3D12DescriptorHeap *descriptorHeap =
nullptr;
423 QVector<DeferredReleaseEntry> queue;
424 QD3D12ObjectPool<QD3D12Resource> *resourcePool =
nullptr;
425 QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool =
nullptr;
426 QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool =
nullptr;
429struct QD3D12CommandBuffer;
431struct QD3D12ResourceBarrierGenerator
433 static const int PREALLOC = 16;
435 void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool)
437 this->resourcePool = resourcePool;
440 void addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle, D3D12_RESOURCE_STATES stateAfter);
441 void enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD);
442 void enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
443 const QD3D12ObjectHandle &resourceHandle,
445 D3D12_RESOURCE_STATES stateBefore,
446 D3D12_RESOURCE_STATES stateAfter);
447 void enqueueUavBarrier(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &resourceHandle);
449 struct TransitionResourceBarrier {
450 QD3D12ObjectHandle resourceHandle;
451 D3D12_RESOURCE_STATES stateBefore;
452 D3D12_RESOURCE_STATES stateAfter;
454 QVarLengthArray<TransitionResourceBarrier, PREALLOC> transitionResourceBarriers;
455 QD3D12ObjectPool<QD3D12Resource> *resourcePool =
nullptr;
458struct QD3D12ShaderBytecodeCache
462 Shader(
const QByteArray &bytecode,
const QShader::NativeResourceBindingMap &rbm)
463 : bytecode(bytecode), nativeResourceBindingMap(rbm)
466 QShader::NativeResourceBindingMap nativeResourceBindingMap;
469 QHash<QRhiShaderStage, Shader> data;
471 void insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s);
474struct QD3D12ShaderVisibleDescriptorHeap
476 bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type, quint32 perFrameDescriptorCount);
478 void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
480 QD3D12DescriptorHeap heap;
481 QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
485struct Q_D3D12_SAMPLER_DESC
487 D3D12_SAMPLER_DESC desc;
489 friend bool operator==(
const Q_D3D12_SAMPLER_DESC &lhs,
const Q_D3D12_SAMPLER_DESC &rhs)
noexcept
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
499 && lhs.desc.MinLOD == rhs.desc.MinLOD
500 && lhs.desc.MaxLOD == rhs.desc.MaxLOD;
503 friend bool operator!=(
const Q_D3D12_SAMPLER_DESC &lhs,
const Q_D3D12_SAMPLER_DESC &rhs)
noexcept
505 return !(lhs == rhs);
508 friend size_t qHash(
const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0)
noexcept
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);
519 seed = hash(seed, key.desc.MinLOD);
520 seed = hash(seed, key.desc.MaxLOD);
525struct QD3D12SamplerManager
527 const quint32 MAX_SAMPLERS = 512;
529 bool create(ID3D12Device *device);
532 QD3D12Descriptor getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc);
534 ID3D12Device *device =
nullptr;
535 QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
536 QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
539enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };
541static inline QD3D12Stage qd3d12_stage(QRhiShaderStage::Type type)
544 case QRhiShaderStage::Vertex:
546 case QRhiShaderStage::TessellationControl:
548 case QRhiShaderStage::TessellationEvaluation:
550 case QRhiShaderStage::Geometry:
552 case QRhiShaderStage::Fragment:
554 case QRhiShaderStage::Compute:
557 Q_UNREACHABLE_RETURN(VS);
560static inline D3D12_SHADER_VISIBILITY qd3d12_stageToVisibility(QD3D12Stage s)
564 return D3D12_SHADER_VISIBILITY_VERTEX;
566 return D3D12_SHADER_VISIBILITY_HULL;
568 return D3D12_SHADER_VISIBILITY_DOMAIN;
570 return D3D12_SHADER_VISIBILITY_GEOMETRY;
572 return D3D12_SHADER_VISIBILITY_PIXEL;
574 return D3D12_SHADER_VISIBILITY_ALL;
576 Q_UNREACHABLE_RETURN(D3D12_SHADER_VISIBILITY_ALL);
579static inline QRhiShaderResourceBinding::StageFlag qd3d12_stageToSrb(QD3D12Stage s)
583 return QRhiShaderResourceBinding::VertexStage;
585 return QRhiShaderResourceBinding::TessellationControlStage;
587 return QRhiShaderResourceBinding::TessellationEvaluationStage;
589 return QRhiShaderResourceBinding::GeometryStage;
591 return QRhiShaderResourceBinding::FragmentStage;
593 return QRhiShaderResourceBinding::ComputeStage;
595 Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::VertexStage);
598struct QD3D12ShaderStageData
601 QD3D12Stage stage = VS;
602 QShader::NativeResourceBindingMap nativeResourceBindingMap;
605struct QD3D12ShaderResourceBindings;
607struct QD3D12ShaderResourceVisitor
609 enum StorageOp { Load = 0, Store, LoadStore };
611 QD3D12ShaderResourceVisitor(
const QD3D12ShaderResourceBindings *srb,
612 const QD3D12ShaderStageData *stageData,
615 stageData(stageData),
616 stageCount(stageCount)
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;
628 const QD3D12ShaderResourceBindings *srb;
629 const QD3D12ShaderStageData *stageData;
637 QRhiReadbackResult *result =
nullptr;
638 QD3D12StagingArea staging;
639 quint32 byteSize = 0;
641 quint32 bytesPerLine = 0;
643 QRhiTexture::Format format = QRhiTexture::UnknownFormat;
644 quint32 stagingRowPitch = 0;
647struct QD3D12MipmapGenerator
649 bool create(QRhiD3D12 *rhiD);
651 void generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle);
654 QD3D12ObjectHandle rootSigHandle;
655 QD3D12ObjectHandle pipelineHandle;
658struct QD3D12MipmapGenerator3D
660 bool create(QRhiD3D12 *rhiD);
662 void generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle);
665 QD3D12ObjectHandle rootSigHandle;
666 QD3D12ObjectHandle pipelineHandle;
669struct QD3D12MemoryAllocator
671 bool create(ID3D12Device *device, IDXGIAdapter1 *adapter);
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,
682 void getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget);
684 bool isUsingD3D12MA()
const {
return allocator !=
nullptr; }
686 ID3D12Device *device =
nullptr;
687 D3D12MA::Allocator *allocator =
nullptr;
690struct QD3D12Buffer :
public QRhiBuffer
692 QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
695 void destroy() override;
696 bool create() override;
697 QRhiBuffer::NativeBuffer nativeBuffer() override;
698 char *beginFullDynamicBufferUpdateForCurrentFrame() override;
699 void endFullDynamicBufferUpdateForCurrentFrame() override;
701 void executeHostWritesForFrameSlot(
int frameSlot);
703 QD3D12ObjectHandle handles[QD3D12_FRAMES_IN_FLIGHT] = {};
708 QVarLengthArray<HostWrite, 16> pendingHostWrites[QD3D12_FRAMES_IN_FLIGHT];
709 friend class QRhiD3D12;
710 friend struct QD3D12CommandBuffer;
713struct QD3D12RenderBuffer :
public QRhiRenderBuffer
715 QD3D12RenderBuffer(QRhiImplementation *rhi,
717 const QSize &pixelSize,
720 QRhiTexture::Format backingFormatHint);
721 ~QD3D12RenderBuffer();
722 void destroy() override;
723 bool create() override;
724 QRhiTexture::Format backingFormat()
const override;
726 static const DXGI_FORMAT DS_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT;
728 QD3D12ObjectHandle handle;
729 QD3D12Descriptor rtv;
730 QD3D12Descriptor dsv;
731 DXGI_FORMAT dxgiFormat;
732 DXGI_SAMPLE_DESC sampleDesc;
734 friend class QRhiD3D12;
737struct QD3D12Texture :
public QRhiTexture
739 QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
740 int arraySize,
int sampleCount, Flags flags);
742 void destroy() override;
743 bool create() override;
744 bool createFrom(NativeTexture src) override;
745 NativeTexture nativeTexture() override;
746 void setNativeLayout(
int layout) override;
748 bool prepareCreate(QSize *adjustedSize =
nullptr);
751 QD3D12ObjectHandle handle;
752 QD3D12Descriptor srv;
753 DXGI_FORMAT dxgiFormat;
754 DXGI_FORMAT srvFormat;
755 DXGI_FORMAT rtFormat;
757 DXGI_SAMPLE_DESC sampleDesc;
759 friend class QRhiD3D12;
760 friend struct QD3D12CommandBuffer;
763struct QD3D12Sampler :
public QRhiSampler
765 QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
766 AddressMode u, AddressMode v, AddressMode w);
768 void destroy() override;
769 bool create() override;
771 QD3D12Descriptor lookupOrCreateShaderVisibleDescriptor();
773 D3D12_SAMPLER_DESC desc = {};
774 QD3D12Descriptor shaderVisibleDescriptor;
777struct QD3D12ShadingRateMap :
public QRhiShadingRateMap
779 QD3D12ShadingRateMap(QRhiImplementation *rhi);
780 ~QD3D12ShadingRateMap();
781 void destroy() override;
782 bool createFrom(QRhiTexture *src) override;
784 QD3D12ObjectHandle handle;
785 friend class QRhiD3D12;
788struct QD3D12RenderPassDescriptor :
public QRhiRenderPassDescriptor
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;
797 void updateSerializedFormat();
799 static const int MAX_COLOR_ATTACHMENTS = 8;
800 int colorAttachmentCount = 0;
801 bool hasDepthStencil =
false;
802 int colorFormat[MAX_COLOR_ATTACHMENTS];
804 bool hasShadingRateMap =
false;
805 QVector<quint32> serializedFormatData;
808struct QD3D12RenderTargetData
810 QD3D12RenderTargetData(QRhiImplementation *) { }
812 QD3D12RenderPassDescriptor *rp =
nullptr;
816 int colorAttCount = 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;
824struct QD3D12SwapChainRenderTarget :
public QRhiSwapChainRenderTarget
826 QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
827 ~QD3D12SwapChainRenderTarget();
828 void destroy() override;
830 QSize pixelSize()
const override;
831 float devicePixelRatio()
const override;
832 int sampleCount()
const override;
834 QD3D12RenderTargetData d;
837struct QD3D12TextureRenderTarget :
public QRhiTextureRenderTarget
839 QD3D12TextureRenderTarget(QRhiImplementation *rhi,
840 const QRhiTextureRenderTargetDescription &desc,
842 ~QD3D12TextureRenderTarget();
843 void destroy() override;
845 QSize pixelSize()
const override;
846 float devicePixelRatio()
const override;
847 int sampleCount()
const override;
849 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
850 bool create() override;
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;
860struct QD3D12GraphicsPipeline;
861struct QD3D12ComputePipeline;
863struct QD3D12ShaderResourceBindings :
public QRhiShaderResourceBindings
865 QD3D12ShaderResourceBindings(QRhiImplementation *rhi);
866 ~QD3D12ShaderResourceBindings();
867 void destroy() override;
868 bool create() override;
869 void updateResources(UpdateFlags flags) override;
871 QD3D12ObjectHandle createRootSignature(
const QD3D12ShaderStageData *stageData,
int stageCount);
874 QVarLengthArray<D3D12_ROOT_PARAMETER1, 2> cbParams[6];
876 D3D12_ROOT_PARAMETER1 srvTables[6] = {};
877 QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> srvRanges[6];
878 quint32 currentSrvRangeOffset[6] = {};
880 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> samplerTables[6];
881 std::array<D3D12_DESCRIPTOR_RANGE1, 16> samplerRanges[6] = {};
882 int samplerRangeHeads[6] = {};
884 D3D12_ROOT_PARAMETER1 uavTables[6] = {};
885 QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> uavRanges[6];
886 quint32 currentUavRangeOffset[6] = {};
890 void visitUniformBuffer(QD3D12Stage s,
891 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
894 void visitTexture(QD3D12Stage s,
895 const QRhiShaderResourceBinding::TextureAndSampler &d,
897 void visitSampler(QD3D12Stage s,
898 const QRhiShaderResourceBinding::TextureAndSampler &d,
900 void visitStorageBuffer(QD3D12Stage s,
901 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
902 QD3D12ShaderResourceVisitor::StorageOp op,
904 void visitStorageImage(QD3D12Stage s,
905 const QRhiShaderResourceBinding::Data::StorageImageData &d,
906 QD3D12ShaderResourceVisitor::StorageOp op,
909 bool hasDynamicOffset =
false;
911 QD3D12GraphicsPipeline *lastUsedGraphicsPipeline =
nullptr;
912 QD3D12ComputePipeline *lastUsedComputePipeline =
nullptr;
914 friend class QRhiD3D12;
915 friend struct QD3D12ShaderResourceVisitor;
918struct QD3D12GraphicsPipeline :
public QRhiGraphicsPipeline
920 QD3D12GraphicsPipeline(QRhiImplementation *rhi);
921 ~QD3D12GraphicsPipeline();
922 void destroy() override;
923 bool create() override;
925 QD3D12ObjectHandle handle;
926 QD3D12ObjectHandle rootSigHandle;
927 std::array<QD3D12ShaderStageData, 5> stageData;
928 D3D12_PRIMITIVE_TOPOLOGY topology;
929 UINT viewInstanceMask = 0;
931 friend class QRhiD3D12;
934struct QD3D12ComputePipeline :
public QRhiComputePipeline
936 QD3D12ComputePipeline(QRhiImplementation *rhi);
937 ~QD3D12ComputePipeline();
938 void destroy() override;
939 bool create() override;
941 QD3D12ObjectHandle handle;
942 QD3D12ObjectHandle rootSigHandle;
943 QD3D12ShaderStageData stageData;
945 friend class QRhiD3D12;
948struct QD3D12CommandBuffer :
public QRhiCommandBuffer
950 QD3D12CommandBuffer(QRhiImplementation *rhi);
951 ~QD3D12CommandBuffer();
952 void destroy() override;
954 const QRhiNativeHandles *nativeHandles();
956 D3D12GraphicsCommandList *cmdList =
nullptr;
957 QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
967 recordingPass = NoPass;
968 currentTarget =
nullptr;
973 void resetPerPassState()
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;
991 PassType recordingPass;
992 QRhiRenderTarget *currentTarget;
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;
1010 double lastGpuTime = 0;
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];
1020 void visitUniformBuffer(QD3D12Stage s,
1021 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
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);
1042struct QD3D12SwapChain :
public QRhiSwapChain
1044 QD3D12SwapChain(QRhiImplementation *rhi);
1046 void destroy() override;
1048 QRhiCommandBuffer *currentFrameCommandBuffer() override;
1049 QRhiRenderTarget *currentFrameRenderTarget() override;
1050 QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
1052 QSize surfacePixelSize() override;
1053 bool isFormatSupported(Format f) override;
1054 QRhiSwapChainHdrInfo hdrInfo() override;
1056 QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
1057 bool createOrResize() override;
1059 void releaseBuffers();
1060 void waitCommandCompletionForFrameSlot(
int frameSlot);
1061 void addCommandCompletionSignalForCurrentFrameSlot();
1062 void chooseFormats();
1064 QWindow *window =
nullptr;
1065 IDXGISwapChain1 *sourceSwapChain1 =
nullptr;
1066 IDXGISwapChain3 *swapChain =
nullptr;
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;
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];
1097 int currentFrameSlot = 0;
1098 int lastFrameLatencyWaitSlot = -1;
1101template<
typename T, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type>
1102struct alignas(
void*) QD3D12PipelineStateSubObject
1104 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type = Type;
1108class QD3D12Adapter :
public QRhiAdapter
1111 QRhiDriverInfo info()
const override;
1114 QRhiDriverInfo adapterInfo;
1117class QRhiD3D12 :
public QRhiImplementation
1122 static const quint32 SMALL_STAGING_AREA_BYTES_PER_FRAME = 16 * 1024 * 1024;
1124 static const quint32 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE = 16384;
1126 QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importDevice =
nullptr);
1128 bool create(QRhi::Flags flags) override;
1129 void destroy() override;
1130 QRhi::AdapterList enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const override;
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,
1141 QRhiRenderBuffer::Flags flags,
1142 QRhiTexture::Format backingFormatHint) override;
1143 QRhiTexture *createTexture(QRhiTexture::Format format,
1144 const QSize &pixelSize,
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;
1156 QRhiTextureRenderTarget *createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1157 QRhiTextureRenderTarget::Flags flags) override;
1159 QRhiShadingRateMap *createShadingRateMap() override;
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;
1168 void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
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;
1178 void setGraphicsPipeline(QRhiCommandBuffer *cb,
1179 QRhiGraphicsPipeline *ps) override;
1181 void setShaderResources(QRhiCommandBuffer *cb,
1182 QRhiShaderResourceBindings *srb,
1183 int dynamicOffsetCount,
1184 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
1186 void setVertexInput(QRhiCommandBuffer *cb,
1187 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1188 QRhiBuffer *indexBuf, quint32 indexOffset,
1189 QRhiCommandBuffer::IndexFormat indexFormat) override;
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;
1197 void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1198 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
1200 void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1201 quint32 instanceCount, quint32 firstIndex,
1202 qint32 vertexOffset, quint32 firstInstance) override;
1204 void debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name) override;
1205 void debugMarkEnd(QRhiCommandBuffer *cb) override;
1206 void debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg) override;
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;
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;
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;
1238 QByteArray pipelineCacheData() override;
1239 void setPipelineCacheData(
const QByteArray &data) override;
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,
1250 quint32 neededDescriptorCount,
1252 void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
1254 bool debugLayer =
false;
1255 UINT maxFrameLatency = 2;
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;
1300 bool multiView =
false;
1301 bool textureViewFormat =
false;
1303 bool vrsMap =
false;
1304 bool vrsAdditionalRates =
false;