summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi/qrhid3d12_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi/qrhid3d12_p.h')
-rw-r--r--src/gui/rhi/qrhid3d12_p.h1248
1 files changed, 1248 insertions, 0 deletions
diff --git a/src/gui/rhi/qrhid3d12_p.h b/src/gui/rhi/qrhid3d12_p.h
new file mode 100644
index 0000000000..3f9abbb5ac
--- /dev/null
+++ b/src/gui/rhi/qrhid3d12_p.h
@@ -0,0 +1,1248 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHID3D12_P_H
+#define QRHID3D12_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qrhi_p.h"
+#include <QWindow>
+#include <QBitArray>
+
+#include <optional>
+#include <array>
+
+#include <d3d12.h>
+#include <d3d12sdklayers.h>
+#include <dxgi1_6.h>
+#include <dcomp.h>
+
+#include "D3D12MemAlloc.h"
+
+// ID3D12Device2 and ID3D12GraphicsCommandList1 and types and enums introduced
+// with those are hard requirements now. These should be declared in any
+// moderately recent d3d12.h, but if it is an SDK from before Windows 10
+// version 1703 then these types could be missing. In the absence of other
+// options, handle this by skipping all the code and making QRhi::create() fail
+// in such builds.
+#ifdef __ID3D12Device2_INTERFACE_DEFINED__
+#define QRHI_D3D12_AVAILABLE
+
+QT_BEGIN_NAMESPACE
+
+static const int QD3D12_FRAMES_IN_FLIGHT = 2;
+
+class QRhiD3D12;
+
+struct QD3D12Descriptor
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
+ D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
+
+ bool isValid() const { return cpuHandle.ptr != 0; }
+};
+
+struct QD3D12ReleaseQueue;
+
+struct QD3D12DescriptorHeap
+{
+ bool isValid() const { return heap && capacity; }
+ bool create(ID3D12Device *device,
+ quint32 descriptorCount,
+ D3D12_DESCRIPTOR_HEAP_TYPE heapType,
+ D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags);
+ void createWithExisting(const QD3D12DescriptorHeap &other,
+ quint32 offsetInDescriptors,
+ quint32 descriptorCount);
+ void destroy();
+ void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
+
+ QD3D12Descriptor get(quint32 count);
+ QD3D12Descriptor at(quint32 index) const;
+ quint32 remainingCapacity() const { return capacity - head; }
+
+ QD3D12Descriptor incremented(const QD3D12Descriptor &descriptor, quint32 offsetInDescriptors) const
+ {
+ D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.cpuHandle;
+ cpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
+ D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = descriptor.gpuHandle;
+ if (gpuHandle.ptr)
+ gpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
+ return { cpuHandle, gpuHandle };
+ }
+
+ ID3D12DescriptorHeap *heap = nullptr;
+ quint32 capacity = 0;
+ QD3D12Descriptor heapStart;
+ quint32 head = 0;
+ quint32 descriptorByteSize = 0;
+ D3D12_DESCRIPTOR_HEAP_TYPE heapType;
+ D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags;
+};
+
+struct QD3D12CpuDescriptorPool
+{
+ bool isValid() const { return !heaps.isEmpty(); }
+ bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType, const char *debugName = "");
+ void destroy();
+
+ QD3D12Descriptor allocate(quint32 count);
+ void release(const QD3D12Descriptor &descriptor, quint32 count);
+
+ static const int DESCRIPTORS_PER_HEAP = 256;
+
+ struct HeapWithMap {
+ QD3D12DescriptorHeap heap;
+ QBitArray map;
+ static HeapWithMap init(const QD3D12DescriptorHeap &heap, quint32 descriptorCount) {
+ HeapWithMap result;
+ result.heap = heap;
+ result.map.resize(descriptorCount);
+ return result;
+ }
+ };
+
+ ID3D12Device *device;
+ quint32 descriptorByteSize;
+ QVector<HeapWithMap> heaps;
+ const char *debugName;
+};
+
+struct QD3D12QueryHeap
+{
+ bool isValid() const { return heap && capacity; }
+ bool create(ID3D12Device *device,
+ quint32 queryCount,
+ D3D12_QUERY_HEAP_TYPE heapType);
+ void destroy();
+
+ ID3D12QueryHeap *heap = nullptr;
+ quint32 capacity = 0;
+};
+
+struct QD3D12StagingArea
+{
+ static const quint32 ALIGNMENT = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; // 512 so good enough both for cb and texdata
+
+ struct Allocation {
+ quint8 *p = nullptr;
+ D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = 0;
+ ID3D12Resource *buffer = nullptr;
+ quint32 bufferOffset = 0;
+ bool isValid() const { return p != nullptr; }
+ };
+
+ bool isValid() const { return allocation && mem.isValid(); }
+ bool create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType);
+ void destroy();
+ void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
+
+ Allocation get(quint32 byteSize);
+
+ quint32 remainingCapacity() const
+ {
+ return capacity - head;
+ }
+
+ static quint32 allocSizeForArray(quint32 size, int count = 1)
+ {
+ return count * ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
+ }
+
+ Allocation mem;
+ ID3D12Resource *resource = nullptr;
+ D3D12MA::Allocation *allocation = nullptr;
+ quint32 head;
+ quint32 capacity;
+};
+
+struct QD3D12ObjectHandle
+{
+ quint32 index = 0;
+ quint32 generation = 0;
+
+ // the default, null handle is guaranteed to give ObjectPool::isValid() == false
+ bool isNull() const { return index == 0 && generation == 0; }
+};
+
+inline bool operator==(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
+{
+ return a.index == b.index && a.generation == b.generation;
+}
+
+inline bool operator!=(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
+{
+ return !(a == b);
+}
+
+template<typename T>
+struct QD3D12ObjectPool
+{
+ void create(const char *debugName = "")
+ {
+ this->debugName = debugName;
+ Q_ASSERT(data.isEmpty());
+ data.append(Data()); // index 0 is always invalid
+ }
+
+ void destroy() {
+ int leakCount = 0; // will nicely destroy everything here, but warn about it if enabled
+ for (Data &d : data) {
+ if (d.object.has_value()) {
+ leakCount += 1;
+ d.object->releaseResources();
+ }
+ }
+ data.clear();
+#ifndef QT_NO_DEBUG
+ // debug builds: just do it always
+ static bool leakCheck = true;
+#else
+ // release builds: opt-in
+ static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK");
+#endif
+ if (leakCheck) {
+ if (leakCount > 0) {
+ qWarning("QD3D12ObjectPool::destroy(): Pool %p '%s' had %d unreleased objects",
+ this, debugName, leakCount);
+ }
+ }
+ }
+
+ bool isValid(const QD3D12ObjectHandle &handle) const
+ {
+ return handle.index > 0
+ && handle.index < quint32(data.count())
+ && handle.generation > 0
+ && handle.generation == data[handle.index].generation
+ && data[handle.index].object.has_value();
+ }
+
+ T lookup(const QD3D12ObjectHandle &handle) const
+ {
+ return isValid(handle) ? *data[handle.index].object : T();
+ }
+
+ const T *lookupRef(const QD3D12ObjectHandle &handle) const
+ {
+ return isValid(handle) ? &*data[handle.index].object : nullptr;
+ }
+
+ T *lookupRef(const QD3D12ObjectHandle &handle)
+ {
+ return isValid(handle) ? &*data[handle.index].object : nullptr;
+ }
+
+ QD3D12ObjectHandle add(const T &object)
+ {
+ Q_ASSERT(!data.isEmpty());
+ const quint32 count = quint32(data.count());
+ quint32 index = 1; // index 0 is always invalid
+ for (; index < count; ++index) {
+ if (!data[index].object.has_value())
+ break;
+ }
+ if (index < count) {
+ data[index].object = object;
+ quint32 &generation = data[index].generation;
+ generation += 1u;
+ return { index, generation };
+ } else {
+ data.append({ object, 1 });
+ return { count, 1 };
+ }
+ }
+
+ void remove(const QD3D12ObjectHandle &handle)
+ {
+ if (T *object = lookupRef(handle)) {
+ object->releaseResources();
+ data[handle.index].object.reset();
+ }
+ }
+
+ const char *debugName;
+ struct Data {
+ std::optional<T> object;
+ quint32 generation = 0;
+ };
+ QVector<Data> data;
+};
+
+struct QD3D12Resource
+{
+ ID3D12Resource *resource;
+ D3D12_RESOURCE_STATES state;
+ D3D12_RESOURCE_DESC desc;
+ D3D12MA::Allocation *allocation;
+ void *cpuMapPtr;
+ enum { UavUsageRead = 0x01, UavUsageWrite = 0x02 };
+ int uavUsage;
+ bool owns;
+
+ // note that this assumes the allocation (if there is one) and the resource
+ // are separately releaseable, see D3D12MemAlloc docs
+ static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
+ ID3D12Resource *resource,
+ D3D12_RESOURCE_STATES state,
+ D3D12MA::Allocation *allocation = nullptr,
+ void *cpuMapPtr = nullptr)
+ {
+ Q_ASSERT(resource);
+ return pool->add({ resource, state, resource->GetDesc(), allocation, cpuMapPtr, 0, true });
+ }
+
+ // for QRhiTexture::createFrom() where the ID3D12Resource is not owned by us
+ static QD3D12ObjectHandle addNonOwningToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
+ ID3D12Resource *resource,
+ D3D12_RESOURCE_STATES state)
+ {
+ Q_ASSERT(resource);
+ return pool->add({ resource, state, resource->GetDesc(), nullptr, nullptr, 0, false });
+ }
+
+ void releaseResources()
+ {
+ if (owns) {
+ // order matters: resource first, then the allocation
+ resource->Release();
+ if (allocation)
+ allocation->Release();
+ }
+ }
+};
+
+struct QD3D12Pipeline
+{
+ enum Type {
+ Graphics,
+ Compute
+ };
+ Type type;
+ ID3D12PipelineState *pso;
+
+ static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Pipeline> *pool,
+ Type type,
+ ID3D12PipelineState *pso)
+ {
+ return pool->add({ type, pso });
+ }
+
+ void releaseResources()
+ {
+ pso->Release();
+ }
+};
+
+struct QD3D12RootSignature
+{
+ ID3D12RootSignature *rootSig;
+
+ static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12RootSignature> *pool,
+ ID3D12RootSignature *rootSig)
+ {
+ return pool->add({ rootSig });
+ }
+
+ void releaseResources()
+ {
+ rootSig->Release();
+ }
+};
+
+struct QD3D12ReleaseQueue
+{
+ void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool,
+ QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool,
+ QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool)
+ {
+ this->resourcePool = resourcePool;
+ this->pipelinePool = pipelinePool;
+ this->rootSignaturePool = rootSignaturePool;
+ }
+
+ void deferredReleaseResource(const QD3D12ObjectHandle &handle);
+ void deferredReleaseResourceWithViews(const QD3D12ObjectHandle &handle,
+ QD3D12CpuDescriptorPool *pool,
+ const QD3D12Descriptor &viewsStart,
+ int viewCount);
+ void deferredReleasePipeline(const QD3D12ObjectHandle &handle);
+ void deferredReleaseRootSignature(const QD3D12ObjectHandle &handle);
+ void deferredReleaseCallback(std::function<void(void*)> callback, void *userData);
+ void deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
+ D3D12MA::Allocation *allocation);
+ void deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap);
+ void deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
+ const QD3D12Descriptor &viewsStart,
+ int viewCount);
+
+ void activatePendingDeferredReleaseRequests(int frameSlot);
+ void executeDeferredReleases(int frameSlot, bool forced = false);
+ void releaseAll();
+
+ struct DeferredReleaseEntry {
+ enum Type {
+ Resource,
+ Pipeline,
+ RootSignature,
+ Callback,
+ ResourceAndAllocation,
+ DescriptorHeap,
+ Views
+ };
+ Type type = Resource;
+ std::optional<int> frameSlotToBeReleasedIn;
+ QD3D12ObjectHandle handle;
+ QD3D12CpuDescriptorPool *poolForViews = nullptr;
+ QD3D12Descriptor viewsStart;
+ int viewCount = 0;
+ std::function<void(void*)> callback = nullptr;
+ void *callbackUserData = nullptr;
+ QPair<ID3D12Resource *, D3D12MA::Allocation *> resourceAndAllocation = {};
+ ID3D12DescriptorHeap *descriptorHeap = nullptr;
+ };
+ QVector<DeferredReleaseEntry> queue;
+ QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
+ QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool = nullptr;
+ QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool = nullptr;
+};
+
+struct QD3D12CommandBuffer;
+
+struct QD3D12ResourceBarrierGenerator
+{
+ static const int PREALLOC = 16;
+
+ void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool)
+ {
+ this->resourcePool = resourcePool;
+ }
+
+ void addTransitionBarrier(const QD3D12ObjectHandle &resourceHandle, D3D12_RESOURCE_STATES stateAfter);
+ void enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD);
+ void enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
+ const QD3D12ObjectHandle &resourceHandle,
+ UINT subresource,
+ D3D12_RESOURCE_STATES stateBefore,
+ D3D12_RESOURCE_STATES stateAfter);
+ void enqueueUavBarrier(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &resourceHandle);
+
+ struct TransitionResourceBarrier {
+ QD3D12ObjectHandle resourceHandle;
+ D3D12_RESOURCE_STATES stateBefore;
+ D3D12_RESOURCE_STATES stateAfter;
+ };
+ QVarLengthArray<TransitionResourceBarrier, PREALLOC> transitionResourceBarriers;
+ QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
+};
+
+struct QD3D12ShaderBytecodeCache
+{
+ struct Shader {
+ Shader() = default;
+ Shader(const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
+ : bytecode(bytecode), nativeResourceBindingMap(rbm)
+ { }
+ QByteArray bytecode;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ };
+
+ QHash<QRhiShaderStage, Shader> data;
+
+ void insertWithCapacityLimit(const QRhiShaderStage &key, const Shader &s);
+};
+
+struct QD3D12ShaderVisibleDescriptorHeap
+{
+ bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type, quint32 perFrameDescriptorCount);
+ void destroy();
+ void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
+
+ QD3D12DescriptorHeap heap;
+ QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
+};
+
+// wrap foreign struct so we can legally supply equality operators and qHash:
+struct Q_D3D12_SAMPLER_DESC
+{
+ D3D12_SAMPLER_DESC desc;
+
+ friend bool operator==(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
+ {
+ return lhs.desc.Filter == rhs.desc.Filter
+ && lhs.desc.AddressU == rhs.desc.AddressU
+ && lhs.desc.AddressV == rhs.desc.AddressV
+ && lhs.desc.AddressW == rhs.desc.AddressW
+ && lhs.desc.MipLODBias == rhs.desc.MipLODBias
+ && lhs.desc.MaxAnisotropy == rhs.desc.MaxAnisotropy
+ && lhs.desc.ComparisonFunc == rhs.desc.ComparisonFunc
+ // BorderColor is never used, skip it
+ && lhs.desc.MinLOD == rhs.desc.MinLOD
+ && lhs.desc.MaxLOD == rhs.desc.MaxLOD;
+ }
+
+ friend bool operator!=(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ friend size_t qHash(const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, key.desc.Filter);
+ seed = hash(seed, key.desc.AddressU);
+ seed = hash(seed, key.desc.AddressV);
+ seed = hash(seed, key.desc.AddressW);
+ seed = hash(seed, key.desc.MipLODBias);
+ seed = hash(seed, key.desc.MaxAnisotropy);
+ seed = hash(seed, key.desc.ComparisonFunc);
+ // BorderColor is never used, skip it
+ seed = hash(seed, key.desc.MinLOD);
+ seed = hash(seed, key.desc.MaxLOD);
+ return seed;
+ }
+};
+
+struct QD3D12SamplerManager
+{
+ const quint32 MAX_SAMPLERS = 512;
+
+ bool create(ID3D12Device *device);
+ void destroy();
+
+ QD3D12Descriptor getShaderVisibleDescriptor(const D3D12_SAMPLER_DESC &desc);
+
+ ID3D12Device *device = nullptr;
+ QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
+ QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
+};
+
+enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };
+
+static inline QD3D12Stage qd3d12_stage(QRhiShaderStage::Type type)
+{
+ switch (type) {
+ case QRhiShaderStage::Vertex:
+ return VS;
+ case QRhiShaderStage::TessellationControl:
+ return HS;
+ case QRhiShaderStage::TessellationEvaluation:
+ return DS;
+ case QRhiShaderStage::Geometry:
+ return GS;
+ case QRhiShaderStage::Fragment:
+ return PS;
+ case QRhiShaderStage::Compute:
+ return CS;
+ }
+ Q_UNREACHABLE_RETURN(VS);
+}
+
+static inline D3D12_SHADER_VISIBILITY qd3d12_stageToVisibility(QD3D12Stage s)
+{
+ switch (s) {
+ case VS:
+ return D3D12_SHADER_VISIBILITY_VERTEX;
+ case HS:
+ return D3D12_SHADER_VISIBILITY_HULL;
+ case DS:
+ return D3D12_SHADER_VISIBILITY_DOMAIN;
+ case GS:
+ return D3D12_SHADER_VISIBILITY_GEOMETRY;
+ case PS:
+ return D3D12_SHADER_VISIBILITY_PIXEL;
+ case CS:
+ return D3D12_SHADER_VISIBILITY_ALL;
+ }
+ Q_UNREACHABLE_RETURN(D3D12_SHADER_VISIBILITY_ALL);
+}
+
+static inline QRhiShaderResourceBinding::StageFlag qd3d12_stageToSrb(QD3D12Stage s)
+{
+ switch (s) {
+ case VS:
+ return QRhiShaderResourceBinding::VertexStage;
+ case HS:
+ return QRhiShaderResourceBinding::TessellationControlStage;
+ case DS:
+ return QRhiShaderResourceBinding::TessellationEvaluationStage;
+ case GS:
+ return QRhiShaderResourceBinding::GeometryStage;
+ case PS:
+ return QRhiShaderResourceBinding::FragmentStage;
+ case CS:
+ return QRhiShaderResourceBinding::ComputeStage;
+ }
+ Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::VertexStage);
+}
+
+struct QD3D12ShaderStageData
+{
+ bool valid = false; // to allow simple arrays where unused stages are indicated by !valid
+ QD3D12Stage stage = VS;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+};
+
+struct QD3D12ShaderResourceBindings;
+
+struct QD3D12ShaderResourceVisitor
+{
+ enum StorageOp { Load = 0, Store, LoadStore };
+
+ QD3D12ShaderResourceVisitor(const QD3D12ShaderResourceBindings *srb,
+ const QD3D12ShaderStageData *stageData,
+ int stageCount)
+ : srb(srb),
+ stageData(stageData),
+ stageCount(stageCount)
+ {
+ }
+
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::UniformBufferData &, int, int)> uniformBuffer = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> texture = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> sampler = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageImageData &, StorageOp, int)> storageImage = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageBufferData &, StorageOp, int)> storageBuffer = nullptr;
+
+ void visit();
+
+ const QD3D12ShaderResourceBindings *srb;
+ const QD3D12ShaderStageData *stageData;
+ int stageCount;
+};
+
+struct QD3D12Readback
+{
+ // common
+ int frameSlot = -1;
+ QRhiReadbackResult *result = nullptr;
+ QD3D12StagingArea staging;
+ quint32 byteSize = 0;
+ // textures
+ quint32 bytesPerLine = 0;
+ QSize pixelSize;
+ QRhiTexture::Format format = QRhiTexture::UnknownFormat;
+ quint32 stagingRowPitch = 0;
+};
+
+struct QD3D12MipmapGenerator
+{
+ bool create(QRhiD3D12 *rhiD);
+ void destroy();
+ void generate(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &textureHandle);
+
+ QRhiD3D12 *rhiD;
+ QD3D12ObjectHandle rootSigHandle;
+ QD3D12ObjectHandle pipelineHandle;
+};
+
+struct QD3D12MemoryAllocator
+{
+ bool create(ID3D12Device *device, IDXGIAdapter1 *adapter);
+ void destroy();
+
+ HRESULT createResource(D3D12_HEAP_TYPE heapType,
+ const D3D12_RESOURCE_DESC *resourceDesc,
+ D3D12_RESOURCE_STATES initialState,
+ const D3D12_CLEAR_VALUE *optimizedClearValue,
+ D3D12MA::Allocation **maybeAllocation,
+ REFIID riidResource,
+ void **ppvResource);
+
+ void getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget);
+
+ bool isUsingD3D12MA() const { return allocator != nullptr; }
+
+ ID3D12Device *device = nullptr;
+ D3D12MA::Allocator *allocator = nullptr;
+};
+
+struct QD3D12Buffer : public QRhiBuffer
+{
+ QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QD3D12Buffer();
+
+ void destroy() override;
+ bool create() override;
+ QRhiBuffer::NativeBuffer nativeBuffer() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+ void endFullDynamicBufferUpdateForCurrentFrame() override;
+
+ void executeHostWritesForFrameSlot(int frameSlot);
+
+ QD3D12ObjectHandle handles[QD3D12_FRAMES_IN_FLIGHT] = {};
+ struct HostWrite {
+ quint32 offset;
+ QRhiBufferData data;
+ };
+ QVarLengthArray<HostWrite, 16> pendingHostWrites[QD3D12_FRAMES_IN_FLIGHT];
+ friend class QRhiD3D12;
+ friend struct QD3D12CommandBuffer;
+};
+
+struct QD3D12RenderBuffer : public QRhiRenderBuffer
+{
+ QD3D12RenderBuffer(QRhiImplementation *rhi,
+ Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QD3D12RenderBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiTexture::Format backingFormat() const override;
+
+ static const DXGI_FORMAT DS_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT;
+
+ QD3D12ObjectHandle handle;
+ QD3D12Descriptor rtv;
+ QD3D12Descriptor dsv;
+ DXGI_FORMAT dxgiFormat;
+ DXGI_SAMPLE_DESC sampleDesc;
+ uint generation = 0;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12Texture : public QRhiTexture
+{
+ QD3D12Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QD3D12Texture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
+ void setNativeLayout(int layout) override;
+
+ bool prepareCreate(QSize *adjustedSize = nullptr);
+ bool finishCreate();
+
+ QD3D12ObjectHandle handle;
+ QD3D12Descriptor srv;
+ DXGI_FORMAT dxgiFormat;
+ DXGI_FORMAT srvFormat;
+ DXGI_FORMAT rtFormat; // RTV/DSV/UAV
+ uint mipLevelCount;
+ DXGI_SAMPLE_DESC sampleDesc;
+ uint generation = 0;
+ friend class QRhiD3D12;
+ friend struct QD3D12CommandBuffer;
+};
+
+struct QD3D12Sampler : public QRhiSampler
+{
+ QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QD3D12Sampler();
+ void destroy() override;
+ bool create() override;
+
+ QD3D12Descriptor lookupOrCreateShaderVisibleDescriptor();
+
+ D3D12_SAMPLER_DESC desc = {};
+ QD3D12Descriptor shaderVisibleDescriptor;
+};
+
+struct QD3D12RenderPassDescriptor : public QRhiRenderPassDescriptor
+{
+ QD3D12RenderPassDescriptor(QRhiImplementation *rhi);
+ ~QD3D12RenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+
+ void updateSerializedFormat();
+
+ static const int MAX_COLOR_ATTACHMENTS = 8;
+ int colorAttachmentCount = 0;
+ bool hasDepthStencil = false;
+ int colorFormat[MAX_COLOR_ATTACHMENTS];
+ int dsFormat;
+ QVector<quint32> serializedFormatData;
+};
+
+struct QD3D12RenderTargetData
+{
+ QD3D12RenderTargetData(QRhiImplementation *) { }
+
+ QD3D12RenderPassDescriptor *rp = nullptr;
+ QSize pixelSize;
+ float dpr = 1;
+ int sampleCount = 1;
+ int colorAttCount = 0;
+ int dsAttCount = 0;
+ QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+ static const int MAX_COLOR_ATTACHMENTS = QD3D12RenderPassDescriptor::MAX_COLOR_ATTACHMENTS;
+ D3D12_CPU_DESCRIPTOR_HANDLE rtv[MAX_COLOR_ATTACHMENTS];
+ D3D12_CPU_DESCRIPTOR_HANDLE dsv;
+};
+
+struct QD3D12SwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QD3D12SwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QD3D12RenderTargetData d;
+};
+
+struct QD3D12TextureRenderTarget : public QRhiTextureRenderTarget
+{
+ QD3D12TextureRenderTarget(QRhiImplementation *rhi,
+ const QRhiTextureRenderTargetDescription &desc,
+ Flags flags);
+ ~QD3D12TextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QD3D12RenderTargetData d;
+ bool ownsRtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
+ QD3D12Descriptor rtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
+ bool ownsDsv = false;
+ QD3D12Descriptor dsv;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12ShaderResourceBindings : public QRhiShaderResourceBindings
+{
+ QD3D12ShaderResourceBindings(QRhiImplementation *rhi);
+ ~QD3D12ShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+
+ QD3D12ObjectHandle createRootSignature(const QD3D12ShaderStageData *stageData, int stageCount);
+
+ struct VisitorData {
+ QVarLengthArray<D3D12_ROOT_PARAMETER1, 2> cbParams[6];
+
+ D3D12_ROOT_PARAMETER1 srvTables[6] = {};
+ QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> srvRanges[6];
+ quint32 currentSrvRangeOffset[6] = {};
+
+ QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> samplerTables[6];
+ std::array<D3D12_DESCRIPTOR_RANGE1, 16> samplerRanges[6] = {};
+ int samplerRangeHeads[6] = {};
+
+ D3D12_ROOT_PARAMETER1 uavTables[6] = {};
+ QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> uavRanges[6];
+ quint32 currentUavRangeOffset[6] = {};
+ } visitorData;
+
+
+ void visitUniformBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::UniformBufferData &d,
+ int shaderRegister,
+ int binding);
+ void visitTexture(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitSampler(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitStorageBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageBufferData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+ void visitStorageImage(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageImageData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+
+ bool hasDynamicOffset = false;
+ uint generation = 0;
+
+ friend class QRhiD3D12;
+ friend struct QD3D12ShaderResourceVisitor;
+};
+
+struct QD3D12GraphicsPipeline : public QRhiGraphicsPipeline
+{
+ QD3D12GraphicsPipeline(QRhiImplementation *rhi);
+ ~QD3D12GraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+
+ QD3D12ObjectHandle handle;
+ QD3D12ObjectHandle rootSigHandle;
+ std::array<QD3D12ShaderStageData, 5> stageData;
+ D3D12_PRIMITIVE_TOPOLOGY topology;
+ UINT viewInstanceMask = 0;
+ uint generation = 0;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12ComputePipeline : public QRhiComputePipeline
+{
+ QD3D12ComputePipeline(QRhiImplementation *rhi);
+ ~QD3D12ComputePipeline();
+ void destroy() override;
+ bool create() override;
+
+ QD3D12ObjectHandle handle;
+ QD3D12ObjectHandle rootSigHandle;
+ QD3D12ShaderStageData stageData;
+ uint generation = 0;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12CommandBuffer : public QRhiCommandBuffer
+{
+ QD3D12CommandBuffer(QRhiImplementation *rhi);
+ ~QD3D12CommandBuffer();
+ void destroy() override;
+
+ const QRhiNativeHandles *nativeHandles();
+
+ ID3D12GraphicsCommandList1 *cmdList = nullptr; // not owned
+ QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
+
+ enum PassType {
+ NoPass,
+ RenderPass,
+ ComputePass
+ };
+
+ void resetState()
+ {
+ recordingPass = NoPass;
+ currentTarget = nullptr;
+
+ resetPerPassState();
+ }
+
+ void resetPerPassState()
+ {
+ currentGraphicsPipeline = nullptr;
+ currentComputePipeline = nullptr;
+ currentPipelineGeneration = 0;
+ currentGraphicsSrb = nullptr;
+ currentComputeSrb = nullptr;
+ currentSrbGeneration = 0;
+ currentIndexBuffer = {};
+ currentIndexOffset = 0;
+ currentIndexFormat = DXGI_FORMAT_R16_UINT;
+ currentVertexBuffers = {};
+ currentVertexOffsets = {};
+ }
+
+ // per-frame
+ PassType recordingPass;
+ QRhiRenderTarget *currentTarget;
+
+ // per-pass
+ QD3D12GraphicsPipeline *currentGraphicsPipeline;
+ QD3D12ComputePipeline *currentComputePipeline;
+ uint currentPipelineGeneration;
+ QRhiShaderResourceBindings *currentGraphicsSrb;
+ QRhiShaderResourceBindings *currentComputeSrb;
+ uint currentSrbGeneration;
+ QD3D12ObjectHandle currentIndexBuffer;
+ quint32 currentIndexOffset;
+ DXGI_FORMAT currentIndexFormat;
+ std::array<QD3D12ObjectHandle, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexBuffers;
+ std::array<quint32, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexOffsets;
+
+ // global
+ double lastGpuTime = 0;
+
+ // per-setShaderResources
+ struct VisitorData {
+ QVarLengthArray<QPair<QD3D12ObjectHandle, quint32>, 4> cbufs[6];
+ QVarLengthArray<QD3D12Descriptor, 8> srvs[6];
+ QVarLengthArray<QD3D12Descriptor, 8> samplers[6];
+ QVarLengthArray<QPair<QD3D12ObjectHandle, D3D12_UNORDERED_ACCESS_VIEW_DESC>, 4> uavs[6];
+ } visitorData;
+
+ void visitUniformBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::UniformBufferData &d,
+ int shaderRegister,
+ int binding,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets);
+ void visitTexture(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitSampler(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitStorageBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageBufferData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+ void visitStorageImage(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageImageData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+};
+
+struct QD3D12SwapChain : public QRhiSwapChain
+{
+ QD3D12SwapChain(QRhiImplementation *rhi);
+ ~QD3D12SwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+ QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
+
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+ QRhiSwapChainHdrInfo hdrInfo() override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool createOrResize() override;
+
+ void releaseBuffers();
+ void waitCommandCompletionForFrameSlot(int frameSlot);
+ void addCommandCompletionSignalForCurrentFrameSlot();
+ void chooseFormats();
+
+ QWindow *window = nullptr;
+ IDXGISwapChain1 *sourceSwapChain1 = nullptr;
+ IDXGISwapChain3 *swapChain = nullptr;
+ QSize pixelSize;
+ UINT swapInterval = 1;
+ UINT swapChainFlags = 0;
+ BOOL stereo = false;
+ DXGI_FORMAT colorFormat;
+ DXGI_FORMAT srgbAdjustedColorFormat;
+ DXGI_COLOR_SPACE_TYPE hdrColorSpace;
+ IDCompositionTarget *dcompTarget = nullptr;
+ IDCompositionVisual *dcompVisual = nullptr;
+ static const UINT BUFFER_COUNT = 3;
+ QD3D12ObjectHandle colorBuffers[BUFFER_COUNT];
+ QD3D12Descriptor rtvs[BUFFER_COUNT];
+ QD3D12Descriptor rtvsRight[BUFFER_COUNT];
+ DXGI_SAMPLE_DESC sampleDesc;
+ QD3D12ObjectHandle msaaBuffers[BUFFER_COUNT];
+ QD3D12Descriptor msaaRtvs[BUFFER_COUNT];
+ QD3D12RenderBuffer *ds = nullptr;
+ UINT currentBackBufferIndex = 0;
+ QD3D12SwapChainRenderTarget rtWrapper;
+ QD3D12SwapChainRenderTarget rtWrapperRight;
+ QD3D12CommandBuffer cbWrapper;
+
+ struct FrameResources {
+ ID3D12Fence *fence = nullptr;
+ HANDLE fenceEvent = nullptr;
+ UINT64 fenceCounter = 0;
+ ID3D12GraphicsCommandList1 *cmdList = nullptr;
+ } frameRes[QD3D12_FRAMES_IN_FLIGHT];
+
+ int currentFrameSlot = 0; // index in frameRes
+};
+
+template<typename T, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type>
+struct alignas(void*) QD3D12PipelineStateSubObject
+{
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type = Type;
+ T object = {};
+};
+
+class QRhiD3D12 : public QRhiImplementation
+{
+public:
+ // 16MB * QD3D12_FRAMES_IN_FLIGHT; buffer and texture upload staging data that
+ // gets no space from this will get their own temporary staging areas.
+ static const quint32 SMALL_STAGING_AREA_BYTES_PER_FRAME = 16 * 1024 * 1024;
+
+ static const quint32 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE = 16384;
+
+ QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importDevice = nullptr);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ void waitGpu();
+ DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount, DXGI_FORMAT format) const;
+ bool ensureDirectCompositionDevice();
+ bool startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList1 **cmdList);
+ void enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
+ void finishActiveReadbacks(bool forced = false);
+ bool ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ int frameSlot,
+ quint32 neededDescriptorCount,
+ bool *gotNew);
+ void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
+
+ bool debugLayer = false;
+ ID3D12Device2 *dev = nullptr;
+ D3D_FEATURE_LEVEL minimumFeatureLevel = D3D_FEATURE_LEVEL(0);
+ LUID adapterLuid = {};
+ bool importedDevice = false;
+ bool importedCommandQueue = false;
+ QRhi::Flags rhiFlags;
+ IDXGIFactory2 *dxgiFactory = nullptr;
+ bool supportsAllowTearing = false;
+ IDXGIAdapter1 *activeAdapter = nullptr;
+ QRhiDriverInfo driverInfoStruct;
+ QRhiD3D12NativeHandles nativeHandlesStruct;
+ bool deviceLost = false;
+ ID3D12CommandQueue *cmdQueue = nullptr;
+ ID3D12Fence *fullFence = nullptr;
+ HANDLE fullFenceEvent = nullptr;
+ UINT64 fullFenceCounter = 0;
+ ID3D12CommandAllocator *cmdAllocators[QD3D12_FRAMES_IN_FLIGHT] = {};
+ QD3D12MemoryAllocator vma;
+ QD3D12CpuDescriptorPool rtvPool;
+ QD3D12CpuDescriptorPool dsvPool;
+ QD3D12CpuDescriptorPool cbvSrvUavPool;
+ QD3D12ObjectPool<QD3D12Resource> resourcePool;
+ QD3D12ObjectPool<QD3D12Pipeline> pipelinePool;
+ QD3D12ObjectPool<QD3D12RootSignature> rootSignaturePool;
+ QD3D12ReleaseQueue releaseQueue;
+ QD3D12ResourceBarrierGenerator barrierGen;
+ QD3D12SamplerManager samplerMgr;
+ QD3D12MipmapGenerator mipmapGen;
+ QD3D12StagingArea smallStagingAreas[QD3D12_FRAMES_IN_FLIGHT];
+ QD3D12ShaderVisibleDescriptorHeap shaderVisibleCbvSrvUavHeap;
+ UINT64 timestampTicksPerSecond = 0;
+ QD3D12QueryHeap timestampQueryHeap;
+ QD3D12StagingArea timestampReadbackArea;
+ IDCompositionDevice *dcompDevice = nullptr;
+ QD3D12SwapChain *currentSwapChain = nullptr;
+ QSet<QD3D12SwapChain *> swapchains;
+ QD3D12ShaderBytecodeCache shaderBytecodeCache;
+ QVarLengthArray<QD3D12Readback, 4> activeReadbacks;
+ bool offscreenActive = false;
+ QD3D12CommandBuffer *offscreenCb[QD3D12_FRAMES_IN_FLIGHT] = {};
+
+ struct {
+ bool multiView = false;
+ bool textureViewFormat = false;
+ } caps;
+};
+
+QT_END_NAMESPACE
+
+#endif // __ID3D12Device2_INTERFACE_DEFINED__
+
+#endif