7#include <QtCore/private/qsystemerror_p.h>
15#define QRHI_D3D12_HAS_OLD_PIX
18#ifdef __ID3D12Device2_INTERFACE_DEFINED__
23
24
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
68
69
70
71
72
75
76
77
78
79
80
81
82
83
84
85
86
89
90
91
92
93
94
97
98
99
100
101
102
103
104
105
106
107
110
111
112
113
114
115
118
119
120
121
122
123
126
127
128
129
130
131
132
135
136
137
138
139
140
141
142
143
144
145
146
147
148
151
152
155static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
157QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
159 debugLayer = params->enableDebugLayer;
161 if (importParams->dev) {
162 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
163 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
165 d3d12Device->Release();
166 importedDevice =
true;
168 qWarning(
"ID3D12Device2 not supported, cannot import device");
171 if (importParams->commandQueue) {
172 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
173 importedCommandQueue =
true;
175 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
176 adapterLuid.LowPart = importParams->adapterLuidLow;
177 adapterLuid.HighPart = importParams->adapterLuidHigh;
182inline Int aligned(Int v, Int byteAlign)
184 return (v + byteAlign - 1) & ~(byteAlign - 1);
187static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
189 return mipSlice + arraySlice * mipLevels;
192static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
194 switch (rt->resourceType()) {
195 case QRhiResource::SwapChainRenderTarget:
196 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
197 case QRhiResource::TextureRenderTarget:
198 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
203 Q_UNREACHABLE_RETURN(
nullptr);
206bool QRhiD3D12::create(QRhi::Flags flags)
210 UINT factoryFlags = 0;
212 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
213 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
217 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
218 "Attempting to create DXGIFactory2 without it.");
219 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
220 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
225 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
226 qPrintable(QSystemError::windowsComString(hr)));
231 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
232 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
233 if (maxFrameLatency != 0)
234 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
236 supportsAllowTearing =
false;
237 IDXGIFactory5 *factory5 =
nullptr;
238 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
239 BOOL allowTearing =
false;
240 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
241 supportsAllowTearing = allowTearing;
246 ID3D12Debug1 *debug =
nullptr;
247 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
248 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
249 debug->EnableDebugLayer();
254 activeAdapter =
nullptr;
256 if (!importedDevice) {
257 IDXGIAdapter1 *adapter;
258 int requestedAdapterIndex = -1;
259 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
260 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
262 if (requestedRhiAdapter)
263 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
266 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
267 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
268 DXGI_ADAPTER_DESC1 desc;
269 adapter->GetDesc1(&desc);
271 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
272 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
274 requestedAdapterIndex = adapterIndex;
280 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
281 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
282 DXGI_ADAPTER_DESC1 desc;
283 adapter->GetDesc1(&desc);
285 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
286 requestedAdapterIndex = adapterIndex;
292 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
293 DXGI_ADAPTER_DESC1 desc;
294 adapter->GetDesc1(&desc);
295 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
296 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
302 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
303 activeAdapter = adapter;
304 adapterLuid = desc.AdapterLuid;
305 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
306 qCDebug(QRHI_LOG_INFO,
" using this adapter");
311 if (!activeAdapter) {
312 qWarning(
"No adapter");
316 if (minimumFeatureLevel == 0)
317 minimumFeatureLevel = MIN_FEATURE_LEVEL;
319 hr = D3D12CreateDevice(activeAdapter,
321 __uuidof(ID3D12Device2),
322 reinterpret_cast<
void **>(&dev));
324 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
330 adapterLuid = dev->GetAdapterLuid();
331 IDXGIAdapter1 *adapter;
332 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
333 DXGI_ADAPTER_DESC1 desc;
334 adapter->GetDesc1(&desc);
335 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
336 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
338 activeAdapter = adapter;
339 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
345 if (!activeAdapter) {
346 qWarning(
"No adapter");
349 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
352 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
355 ID3D12InfoQueue *infoQueue;
356 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
357 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
358 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
359 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
360 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
362 D3D12_INFO_QUEUE_FILTER filter = {};
363 D3D12_MESSAGE_ID suppressedMessages[2] = {
365 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
367 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
369 filter.DenyList.NumIDs = 2;
370 filter.DenyList.pIDList = suppressedMessages;
373 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
374 filter.DenyList.NumSeverities = 1;
375 filter.DenyList.pSeverityList = &infoSev;
376 infoQueue->PushStorageFilter(&filter);
377 infoQueue->Release();
381 if (!importedCommandQueue) {
382 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
383 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
384 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
385 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
387 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
392 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
394 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
397 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
398 fullFenceCounter = 0;
400 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
401 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
402 __uuidof(ID3D12CommandAllocator),
403 reinterpret_cast<
void **>(&cmdAllocators[i]));
405 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
410 if (!vma.create(dev, activeAdapter)) {
411 qWarning(
"Failed to initialize graphics memory suballocator");
415 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
416 qWarning(
"Could not create RTV pool");
420 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
421 qWarning(
"Could not create DSV pool");
425 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
426 qWarning(
"Could not create CBV-SRV-UAV pool");
430 resourcePool.create(
"main resource pool");
431 pipelinePool.create(
"main pipeline pool");
432 rootSignaturePool.create(
"main root signature pool");
433 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
434 barrierGen.create(&resourcePool);
436 if (!samplerMgr.create(dev)) {
437 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
441 if (!mipmapGen.create(
this)) {
442 qWarning(
"Could not initialize mipmap generator");
446 if (!mipmapGen3D.create(
this)) {
447 qWarning(
"Could not initialize 3D texture mipmap generator");
451 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME, QD3D12StagingArea::ALIGNMENT);
452 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
453 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
454 qWarning(
"Could not create host-visible staging area");
457 QString decoratedName = QLatin1String(
"Small staging area buffer/");
458 decoratedName += QString::number(i);
459 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
462 if (!shaderVisibleCbvSrvUavHeap.create(dev,
463 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
464 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
466 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
470 if (flags.testFlag(QRhi::EnableTimestamps)) {
471 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
487 if (wantsStablePowerState)
488 dev->SetStablePowerState(TRUE);
490 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
492 qWarning(
"Failed to query timestamp frequency: %s",
493 qPrintable(QSystemError::windowsComString(hr)));
496 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
497 qWarning(
"Failed to create timestamp query pool");
500 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
501 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
502 qWarning(
"Failed to create timestamp readback buffer");
505 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
506 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
510 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
511 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
512 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
514 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
517#ifdef QRHI_D3D12_CL5_AVAILABLE
518 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
519 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
520 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
521 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
522 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
523 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
528 caps.vrsAdditionalRates =
false;
532 offscreenActive =
false;
534 nativeHandlesStruct.dev = dev;
535 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
536 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
537 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
538 nativeHandlesStruct.commandQueue = cmdQueue;
543void QRhiD3D12::destroy()
545 if (!deviceLost && fullFence && fullFenceEvent)
548 releaseQueue.releaseAll();
550 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
551 if (offscreenCb[i]) {
552 if (offscreenCb[i]->cmdList)
553 offscreenCb[i]->cmdList->Release();
554 delete offscreenCb[i];
555 offscreenCb[i] =
nullptr;
559 timestampQueryHeap.destroy();
560 timestampReadbackArea.destroy();
562 shaderVisibleCbvSrvUavHeap.destroy();
564 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
565 smallStagingAreas[i].destroy();
568 mipmapGen3D.destroy();
569 samplerMgr.destroy();
570 resourcePool.destroy();
571 pipelinePool.destroy();
572 rootSignaturePool.destroy();
575 cbvSrvUavPool.destroy();
577 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
578 if (cmdAllocators[i]) {
579 cmdAllocators[i]->Release();
580 cmdAllocators[i] =
nullptr;
584 if (fullFenceEvent) {
585 CloseHandle(fullFenceEvent);
586 fullFenceEvent =
nullptr;
590 fullFence->Release();
594 if (!importedCommandQueue) {
603 if (!importedDevice) {
611 dcompDevice->Release();
612 dcompDevice =
nullptr;
616 activeAdapter->Release();
617 activeAdapter =
nullptr;
621 dxgiFactory->Release();
622 dxgiFactory =
nullptr;
626 importedDevice =
false;
627 importedCommandQueue =
false;
629 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
632QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
634 LUID requestedLuid = {};
636 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
637 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
638 if (adapterLuid.LowPart || adapterLuid.HighPart)
639 requestedLuid = adapterLuid;
642 IDXGIFactory2 *dxgi =
nullptr;
643 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
646 QRhi::AdapterList list;
647 IDXGIAdapter1 *adapter;
648 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
649 DXGI_ADAPTER_DESC1 desc;
650 adapter->GetDesc1(&desc);
652 if (requestedLuid.LowPart || requestedLuid.HighPart) {
653 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
654 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
659 QD3D12Adapter *a =
new QD3D12Adapter;
660 a->luid = desc.AdapterLuid;
661 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
669QRhiDriverInfo QD3D12Adapter::info()
const
674QList<
int> QRhiD3D12::supportedSampleCounts()
const
676 return { 1, 2, 4, 8 };
679QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
682 switch (sampleCount) {
685 if (caps.vrsAdditionalRates) {
686 sizes.append(QSize(4, 4));
687 sizes.append(QSize(4, 2));
688 sizes.append(QSize(2, 4));
690 sizes.append(QSize(2, 2));
691 sizes.append(QSize(2, 1));
692 sizes.append(QSize(1, 2));
695 if (caps.vrsAdditionalRates)
696 sizes.append(QSize(2, 4));
697 sizes.append(QSize(2, 2));
698 sizes.append(QSize(2, 1));
699 sizes.append(QSize(1, 2));
702 sizes.append(QSize(2, 2));
703 sizes.append(QSize(2, 1));
704 sizes.append(QSize(1, 2));
709 sizes.append(QSize(1, 1));
713QRhiSwapChain *QRhiD3D12::createSwapChain()
715 return new QD3D12SwapChain(
this);
718QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
720 return new QD3D12Buffer(
this, type, usage, size);
723int QRhiD3D12::ubufAlignment()
const
725 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
728bool QRhiD3D12::isYUpInFramebuffer()
const
733bool QRhiD3D12::isYUpInNDC()
const
738bool QRhiD3D12::isClipDepthZeroToOne()
const
743QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
748 if (m.isIdentity()) {
750 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
751 0.0f, 1.0f, 0.0f, 0.0f,
752 0.0f, 0.0f, 0.5f, 0.5f,
753 0.0f, 0.0f, 0.0f, 1.0f);
758bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
762 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
768bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
771 case QRhi::MultisampleTexture:
773 case QRhi::MultisampleRenderBuffer:
775 case QRhi::DebugMarkers:
776#ifdef QRHI_D3D12_HAS_OLD_PIX
781 case QRhi::Timestamps:
783 case QRhi::Instancing:
785 case QRhi::CustomInstanceStepRate:
787 case QRhi::PrimitiveRestart:
789 case QRhi::NonDynamicUniformBuffers:
791 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
793 case QRhi::NPOTTextureRepeat:
795 case QRhi::RedOrAlpha8IsRed:
797 case QRhi::ElementIndexUint:
801 case QRhi::WideLines:
803 case QRhi::VertexShaderPointSize:
805 case QRhi::BaseVertex:
807 case QRhi::BaseInstance:
809 case QRhi::TriangleFanTopology:
811 case QRhi::ReadBackNonUniformBuffer:
813 case QRhi::ReadBackNonBaseMipLevel:
815 case QRhi::TexelFetch:
817 case QRhi::RenderToNonBaseMipLevel:
819 case QRhi::IntAttributes:
821 case QRhi::ScreenSpaceDerivatives:
823 case QRhi::ReadBackAnyTextureFormat:
825 case QRhi::PipelineCacheDataLoadSave:
827 case QRhi::ImageDataStride:
829 case QRhi::RenderBufferImport:
831 case QRhi::ThreeDimensionalTextures:
833 case QRhi::RenderTo3DTextureSlice:
835 case QRhi::TextureArrays:
837 case QRhi::Tessellation:
839 case QRhi::GeometryShader:
841 case QRhi::TextureArrayRange:
843 case QRhi::NonFillPolygonMode:
845 case QRhi::OneDimensionalTextures:
847 case QRhi::OneDimensionalTextureMipmaps:
849 case QRhi::HalfAttributes:
851 case QRhi::RenderToOneDimensionalTexture:
853 case QRhi::ThreeDimensionalTextureMipmaps:
855 case QRhi::MultiView:
856 return caps.multiView;
857 case QRhi::TextureViewFormat:
858 return caps.textureViewFormat;
859 case QRhi::ResolveDepthStencil:
863 case QRhi::VariableRateShading:
865 case QRhi::VariableRateShadingMap:
866 case QRhi::VariableRateShadingMapWithTexture:
868 case QRhi::PerRenderTargetBlending:
869 case QRhi::SampleVariables:
871 case QRhi::InstanceIndexIncludesBaseInstance:
873 case QRhi::DepthClamp:
879int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
882 case QRhi::TextureSizeMin:
884 case QRhi::TextureSizeMax:
886 case QRhi::MaxColorAttachments:
888 case QRhi::FramesInFlight:
889 return QD3D12_FRAMES_IN_FLIGHT;
890 case QRhi::MaxAsyncReadbackFrames:
891 return QD3D12_FRAMES_IN_FLIGHT;
892 case QRhi::MaxThreadGroupsPerDimension:
894 case QRhi::MaxThreadsPerThreadGroup:
896 case QRhi::MaxThreadGroupX:
898 case QRhi::MaxThreadGroupY:
900 case QRhi::MaxThreadGroupZ:
902 case QRhi::TextureArraySizeMax:
904 case QRhi::MaxUniformBufferRange:
906 case QRhi::MaxVertexInputs:
908 case QRhi::MaxVertexOutputs:
910 case QRhi::ShadingRateImageTileSize:
911 return shadingRateImageTileSize;
916const QRhiNativeHandles *QRhiD3D12::nativeHandles()
918 return &nativeHandlesStruct;
921QRhiDriverInfo QRhiD3D12::driverInfo()
const
923 return driverInfoStruct;
926QRhiStats QRhiD3D12::statistics()
929 result.totalPipelineCreationTime = totalPipelineCreationTime();
931 D3D12MA::Budget budgets[2];
932 vma.getBudget(&budgets[0], &budgets[1]);
933 for (
int i = 0; i < 2; ++i) {
934 const D3D12MA::Statistics &stats(budgets[i].Stats);
935 result.blockCount += stats.BlockCount;
936 result.allocCount += stats.AllocationCount;
937 result.usedBytes += stats.AllocationBytes;
938 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
939 result.totalUsageBytes += budgets[i].UsageBytes;
945bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
951void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
956void QRhiD3D12::releaseCachedResources()
958 shaderBytecodeCache.data.clear();
961bool QRhiD3D12::isDeviceLost()
const
966QByteArray QRhiD3D12::pipelineCacheData()
971void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
976QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
977 int sampleCount, QRhiRenderBuffer::Flags flags,
978 QRhiTexture::Format backingFormatHint)
980 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
983QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
984 const QSize &pixelSize,
int depth,
int arraySize,
985 int sampleCount, QRhiTexture::Flags flags)
987 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
990QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
991 QRhiSampler::Filter mipmapMode,
992 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
994 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
997QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
998 QRhiTextureRenderTarget::Flags flags)
1000 return new QD3D12TextureRenderTarget(
this, desc, flags);
1003QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1005 return new QD3D12ShadingRateMap(
this);
1008QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1010 return new QD3D12GraphicsPipeline(
this);
1013QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1015 return new QD3D12ComputePipeline(
this);
1018QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1020 return new QD3D12ShaderResourceBindings(
this);
1023void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1025 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1026 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1027 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1028 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1030 if (pipelineChanged) {
1031 cbD->currentGraphicsPipeline = psD;
1032 cbD->currentComputePipeline =
nullptr;
1033 cbD->currentPipelineGeneration = psD->generation;
1035 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1036 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1037 cbD->cmdList->SetPipelineState(pipeline->pso);
1038 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1039 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1042 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1044 if (psD->viewInstanceMask)
1045 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1049void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
1050 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1053 int dynamicOffsetCount,
1054 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1056 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1057 quint32 offset = d.offset;
1058 if (d.hasDynamicOffset) {
1059 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1060 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1061 if (dynOfs.first == binding) {
1062 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1063 offset += dynOfs.second;
1067 QRHI_RES_RHI(QRhiD3D12);
1068 visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
1071void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
1072 const QRhiShaderResourceBinding::TextureAndSampler &d,
1075 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1076 visitorData.srvs[s].append(texD->srv);
1079void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
1080 const QRhiShaderResourceBinding::TextureAndSampler &d,
1083 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
1084 visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
1087void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
1088 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1089 QD3D12ShaderResourceVisitor::StorageOp,
1092 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1094 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1095 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1096 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1097 uavDesc.Buffer.FirstElement = d.offset / 4;
1098 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1099 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1100 visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
1103void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
1104 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1105 QD3D12ShaderResourceVisitor::StorageOp,
1108 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1109 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1110 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1111 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1112 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1113 uavDesc.Format = texD->rtFormat;
1115 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1116 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1117 uavDesc.Texture2DArray.FirstArraySlice = 0;
1118 uavDesc.Texture2DArray.ArraySize = 6;
1119 }
else if (isArray) {
1120 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1121 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1122 uavDesc.Texture2DArray.FirstArraySlice = 0;
1123 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1125 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1126 uavDesc.Texture3D.MipSlice = UINT(d.level);
1127 uavDesc.Texture3D.WSize = UINT(-1);
1129 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1130 uavDesc.Texture2D.MipSlice = UINT(d.level);
1132 visitorData.uavs[s].append({ texD->handle, uavDesc });
1135void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1136 int dynamicOffsetCount,
1137 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1139 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1140 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1141 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1142 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1146 srb = gfxPsD->m_shaderResourceBindings;
1148 srb = compPsD->m_shaderResourceBindings;
1151 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1153 bool pipelineChanged =
false;
1155 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD;
1156 srbD->lastUsedGraphicsPipeline = gfxPsD;
1158 pipelineChanged = srbD->lastUsedComputePipeline != compPsD;
1159 srbD->lastUsedComputePipeline = compPsD;
1162 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1163 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1165 case QRhiShaderResourceBinding::UniformBuffer:
1167 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1168 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1169 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1170 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1173 case QRhiShaderResourceBinding::SampledTexture:
1174 case QRhiShaderResourceBinding::Texture:
1175 case QRhiShaderResourceBinding::Sampler:
1177 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1178 for (
int elem = 0; elem < data->count; ++elem) {
1179 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1180 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1184 Q_ASSERT(texD || samplerD);
1187 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1188 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1189 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1190 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1192 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1194 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1195 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1200 case QRhiShaderResourceBinding::ImageLoad:
1201 case QRhiShaderResourceBinding::ImageStore:
1202 case QRhiShaderResourceBinding::ImageLoadStore:
1204 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1205 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1206 if (res->uavUsage) {
1207 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1209 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1211 if (b->type == QRhiShaderResourceBinding::ImageStore
1212 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1215 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1220 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1221 res->uavUsage |= QD3D12Resource::UavUsageRead;
1222 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1223 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1224 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1225 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1229 case QRhiShaderResourceBinding::BufferLoad:
1230 case QRhiShaderResourceBinding::BufferStore:
1231 case QRhiShaderResourceBinding::BufferLoadStore:
1233 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1234 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1235 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1236 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1237 if (res->uavUsage) {
1238 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1240 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1242 if (b->type == QRhiShaderResourceBinding::BufferStore
1243 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1246 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1251 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1252 res->uavUsage |= QD3D12Resource::UavUsageRead;
1253 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1254 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1255 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1256 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1263 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1264 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1266 if (pipelineChanged || srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1267 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1273 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1275 QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
1278 using namespace std::placeholders;
1279 visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1280 visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
1281 visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
1282 visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
1283 visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
1287 quint32 cbvSrvUavCount = 0;
1288 for (
int s = 0; s < 6; ++s) {
1290 cbvSrvUavCount += visitorData.srvs[s].count();
1291 cbvSrvUavCount += visitorData.uavs[s].count();
1294 bool gotNewHeap =
false;
1295 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1296 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1304 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1305 " per-frame slice size is now %u,"
1306 " if this happens frequently then that's not great.",
1307 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1308 bindShaderVisibleHeaps(cbD);
1311 int rootParamIndex = 0;
1312 for (
int s = 0; s < 6; ++s) {
1313 if (!visitorData.cbufs[s].isEmpty()) {
1314 for (
int i = 0, count = visitorData.cbufs[s].count(); i < count; ++i) {
1315 const auto &cbuf(visitorData.cbufs[s][i]);
1316 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.first)) {
1317 quint32 offset = cbuf.second;
1318 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1319 if (cbD->currentGraphicsPipeline)
1320 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1322 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1324 rootParamIndex += 1;
1328 for (
int s = 0; s < 6; ++s) {
1329 if (!visitorData.srvs[s].isEmpty()) {
1330 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1331 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[s].count());
1332 for (
int i = 0, count = visitorData.srvs[s].count(); i < count; ++i) {
1333 const auto &srv(visitorData.srvs[s][i]);
1334 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc, i).cpuHandle, srv.cpuHandle,
1335 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1338 if (cbD->currentGraphicsPipeline)
1339 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1340 else if (cbD->currentComputePipeline)
1341 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1343 rootParamIndex += 1;
1346 for (
int s = 0; s < 6; ++s) {
1349 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.samplers[s]) {
1350 if (cbD->currentGraphicsPipeline)
1351 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1352 else if (cbD->currentComputePipeline)
1353 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1355 rootParamIndex += 1;
1358 for (
int s = 0; s < 6; ++s) {
1359 if (!visitorData.uavs[s].isEmpty()) {
1360 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1361 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[s].count());
1362 for (
int i = 0, count = visitorData.uavs[s].count(); i < count; ++i) {
1363 const auto &uav(visitorData.uavs[s][i]);
1364 if (QD3D12Resource *res = resourcePool.lookupRef(uav.first)) {
1365 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.second,
1366 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1368 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1369 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1373 if (cbD->currentGraphicsPipeline)
1374 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1375 else if (cbD->currentComputePipeline)
1376 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1378 rootParamIndex += 1;
1383 cbD->currentGraphicsSrb = srb;
1384 cbD->currentComputeSrb =
nullptr;
1386 cbD->currentGraphicsSrb =
nullptr;
1387 cbD->currentComputeSrb = srb;
1389 cbD->currentSrbGeneration = srbD->generation;
1393void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1394 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1395 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1397 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1398 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1400 bool needsBindVBuf =
false;
1401 for (
int i = 0; i < bindingCount; ++i) {
1402 const int inputSlot = startBinding + i;
1403 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1404 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1405 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1407 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1409 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1410 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1412 needsBindVBuf =
true;
1413 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1414 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1418 if (needsBindVBuf) {
1419 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1420 vbv.reserve(bindingCount);
1422 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1423 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1424 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1426 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1427 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1428 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1429 const quint32 offset = bindings[i].second;
1430 const quint32 stride = inputLayout.bindingAt(i)->stride();
1432 if (bufD->m_type != QRhiBuffer::Dynamic) {
1433 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1434 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1437 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1439 res->resource->GetGPUVirtualAddress() + offset,
1440 UINT(res->desc.Width - offset),
1446 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1450 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1451 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1452 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1454 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1456 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1457 : DXGI_FORMAT_R32_UINT;
1458 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1459 || cbD->currentIndexOffset != indexOffset
1460 || cbD->currentIndexFormat != dxgiFormat)
1462 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1463 cbD->currentIndexOffset = indexOffset;
1464 cbD->currentIndexFormat = dxgiFormat;
1466 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1467 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1468 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1471 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1472 const D3D12_INDEX_BUFFER_VIEW ibv = {
1473 res->resource->GetGPUVirtualAddress() + indexOffset,
1474 UINT(res->desc.Width - indexOffset),
1477 cbD->cmdList->IASetIndexBuffer(&ibv);
1483void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1485 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1486 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1487 Q_ASSERT(cbD->currentTarget);
1488 const QSize outputSize = cbD->currentTarget->pixelSize();
1492 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1500 v.MinDepth = viewport.minDepth();
1501 v.MaxDepth = viewport.maxDepth();
1502 cbD->cmdList->RSSetViewports(1, &v);
1504 if (cbD->currentGraphicsPipeline
1505 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1507 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
1514 cbD->cmdList->RSSetScissorRects(1, &r);
1518void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1520 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1521 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1522 Q_ASSERT(cbD->currentTarget);
1523 const QSize outputSize = cbD->currentTarget->pixelSize();
1527 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1536 cbD->cmdList->RSSetScissorRects(1, &r);
1539void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1541 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1542 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1543 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1544 cbD->cmdList->OMSetBlendFactor(v);
1547void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1549 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1550 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1551 cbD->cmdList->OMSetStencilRef(refValue);
1554static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1556 if (coarsePixelSize == QSize(1, 2))
1557 return D3D12_SHADING_RATE_1X2;
1558 if (coarsePixelSize == QSize(2, 1))
1559 return D3D12_SHADING_RATE_2X1;
1560 if (coarsePixelSize == QSize(2, 2))
1561 return D3D12_SHADING_RATE_2X2;
1562 if (coarsePixelSize == QSize(2, 4))
1563 return D3D12_SHADING_RATE_2X4;
1564 if (coarsePixelSize == QSize(4, 2))
1565 return D3D12_SHADING_RATE_4X2;
1566 if (coarsePixelSize == QSize(4, 4))
1567 return D3D12_SHADING_RATE_4X4;
1568 return D3D12_SHADING_RATE_1X1;
1571void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
1573 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1574 cbD->hasShadingRateSet =
false;
1576#ifdef QRHI_D3D12_CL5_AVAILABLE
1580 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1581 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
1582 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
1583 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
1584 cbD->hasShadingRateSet =
true;
1587 Q_UNUSED(coarsePixelSize);
1588 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
1592void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1593 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1595 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1596 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1597 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
1600void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1601 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1603 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1604 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1605 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
1606 firstIndex, vertexOffset,
1610void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
1615 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1616#ifdef QRHI_D3D12_HAS_OLD_PIX
1617 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
1624void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
1629 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1630#ifdef QRHI_D3D12_HAS_OLD_PIX
1631 PIXEndEvent(cbD->cmdList);
1637void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
1642 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1643#ifdef QRHI_D3D12_HAS_OLD_PIX
1644 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
1651const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
1653 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
1656void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
1661void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
1663 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1664 cbD->resetPerPassState();
1665 bindShaderVisibleHeaps(cbD);
1666 if (cbD->currentTarget) {
1667 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
1668 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1671 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1675double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
1677 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1678 return cbD->lastGpuTime;
1681static void calculateGpuTime(QD3D12CommandBuffer *cbD,
1682 int timestampPairStartIndex,
1683 const quint8 *readbackBufPtr,
1684 quint64 timestampTicksPerSecond)
1686 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
1687 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
1688 const quint64 startTime = *p++;
1689 const quint64 endTime = *p;
1690 if (startTime < endTime) {
1691 const quint64 ticks = endTime - startTime;
1692 const double timeSec = ticks /
double(timestampTicksPerSecond);
1693 cbD->lastGpuTime = timeSec;
1697QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
1701 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1702 currentSwapChain = swapChainD;
1703 currentFrameSlot = swapChainD->currentFrameSlot;
1704 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1717 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1718 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1720 if (swapChainD->frameLatencyWaitableObject) {
1722 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
1723 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
1724 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
1728 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1730 qWarning(
"Failed to reset command allocator: %s",
1731 qPrintable(QSystemError::windowsComString(hr)));
1732 return QRhi::FrameOpError;
1735 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1736 return QRhi::FrameOpError;
1738 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1739 cbD->cmdList = fr.cmdList;
1741 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1742 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1743 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1745 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1746 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1748 if (swapChainD->stereo) {
1749 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1750 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1751 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
1753 swapChainD->rtWrapperRight.d.dsv =
1754 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
1761 releaseQueue.executeDeferredReleases(currentFrameSlot);
1767 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1769 smallStagingAreas[currentFrameSlot].head = 0;
1771 bindShaderVisibleHeaps(cbD);
1773 finishActiveReadbacks();
1775 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1778 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1779 calculateGpuTime(cbD,
1780 timestampPairStartIndex,
1781 timestampReadbackArea.mem.p,
1782 timestampTicksPerSecond);
1784 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1785 D3D12_QUERY_TYPE_TIMESTAMP,
1786 timestampPairStartIndex);
1789 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
1791 return QRhi::FrameOpSuccess;
1794QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
1796 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1797 Q_ASSERT(currentSwapChain == swapChainD);
1798 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1800 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1801 if (swapChainD->sampleDesc.Count > 1) {
1802 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1803 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1804 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1805 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1806 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1807 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
1809 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
1812 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1813 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1815 if (timestampQueryHeap.isValid()) {
1816 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1817 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1818 D3D12_QUERY_TYPE_TIMESTAMP,
1819 timestampPairStartIndex + 1);
1820 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1821 D3D12_QUERY_TYPE_TIMESTAMP,
1822 timestampPairStartIndex,
1824 timestampReadbackArea.mem.buffer,
1825 timestampPairStartIndex *
sizeof(quint64));
1828 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1829 HRESULT hr = cmdList->Close();
1831 qWarning(
"Failed to close command list: %s",
1832 qPrintable(QSystemError::windowsComString(hr)));
1833 return QRhi::FrameOpError;
1836 ID3D12CommandList *execList[] = { cmdList };
1837 cmdQueue->ExecuteCommandLists(1, execList);
1839 if (!flags.testFlag(QRhi::SkipPresent)) {
1840 UINT presentFlags = 0;
1841 if (swapChainD->swapInterval == 0
1842 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1844 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1846 if (!swapChainD->swapChain) {
1847 qWarning(
"Failed to present, no swapchain");
1848 return QRhi::FrameOpError;
1850 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
1851 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
1852 qWarning(
"Device loss detected in Present()");
1854 return QRhi::FrameOpDeviceLost;
1855 }
else if (FAILED(hr)) {
1856 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
1857 return QRhi::FrameOpError;
1860 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
1861 dcompDevice->Commit();
1864 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
1871 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1873 if (!flags.testFlag(QRhi::SkipPresent)) {
1877 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1878 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
1881 currentSwapChain =
nullptr;
1882 return QRhi::FrameOpSuccess;
1885QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
1898 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1900 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1901 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1903 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1905 qWarning(
"Failed to reset command allocator: %s",
1906 qPrintable(QSystemError::windowsComString(hr)));
1907 return QRhi::FrameOpError;
1910 if (!offscreenCb[currentFrameSlot])
1911 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
1912 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1913 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
1914 return QRhi::FrameOpError;
1916 releaseQueue.executeDeferredReleases(currentFrameSlot);
1918 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1919 smallStagingAreas[currentFrameSlot].head = 0;
1921 bindShaderVisibleHeaps(cbD);
1923 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1924 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1925 D3D12_QUERY_TYPE_TIMESTAMP,
1926 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
1929 offscreenActive =
true;
1932 return QRhi::FrameOpSuccess;
1935QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
1938 Q_ASSERT(offscreenActive);
1939 offscreenActive =
false;
1941 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1942 if (timestampQueryHeap.isValid()) {
1943 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1944 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1945 D3D12_QUERY_TYPE_TIMESTAMP,
1946 timestampPairStartIndex + 1);
1947 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1948 D3D12_QUERY_TYPE_TIMESTAMP,
1949 timestampPairStartIndex,
1951 timestampReadbackArea.mem.buffer,
1952 timestampPairStartIndex *
sizeof(quint64));
1955 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1956 HRESULT hr = cmdList->Close();
1958 qWarning(
"Failed to close command list: %s",
1959 qPrintable(QSystemError::windowsComString(hr)));
1960 return QRhi::FrameOpError;
1963 ID3D12CommandList *execList[] = { cmdList };
1964 cmdQueue->ExecuteCommandLists(1, execList);
1966 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1973 finishActiveReadbacks(
true);
1976 if (timestampQueryHeap.isValid()) {
1977 calculateGpuTime(cbD,
1978 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
1979 timestampReadbackArea.mem.p,
1980 timestampTicksPerSecond);
1983 return QRhi::FrameOpSuccess;
1986QRhi::FrameOpResult QRhiD3D12::finish()
1988 QD3D12CommandBuffer *cbD =
nullptr;
1990 if (offscreenActive) {
1991 Q_ASSERT(!currentSwapChain);
1992 cbD = offscreenCb[currentFrameSlot];
1994 Q_ASSERT(currentSwapChain);
1995 cbD = ¤tSwapChain->cbWrapper;
1998 return QRhi::FrameOpError;
2000 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2002 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2003 HRESULT hr = cmdList->Close();
2005 qWarning(
"Failed to close command list: %s",
2006 qPrintable(QSystemError::windowsComString(hr)));
2007 return QRhi::FrameOpError;
2010 ID3D12CommandList *execList[] = { cmdList };
2011 cmdQueue->ExecuteCommandLists(1, execList);
2013 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2020 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2022 qWarning(
"Failed to reset command allocator: %s",
2023 qPrintable(QSystemError::windowsComString(hr)));
2024 return QRhi::FrameOpError;
2027 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2028 return QRhi::FrameOpError;
2032 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2033 smallStagingAreas[currentFrameSlot].head = 0;
2035 bindShaderVisibleHeaps(cbD);
2038 releaseQueue.releaseAll();
2039 finishActiveReadbacks(
true);
2041 return QRhi::FrameOpSuccess;
2044void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2046 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2047 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2048 enqueueResourceUpdates(cbD, resourceUpdates);
2051void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2052 QRhiRenderTarget *rt,
2053 const QColor &colorClearValue,
2054 const QRhiDepthStencilClearValue &depthStencilClearValue,
2055 QRhiResourceUpdateBatch *resourceUpdates,
2056 QRhiCommandBuffer::BeginPassFlags)
2058 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2059 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2061 if (resourceUpdates)
2062 enqueueResourceUpdates(cbD, resourceUpdates);
2064 QD3D12RenderTargetData *rtD = rtData(rt);
2065 bool wantsColorClear =
true;
2066 bool wantsDsClear =
true;
2067 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2068 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2069 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2070 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2071 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2074 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2075 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2076 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2077 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2079 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2081 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2083 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2085 if (rtTex->m_desc.depthStencilBuffer()) {
2086 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2087 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2088 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2089 }
else if (rtTex->m_desc.depthTexture()) {
2090 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2091 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2093 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2095 Q_ASSERT(currentSwapChain);
2096 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2097 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
2098 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2099 D3D12_RESOURCE_STATE_RENDER_TARGET);
2100 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2103 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2106 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2108 if (rtD->colorAttCount && wantsColorClear) {
2109 float clearColor[4] = {
2110 colorClearValue.redF(),
2111 colorClearValue.greenF(),
2112 colorClearValue.blueF(),
2113 colorClearValue.alphaF()
2115 for (
int i = 0; i < rtD->colorAttCount; ++i)
2116 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2118 if (rtD->dsAttCount && wantsDsClear) {
2119 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2120 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2121 depthStencilClearValue.depthClearValue(),
2122 UINT8(depthStencilClearValue.stencilClearValue()),
2127 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2128 cbD->currentTarget = rt;
2130 bool hasShadingRateMapSet =
false;
2131#ifdef QRHI_D3D12_CL5_AVAILABLE
2132 if (rtD->rp->hasShadingRateMap) {
2133 cbD->setShadingRate(QSize(1, 1));
2134 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2135 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2136 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2137 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2138 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2139 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2140 cbD->cmdList->RSSetShadingRateImage(res->resource);
2141 hasShadingRateMapSet =
true;
2143 }
else if (cbD->hasShadingRateMapSet) {
2144 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2145 cbD->setShadingRate(QSize(1, 1));
2146 }
else if (cbD->hasShadingRateSet) {
2147 cbD->setShadingRate(QSize(1, 1));
2151 cbD->resetPerPassState();
2154 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2157void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2159 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2160 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2162 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2163 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2164 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2167 const QRhiColorAttachment &colorAtt(*it);
2168 if (!colorAtt.resolveTexture())
2171 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2172 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2176 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2177 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2178 Q_ASSERT(srcTexD || srcRbD);
2179 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2184 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2185 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2186 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2189 if (srcTexD->sampleDesc.Count <= 1) {
2190 qWarning(
"Cannot resolve a non-multisample texture");
2193 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2194 qWarning(
"Resolve source and destination sizes do not match");
2198 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2199 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2200 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2203 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2204 qWarning(
"Resolve source and destination sizes do not match");
2209 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2210 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2211 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2213 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2214 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2215 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2216 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2217 UINT(colorAtt.resolveLayer()) + resolveIdx,
2218 dstTexD->mipLevelCount);
2219 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
2220 srcRes->resource, srcSubresource,
2221 dstTexD->dxgiFormat);
2224 if (rtTex->m_desc.depthResolveTexture())
2225 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2228 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2229 cbD->currentTarget =
nullptr;
2231 if (resourceUpdates)
2232 enqueueResourceUpdates(cbD, resourceUpdates);
2235void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2236 QRhiResourceUpdateBatch *resourceUpdates,
2237 QRhiCommandBuffer::BeginPassFlags)
2239 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2240 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2242 if (resourceUpdates)
2243 enqueueResourceUpdates(cbD, resourceUpdates);
2245 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2247 cbD->resetPerPassState();
2250void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2252 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2253 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2255 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2257 if (resourceUpdates)
2258 enqueueResourceUpdates(cbD, resourceUpdates);
2261void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2263 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2264 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2265 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2266 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2268 if (pipelineChanged) {
2269 cbD->currentGraphicsPipeline =
nullptr;
2270 cbD->currentComputePipeline = psD;
2271 cbD->currentPipelineGeneration = psD->generation;
2273 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2274 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2275 cbD->cmdList->SetPipelineState(pipeline->pso);
2276 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2277 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2282void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2284 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2285 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2286 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2289bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2290 quint32 descriptorCount,
2291 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2292 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2295 capacity = descriptorCount;
2296 this->heapType = heapType;
2297 this->heapFlags = heapFlags;
2299 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2300 heapDesc.Type = heapType;
2301 heapDesc.NumDescriptors = capacity;
2302 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2304 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2306 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2308 capacity = descriptorByteSize = 0;
2312 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2313 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2314 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2315 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2320void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2321 quint32 offsetInDescriptors,
2322 quint32 descriptorCount)
2326 capacity = descriptorCount;
2327 heapType = other.heapType;
2328 heapFlags = other.heapFlags;
2329 descriptorByteSize = other.descriptorByteSize;
2330 heapStart = incremented(other.heapStart, offsetInDescriptors);
2333void QD3D12DescriptorHeap::destroy()
2342void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2345 releaseQueue->deferredReleaseDescriptorHeap(heap);
2351QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2353 Q_ASSERT(count > 0);
2354 if (head + count > capacity) {
2355 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2359 return at(head - count);
2362QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2364 const quint32 startOffset = index * descriptorByteSize;
2365 QD3D12Descriptor result;
2366 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2367 if (heapStart.gpuHandle.ptr != 0)
2368 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2372bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2374 QD3D12DescriptorHeap firstHeap;
2375 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2377 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2378 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2379 this->device = device;
2380 this->debugName = debugName;
2384void QD3D12CpuDescriptorPool::destroy()
2388 static bool leakCheck =
true;
2391 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2394 for (HeapWithMap &heap : heaps) {
2395 const int leakedDescriptorCount = heap.map.count(
true);
2396 if (leakedDescriptorCount > 0) {
2397 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2398 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2399 &heap.heap,
this, debugName, leakedDescriptorCount);
2403 for (HeapWithMap &heap : heaps)
2404 heap.heap.destroy();
2408QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2410 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2412 HeapWithMap &last(heaps.last());
2413 if (last.heap.head + count <= last.heap.capacity) {
2414 quint32 firstIndex = last.heap.head;
2415 for (quint32 i = 0; i < count; ++i)
2416 last.map.setBit(firstIndex + i);
2417 return last.heap.get(count);
2420 for (HeapWithMap &heap : heaps) {
2421 quint32 freeCount = 0;
2422 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2423 if (heap.map.testBit(i)) {
2427 if (freeCount == count) {
2428 quint32 firstIndex = i - (freeCount - 1);
2429 for (quint32 j = 0; j < count; ++j) {
2430 heap.map.setBit(firstIndex + j);
2431 return heap.heap.at(firstIndex);
2438 QD3D12DescriptorHeap newHeap;
2439 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2442 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2444 for (quint32 i = 0; i < count; ++i)
2445 heaps.last().map.setBit(i);
2447 return heaps.last().heap.get(count);
2450void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
2452 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2453 if (!descriptor.isValid())
2456 const SIZE_T addr = descriptor.cpuHandle.ptr;
2457 for (HeapWithMap &heap : heaps) {
2458 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
2459 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2460 if (addr >= begin && addr < end) {
2461 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
2462 for (quint32 i = 0; i < count; ++i)
2463 heap.map.setBit(firstIndex + i,
false);
2468 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2469 quint64(descriptor.cpuHandle.ptr));
2472bool QD3D12QueryHeap::create(ID3D12Device *device,
2474 D3D12_QUERY_HEAP_TYPE heapType)
2476 capacity = queryCount;
2478 D3D12_QUERY_HEAP_DESC heapDesc = {};
2479 heapDesc.Type = heapType;
2480 heapDesc.Count = capacity;
2482 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
2484 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2493void QD3D12QueryHeap::destroy()
2502bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
2504 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2505 D3D12_RESOURCE_DESC resourceDesc = {};
2506 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2507 resourceDesc.Width = capacity;
2508 resourceDesc.Height = 1;
2509 resourceDesc.DepthOrArraySize = 1;
2510 resourceDesc.MipLevels = 1;
2511 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2512 resourceDesc.SampleDesc = { 1, 0 };
2513 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2514 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2515 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2516 HRESULT hr = rhi->vma.createResource(heapType,
2518 D3D12_RESOURCE_STATES(state),
2521 __uuidof(ID3D12Resource),
2522 reinterpret_cast<
void **>(&resource));
2524 qWarning(
"Failed to create buffer for staging area: %s",
2525 qPrintable(QSystemError::windowsComString(hr)));
2529 hr = resource->Map(0,
nullptr, &p);
2531 qWarning(
"Failed to map buffer for staging area: %s",
2532 qPrintable(QSystemError::windowsComString(hr)));
2537 mem.p =
static_cast<quint8 *>(p);
2538 mem.gpuAddr = resource->GetGPUVirtualAddress();
2539 mem.buffer = resource;
2540 mem.bufferOffset = 0;
2542 this->capacity = capacity;
2548void QD3D12StagingArea::destroy()
2551 resource->Release();
2555 allocation->Release();
2556 allocation =
nullptr;
2561void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2564 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
2568QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
2570 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
2571 if (head + allocSize > capacity) {
2572 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2573 allocSize, byteSize, capacity, remainingCapacity());
2576 const quint32 offset = head;
2580 mem.gpuAddr + offset,
2589void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
2591 DeferredReleaseEntry e;
2596void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
2597 QD3D12CpuDescriptorPool *pool,
2598 const QD3D12Descriptor &viewsStart,
2601 DeferredReleaseEntry e;
2602 e.type = DeferredReleaseEntry::Resource;
2604 e.poolForViews = pool;
2605 e.viewsStart = viewsStart;
2606 e.viewCount = viewCount;
2610void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
2612 DeferredReleaseEntry e;
2613 e.type = DeferredReleaseEntry::Pipeline;
2618void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
2620 DeferredReleaseEntry e;
2621 e.type = DeferredReleaseEntry::RootSignature;
2626void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2628 DeferredReleaseEntry e;
2629 e.type = DeferredReleaseEntry::Callback;
2630 e.callback = callback;
2631 e.callbackUserData = userData;
2635void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2636 D3D12MA::Allocation *allocation)
2638 DeferredReleaseEntry e;
2639 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2640 e.resourceAndAllocation = { resource, allocation };
2644void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2646 DeferredReleaseEntry e;
2647 e.type = DeferredReleaseEntry::DescriptorHeap;
2648 e.descriptorHeap = heap;
2652void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
2653 const QD3D12Descriptor &viewsStart,
2656 DeferredReleaseEntry e;
2657 e.type = DeferredReleaseEntry::Views;
2658 e.poolForViews = pool;
2659 e.viewsStart = viewsStart;
2660 e.viewCount = viewCount;
2664void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2666 for (DeferredReleaseEntry &e : queue) {
2667 if (!e.frameSlotToBeReleasedIn.has_value())
2668 e.frameSlotToBeReleasedIn = frameSlot;
2672void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2674 for (
int i = queue.count() - 1; i >= 0; --i) {
2675 const DeferredReleaseEntry &e(queue[i]);
2676 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2678 case DeferredReleaseEntry::Resource:
2679 resourcePool->remove(e.handle);
2680 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
2681 e.poolForViews->release(e.viewsStart, e.viewCount);
2683 case DeferredReleaseEntry::Pipeline:
2684 pipelinePool->remove(e.handle);
2686 case DeferredReleaseEntry::RootSignature:
2687 rootSignaturePool->remove(e.handle);
2689 case DeferredReleaseEntry::Callback:
2690 e.callback(e.callbackUserData);
2692 case DeferredReleaseEntry::ResourceAndAllocation:
2695 e.resourceAndAllocation.first->Release();
2696 if (e.resourceAndAllocation.second)
2697 e.resourceAndAllocation.second->Release();
2699 case DeferredReleaseEntry::DescriptorHeap:
2700 e.descriptorHeap->Release();
2702 case DeferredReleaseEntry::Views:
2703 e.poolForViews->release(e.viewsStart, e.viewCount);
2711void QD3D12ReleaseQueue::releaseAll()
2713 executeDeferredReleases(0,
true);
2716void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2717 D3D12_RESOURCE_STATES stateAfter)
2719 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2720 if (stateAfter != res->state) {
2721 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
2722 res->state = stateAfter;
2727void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2729 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
2730 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2731 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
2732 D3D12_RESOURCE_BARRIER barrier = {};
2733 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2734 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2735 barrier.Transition.pResource = res->resource;
2736 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2737 barrier.Transition.StateBefore = trb.stateBefore;
2738 barrier.Transition.StateAfter = trb.stateAfter;
2739 barriers.append(barrier);
2742 transitionResourceBarriers.clear();
2743 if (!barriers.isEmpty())
2744 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
2747void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2748 const QD3D12ObjectHandle &resourceHandle,
2750 D3D12_RESOURCE_STATES stateBefore,
2751 D3D12_RESOURCE_STATES stateAfter)
2753 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2754 D3D12_RESOURCE_BARRIER barrier = {};
2755 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2756 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2757 barrier.Transition.pResource = res->resource;
2758 barrier.Transition.Subresource = subresource;
2759 barrier.Transition.StateBefore = stateBefore;
2760 barrier.Transition.StateAfter = stateAfter;
2761 cbD->cmdList->ResourceBarrier(1, &barrier);
2765void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2766 const QD3D12ObjectHandle &resourceHandle)
2768 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2769 D3D12_RESOURCE_BARRIER barrier = {};
2770 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2771 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2772 barrier.UAV.pResource = res->resource;
2773 cbD->cmdList->ResourceBarrier(1, &barrier);
2777void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
2779 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2781 data.insert(key, s);
2784bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
2785 D3D12_DESCRIPTOR_HEAP_TYPE type,
2786 quint32 perFrameDescriptorCount)
2788 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2790 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2793 const quint32 CBV_SRV_UAV_MAX = 1000000;
2794 const quint32 SAMPLER_MAX = 2048;
2795 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2796 size = qMin(size, CBV_SRV_UAV_MAX);
2797 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2798 size = qMin(size, SAMPLER_MAX);
2800 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2801 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
2805 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
2806 quint32 currentOffsetInDescriptors = 0;
2807 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
2808 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2809 currentOffsetInDescriptors += perFrameDescriptorCount;
2815void QD3D12ShaderVisibleDescriptorHeap::destroy()
2820void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2822 heap.destroyWithDeferredRelease(releaseQueue);
2825static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
2828 return { binding, binding };
2830 auto it = map.constFind(binding);
2831 if (it != map.cend())
2840void QD3D12ShaderResourceVisitor::visit()
2842 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2843 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
2844 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
2846 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
2847 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
2851 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
2855 case QRhiShaderResourceBinding::UniformBuffer:
2857 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2858 if (shaderRegister >= 0 && uniformBuffer)
2859 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
2862 case QRhiShaderResourceBinding::SampledTexture:
2864 Q_ASSERT(bd->u.stex.count > 0);
2865 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2866 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
2867 for (
int i = 0; i < bd->u.stex.count; ++i) {
2868 if (textureBaseShaderRegister >= 0 && texture)
2869 texture(sd->stage, bd->u.stex.texSamplers[i], textureBaseShaderRegister + i);
2870 if (samplerBaseShaderRegister >= 0 && sampler)
2871 sampler(sd->stage, bd->u.stex.texSamplers[i], samplerBaseShaderRegister + i);
2875 case QRhiShaderResourceBinding::Texture:
2877 Q_ASSERT(bd->u.stex.count > 0);
2878 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2879 if (baseShaderRegister >= 0 && texture) {
2880 for (
int i = 0; i < bd->u.stex.count; ++i)
2881 texture(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
2885 case QRhiShaderResourceBinding::Sampler:
2887 Q_ASSERT(bd->u.stex.count > 0);
2888 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2889 if (baseShaderRegister >= 0 && sampler) {
2890 for (
int i = 0; i < bd->u.stex.count; ++i)
2891 sampler(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
2895 case QRhiShaderResourceBinding::ImageLoad:
2897 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2898 if (shaderRegister >= 0 && storageImage)
2899 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
2902 case QRhiShaderResourceBinding::ImageStore:
2904 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2905 if (shaderRegister >= 0 && storageImage)
2906 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
2909 case QRhiShaderResourceBinding::ImageLoadStore:
2911 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2912 if (shaderRegister >= 0 && storageImage)
2913 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
2916 case QRhiShaderResourceBinding::BufferLoad:
2918 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2919 if (shaderRegister >= 0 && storageBuffer)
2920 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
2923 case QRhiShaderResourceBinding::BufferStore:
2925 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2926 if (shaderRegister >= 0 && storageBuffer)
2927 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
2930 case QRhiShaderResourceBinding::BufferLoadStore:
2932 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2933 if (shaderRegister >= 0 && storageBuffer)
2934 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
2942bool QD3D12SamplerManager::create(ID3D12Device *device)
2945 if (!shaderVisibleSamplerHeap.create(device,
2946 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
2947 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
2949 qWarning(
"Could not create shader-visible SAMPLER heap");
2953 this->device = device;
2957void QD3D12SamplerManager::destroy()
2960 shaderVisibleSamplerHeap.destroy();
2965QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
2967 auto it = gpuMap.constFind({desc});
2968 if (it != gpuMap.cend())
2971 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
2972 if (descriptor.isValid()) {
2973 device->CreateSampler(&desc, descriptor.cpuHandle);
2974 gpuMap.insert({desc}, descriptor);
2976 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
2977 " this should not happen, maximum number of unique samplers is %u",
2978 shaderVisibleSamplerHeap.heap.capacity);
2984bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
2988 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
2989 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
2992 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
2993 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2994 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
2997 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
2998 descriptorRanges[0].NumDescriptors = 1;
2999 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3000 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3001 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3002 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3003 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3006 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3007 descriptorRanges[1].NumDescriptors = 4;
3008 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3009 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3010 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3011 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3014 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3015 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3016 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3017 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3018 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3019 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3021 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3022 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3023 rsDesc.Desc_1_1.NumParameters = 3;
3024 rsDesc.Desc_1_1.pParameters = rootParams;
3025 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3026 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3028 ID3DBlob *signature =
nullptr;
3029 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3031 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3034 ID3D12RootSignature *rootSig =
nullptr;
3035 hr = rhiD->dev->CreateRootSignature(0,
3036 signature->GetBufferPointer(),
3037 signature->GetBufferSize(),
3038 __uuidof(ID3D12RootSignature),
3039 reinterpret_cast<
void **>(&rootSig));
3040 signature->Release();
3042 qWarning(
"Failed to create root signature: %s",
3043 qPrintable(QSystemError::windowsComString(hr)));
3047 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3049 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3050 psoDesc.pRootSignature = rootSig;
3051 psoDesc.CS.pShaderBytecode = g_csMipmap;
3052 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3053 ID3D12PipelineState *pso =
nullptr;
3054 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3055 __uuidof(ID3D12PipelineState),
3056 reinterpret_cast<
void **>(&pso));
3058 qWarning(
"Failed to create compute pipeline state: %s",
3059 qPrintable(QSystemError::windowsComString(hr)));
3060 rhiD->rootSignaturePool.remove(rootSigHandle);
3065 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3070void QD3D12MipmapGenerator::destroy()
3072 rhiD->pipelinePool.remove(pipelineHandle);
3073 pipelineHandle = {};
3074 rhiD->rootSignaturePool.remove(rootSigHandle);
3078void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3080 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3083 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3086 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3090 const quint32 mipLevelCount = res->desc.MipLevels;
3091 if (mipLevelCount < 2)
3094 if (res->desc.SampleDesc.Count > 1) {
3095 qWarning(
"Cannot generate mipmaps for MSAA texture");
3099 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3101 qWarning(
"Cannot generate mipmaps for 1D texture");
3105 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3106 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3107 && res->desc.DepthOrArraySize > 1;
3108 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3111 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3115 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3116 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3118 cbD->cmdList->SetPipelineState(pipeline->pso);
3119 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3121 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3124 quint32 srcMipLevel;
3125 quint32 numMipLevels;
3130 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3131 std::optional<QD3D12StagingArea> ownStagingArea;
3132 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3133 ownStagingArea = QD3D12StagingArea();
3134 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3135 qWarning(
"Could not create staging area for mipmap generation");
3139 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3140 ? &ownStagingArea.value()
3141 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3143 bool gotNewHeap =
false;
3144 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3145 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3146 rhiD->currentFrameSlot,
3147 (1 + 4) * mipLevelCount * layerCount,
3150 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3154 rhiD->bindShaderVisibleHeaps(cbD);
3156 for (quint32 layer = 0; layer < layerCount; ++layer) {
3157 for (quint32 level = 0; level < mipLevelCount ;) {
3158 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3159 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3160 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3161 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3163 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3164 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3165 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3166 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3168 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3169 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3170 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3171 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3173 CBufData cbufData = {
3176 1.0f /
float(levelPlusOneMipWidth),
3177 1.0f /
float(levelPlusOneMipHeight)
3180 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3181 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3182 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3184 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3185 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3186 srvDesc.Format = res->desc.Format;
3187 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3188 if (isCubeOrArray) {
3189 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3190 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3191 srvDesc.Texture2DArray.FirstArraySlice = layer;
3192 srvDesc.Texture2DArray.ArraySize = 1;
3194 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3195 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3197 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3198 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3200 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3201 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3203 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3204 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3205 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3206 uavDesc.Format = res->desc.Format;
3207 if (isCubeOrArray) {
3208 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3209 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3210 uavDesc.Texture2DArray.FirstArraySlice = layer;
3211 uavDesc.Texture2DArray.ArraySize = 1;
3213 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3214 uavDesc.Texture2D.MipSlice = uavMipLevel;
3216 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3217 uavCpuHandle.ptr += descriptorByteSize;
3219 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3221 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3223 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3224 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3225 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3226 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3228 level += numGenMips;
3232 if (ownStagingArea.has_value())
3233 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3236bool QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
3240 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3241 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3244 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3245 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3246 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3249 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3250 descriptorRanges[0].NumDescriptors = 1;
3251 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3252 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3253 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3254 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3255 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3258 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3259 descriptorRanges[1].NumDescriptors = 1;
3260 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3261 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3262 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3263 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3266 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3267 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3268 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3269 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3270 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3271 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3273 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3274 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3275 rsDesc.Desc_1_1.NumParameters = 3;
3276 rsDesc.Desc_1_1.pParameters = rootParams;
3277 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3278 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3280 ID3DBlob *signature =
nullptr;
3281 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3283 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3286 ID3D12RootSignature *rootSig =
nullptr;
3287 hr = rhiD->dev->CreateRootSignature(0,
3288 signature->GetBufferPointer(),
3289 signature->GetBufferSize(),
3290 __uuidof(ID3D12RootSignature),
3291 reinterpret_cast<
void **>(&rootSig));
3292 signature->Release();
3294 qWarning(
"Failed to create root signature: %s",
3295 qPrintable(QSystemError::windowsComString(hr)));
3299 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3301 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3302 psoDesc.pRootSignature = rootSig;
3303 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
3304 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
3305 ID3D12PipelineState *pso =
nullptr;
3306 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3307 __uuidof(ID3D12PipelineState),
3308 reinterpret_cast<
void **>(&pso));
3310 qWarning(
"Failed to create compute pipeline state: %s",
3311 qPrintable(QSystemError::windowsComString(hr)));
3312 rhiD->rootSignaturePool.remove(rootSigHandle);
3317 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3322void QD3D12MipmapGenerator3D::destroy()
3324 rhiD->pipelinePool.remove(pipelineHandle);
3325 pipelineHandle = {};
3326 rhiD->rootSignaturePool.remove(rootSigHandle);
3330void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3332 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3335 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3338 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3342 const quint32 mipLevelCount = res->desc.MipLevels;
3343 if (mipLevelCount < 2)
3346 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3348 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
3352 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3353 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3355 cbD->cmdList->SetPipelineState(pipeline->pso);
3356 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3358 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3364 quint32 srcMipLevel;
3367 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
3368 std::optional<QD3D12StagingArea> ownStagingArea;
3369 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3370 ownStagingArea = QD3D12StagingArea();
3371 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3372 qWarning(
"Could not create staging area for mipmap generation");
3376 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3377 ? &ownStagingArea.value()
3378 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3380 bool gotNewHeap =
false;
3381 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3382 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3383 rhiD->currentFrameSlot,
3384 (1 + 1) * mipLevelCount,
3387 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3391 rhiD->bindShaderVisibleHeaps(cbD);
3393 for (quint32 level = 0; level < mipLevelCount; ++level) {
3394 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
3395 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3396 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3397 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3399 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
3400 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
3401 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
3403 CBufData cbufData = {
3404 1.0f /
float(levelPlusOneMipWidth),
3405 1.0f /
float(levelPlusOneMipHeight),
3406 1.0f /
float(levelPlusOneMipDepth),
3410 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3411 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3412 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3414 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3415 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3416 srvDesc.Format = res->desc.Format;
3417 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3418 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
3419 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
3421 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3422 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3424 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3425 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3426 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
3427 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3428 uavDesc.Format = res->desc.Format;
3429 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
3430 uavDesc.Texture3D.MipSlice = uavMipLevel;
3431 uavDesc.Texture3D.WSize = UINT(-1);
3432 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3433 uavCpuHandle.ptr += descriptorByteSize;
3434 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3436 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
3438 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3439 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3440 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3441 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3444 if (ownStagingArea.has_value())
3445 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3448bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
3450 this->device = device;
3457 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
3461 DXGI_ADAPTER_DESC1 desc;
3462 adapter->GetDesc1(&desc);
3463 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
3466 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3467 allocatorDesc.pDevice = device;
3468 allocatorDesc.pAdapter = adapter;
3471 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
3472 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3474 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
3475 qPrintable(QSystemError::windowsComString(hr)));
3481void QD3D12MemoryAllocator::destroy()
3484 allocator->Release();
3485 allocator =
nullptr;
3489HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
3490 const D3D12_RESOURCE_DESC *resourceDesc,
3491 D3D12_RESOURCE_STATES initialState,
3492 const D3D12_CLEAR_VALUE *optimizedClearValue,
3493 D3D12MA::Allocation **maybeAllocation,
3494 REFIID riidResource,
3498 D3D12MA::ALLOCATION_DESC allocDesc = {};
3499 allocDesc.HeapType = heapType;
3500 return allocator->CreateResource(&allocDesc,
3503 optimizedClearValue,
3508 *maybeAllocation =
nullptr;
3509 D3D12_HEAP_PROPERTIES heapProps = {};
3510 heapProps.Type = heapType;
3511 return device->CreateCommittedResource(&heapProps,
3512 D3D12_HEAP_FLAG_NONE,
3515 optimizedClearValue,
3521void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
3524 allocator->GetBudget(localBudget, nonLocalBudget);
3527 *nonLocalBudget = {};
3531void QRhiD3D12::waitGpu()
3533 fullFenceCounter += 1u;
3534 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
3535 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
3536 WaitForSingleObject(fullFenceEvent, INFINITE);
3540DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
3542 DXGI_SAMPLE_DESC desc;
3546 const int s = effectiveSampleCount(sampleCount);
3549 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
3550 msaaInfo.Format = format;
3551 msaaInfo.SampleCount = UINT(s);
3552 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
3553 if (msaaInfo.NumQualityLevels > 0) {
3554 desc.Count = UINT(s);
3555 desc.Quality = msaaInfo.NumQualityLevels - 1;
3557 qWarning(
"No quality levels for multisampling with sample count %d", s);
3565bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
3567 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
3569 HRESULT hr = dev->CreateCommandList(0,
3570 D3D12_COMMAND_LIST_TYPE_DIRECT,
3573 __uuidof(D3D12GraphicsCommandList),
3574 reinterpret_cast<
void **>(cmdList));
3576 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3580 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
3582 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3589static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
3592 case DXGI_FORMAT_R8G8B8A8_UNORM:
3593 return QRhiTexture::RGBA8;
3594 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
3596 (*flags) |= QRhiTexture::sRGB;
3597 return QRhiTexture::RGBA8;
3598 case DXGI_FORMAT_B8G8R8A8_UNORM:
3599 return QRhiTexture::BGRA8;
3600 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
3602 (*flags) |= QRhiTexture::sRGB;
3603 return QRhiTexture::BGRA8;
3604 case DXGI_FORMAT_R16G16B16A16_FLOAT:
3605 return QRhiTexture::RGBA16F;
3606 case DXGI_FORMAT_R32G32B32A32_FLOAT:
3607 return QRhiTexture::RGBA32F;
3608 case DXGI_FORMAT_R10G10B10A2_UNORM:
3609 return QRhiTexture::RGB10A2;
3611 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
3614 return QRhiTexture::UnknownFormat;
3617void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
3619 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
3621 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
3622 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
3623 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
3624 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3625 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
3626 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3627 if (u.offset == 0 && u.data.size() == bufD->m_size)
3628 bufD->pendingHostWrites[i].clear();
3629 bufD->pendingHostWrites[i].append({ u.offset, u.data });
3631 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
3632 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3633 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
3634 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3642 QD3D12StagingArea::Allocation stagingAlloc;
3643 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3644 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3645 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3647 std::optional<QD3D12StagingArea> ownStagingArea;
3648 if (!stagingAlloc.isValid()) {
3649 ownStagingArea = QD3D12StagingArea();
3650 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3652 stagingAlloc = ownStagingArea->get(allocSize);
3653 if (!stagingAlloc.isValid()) {
3654 ownStagingArea->destroy();
3659 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3661 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3662 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3664 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3665 cbD->cmdList->CopyBufferRegion(res->resource,
3667 stagingAlloc.buffer,
3668 stagingAlloc.bufferOffset + u.offset,
3672 if (ownStagingArea.has_value())
3673 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3674 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
3675 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3676 if (bufD->m_type == QRhiBuffer::Dynamic) {
3677 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3678 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3679 Q_ASSERT(res->cpuMapPtr);
3680 u.result->data.resize(u.readSize);
3681 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
3683 if (u.result->completed)
3684 u.result->completed();
3686 QD3D12Readback readback;
3687 readback.frameSlot = currentFrameSlot;
3688 readback.result = u.result;
3689 readback.byteSize = u.readSize;
3690 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3691 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3692 if (u.result->completed)
3693 u.result->completed();
3696 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3697 if (!stagingAlloc.isValid()) {
3698 readback.staging.destroy();
3699 if (u.result->completed)
3700 u.result->completed();
3703 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3704 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3705 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3706 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3707 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
3708 activeReadbacks.append(readback);
3710 readback.staging.destroy();
3711 if (u.result->completed)
3712 u.result->completed();
3718 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
3719 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
3720 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
3721 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3722 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3723 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
3726 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3727 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3728 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
3729 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
3730 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
3731 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
3732 footprint.Format = res->desc.Format;
3733 footprint.Depth = 1;
3734 quint32 totalBytes = 0;
3736 const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
3737 : subresDesc.sourceSize();
3738 const QPoint srcPos = subresDesc.sourceTopLeft();
3739 QPoint dstPos = subresDesc.destinationTopLeft();
3741 if (!subresDesc.image().isNull()) {
3742 const QImage img = subresDesc.image();
3743 const int bpl = img.bytesPerLine();
3744 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3745 totalBytes = footprint.RowPitch * img.height();
3746 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3749 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3750 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3751 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3752 totalBytes = footprint.RowPitch * rowCount;
3753 }
else if (!subresDesc.data().isEmpty()) {
3755 if (subresDesc.dataStride())
3756 bpl = subresDesc.dataStride();
3758 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3759 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3760 totalBytes = footprint.RowPitch * subresSize.height();
3762 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
3766 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
3767 QD3D12StagingArea::Allocation stagingAlloc;
3768 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3769 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3771 std::optional<QD3D12StagingArea> ownStagingArea;
3772 if (!stagingAlloc.isValid()) {
3773 ownStagingArea = QD3D12StagingArea();
3774 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3776 stagingAlloc = ownStagingArea->get(allocSize);
3777 if (!stagingAlloc.isValid()) {
3778 ownStagingArea->destroy();
3783 D3D12_TEXTURE_COPY_LOCATION dst;
3784 dst.pResource = res->resource;
3785 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3786 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
3787 D3D12_TEXTURE_COPY_LOCATION src;
3788 src.pResource = stagingAlloc.buffer;
3789 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3790 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3794 if (!subresDesc.image().isNull()) {
3795 const QImage img = subresDesc.image();
3796 const int bpc = qMax(1, img.depth() / 8);
3797 const int bpl = img.bytesPerLine();
3799 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
3800 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
3801 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
3802 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
3804 footprint.Width = size.width();
3805 footprint.Height = size.height();
3809 srcBox.right = UINT(size.width());
3810 srcBox.bottom = UINT(size.height());
3814 const uchar *imgPtr = img.constBits();
3815 const quint32 lineBytes = size.width() * bpc;
3816 for (
int y = 0, h = size.height(); y < h; ++y) {
3817 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3818 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3821 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3824 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3826 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3827 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3832 srcBox.right = aligned(subresSize.width(), blockDim.width());
3833 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3838 footprint.Width = aligned(subresSize.width(), blockDim.width());
3839 footprint.Height = aligned(subresSize.height(), blockDim.height());
3841 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3842 const QByteArray imgData = subresDesc.data();
3843 const char *imgPtr = imgData.constData();
3844 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3845 for (
int y = 0; y < rowCount; ++y)
3846 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3847 }
else if (!subresDesc.data().isEmpty()) {
3850 srcBox.right = subresSize.width();
3851 srcBox.bottom = subresSize.height();
3855 footprint.Width = subresSize.width();
3856 footprint.Height = subresSize.height();
3859 if (subresDesc.dataStride())
3860 bpl = subresDesc.dataStride();
3862 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3864 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3865 const QByteArray data = subresDesc.data();
3866 const char *imgPtr = data.constData();
3867 for (
int y = 0, h = subresSize.height(); y < h; ++y)
3868 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3871 src.PlacedFootprint.Footprint = footprint;
3873 cbD->cmdList->CopyTextureRegion(&dst,
3876 is3D ? UINT(layer) : 0u,
3880 if (ownStagingArea.has_value())
3881 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3885 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
3886 Q_ASSERT(u.src && u.dst);
3887 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
3888 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
3889 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3890 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3891 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
3892 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
3893 if (!srcRes || !dstRes)
3896 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3897 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3898 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3900 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
3901 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
3902 srcD->mipLevelCount);
3903 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
3904 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
3905 dstD->mipLevelCount);
3906 const QPoint dp = u.desc.destinationTopLeft();
3907 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
3908 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
3909 const QPoint sp = u.desc.sourceTopLeft();
3912 srcBox.left = UINT(sp.x());
3913 srcBox.top = UINT(sp.y());
3914 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
3916 srcBox.right = srcBox.left + UINT(copySize.width());
3917 srcBox.bottom = srcBox.top + UINT(copySize.height());
3918 srcBox.back = srcBox.front + 1;
3920 D3D12_TEXTURE_COPY_LOCATION src;
3921 src.pResource = srcRes->resource;
3922 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3923 src.SubresourceIndex = srcSubresource;
3924 D3D12_TEXTURE_COPY_LOCATION dst;
3925 dst.pResource = dstRes->resource;
3926 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3927 dst.SubresourceIndex = dstSubresource;
3929 cbD->cmdList->CopyTextureRegion(&dst,
3932 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
3935 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
3936 QD3D12Readback readback;
3937 readback.frameSlot = currentFrameSlot;
3938 readback.result = u.result;
3940 QD3D12ObjectHandle srcHandle;
3943 if (u.rb.texture()) {
3944 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
3945 if (texD->sampleDesc.Count > 1) {
3946 qWarning(
"Multisample texture cannot be read back");
3949 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3950 if (u.rb.rect().isValid())
3953 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
3954 readback.format = texD->m_format;
3955 srcHandle = texD->handle;
3957 Q_ASSERT(currentSwapChain);
3958 if (u.rb.rect().isValid())
3961 rect = QRect({0, 0}, currentSwapChain->pixelSize);
3962 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
3963 if (readback.format == QRhiTexture::UnknownFormat)
3965 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
3967 readback.pixelSize = rect.size();
3969 textureFormatInfo(readback.format,
3971 &readback.bytesPerLine,
3975 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
3979 const UINT subresource = calcSubresource(UINT(u.rb.level()),
3980 is3D ? 0u : UINT(u.rb.layer()),
3981 srcRes->desc.MipLevels);
3982 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
3985 UINT64 totalBytes = 0;
3986 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
3987 &layout,
nullptr,
nullptr, &totalBytes);
3988 readback.stagingRowPitch = layout.Footprint.RowPitch;
3990 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
3991 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3992 if (u.result->completed)
3993 u.result->completed();
3996 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
3997 if (!stagingAlloc.isValid()) {
3998 readback.staging.destroy();
3999 if (u.result->completed)
4000 u.result->completed();
4003 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4005 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4006 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4008 D3D12_TEXTURE_COPY_LOCATION dst;
4009 dst.pResource = stagingAlloc.buffer;
4010 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4011 dst.PlacedFootprint.Offset = 0;
4012 dst.PlacedFootprint.Footprint = layout.Footprint;
4014 D3D12_TEXTURE_COPY_LOCATION src;
4015 src.pResource = srcRes->resource;
4016 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4017 src.SubresourceIndex = subresource;
4019 D3D12_BOX srcBox = {};
4020 srcBox.left = UINT(rect.left());
4021 srcBox.top = UINT(rect.top());
4022 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4024 srcBox.right = srcBox.left + UINT(rect.width());
4025 srcBox.bottom = srcBox.top + UINT(rect.height());
4026 srcBox.back = srcBox.front + 1;
4028 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4029 activeReadbacks.append(readback);
4030 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4031 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4032 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4033 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4034 mipmapGen3D.generate(cbD, texD->handle);
4036 mipmapGen.generate(cbD, texD->handle);
4043void QRhiD3D12::finishActiveReadbacks(
bool forced)
4045 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4047 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4048 QD3D12Readback &readback(activeReadbacks[i]);
4049 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4050 readback.result->format = readback.format;
4051 readback.result->pixelSize = readback.pixelSize;
4052 readback.result->data.resize(
int(readback.byteSize));
4054 if (readback.format != QRhiTexture::UnknownFormat) {
4055 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4056 const quint8 *srcPtr = readback.staging.mem.p;
4057 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4058 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4059 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4061 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4064 readback.staging.destroy();
4066 if (readback.result->completed)
4067 completedCallbacks.append(readback.result->completed);
4069 activeReadbacks.remove(i);
4073 for (
auto f : completedCallbacks)
4077bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4078 D3D12_DESCRIPTOR_HEAP_TYPE type,
4080 quint32 neededDescriptorCount,
4088 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4089 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4090 neededDescriptorCount);
4091 QD3D12ShaderVisibleDescriptorHeap newHeap;
4092 if (!newHeap.create(dev, type, newPerFrameSize)) {
4093 qWarning(
"Could not create new shader-visible descriptor heap");
4096 h->destroyWithDeferredRelease(&releaseQueue);
4103void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4105 ID3D12DescriptorHeap *heaps[] = {
4106 shaderVisibleCbvSrvUavHeap.heap.heap,
4107 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4109 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4112QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4113 : QRhiBuffer(rhi, type, usage, size)
4117QD3D12Buffer::~QD3D12Buffer()
4122void QD3D12Buffer::destroy()
4124 if (handles[0].isNull())
4127 QRHI_RES_RHI(QRhiD3D12);
4136 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4138 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4140 pendingHostWrites[i].clear();
4144 rhiD->unregisterResource(
this);
4147bool QD3D12Buffer::create()
4149 if (!handles[0].isNull())
4152 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4153 qWarning(
"UniformBuffer must always be Dynamic");
4157 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4158 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4162 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4163 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4165 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4166 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4167 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4169 QRHI_RES_RHI(QRhiD3D12);
4171 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4172 if (i == 0 || m_type == Dynamic) {
4173 D3D12_RESOURCE_DESC resourceDesc = {};
4174 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4175 resourceDesc.Width = roundedSize;
4176 resourceDesc.Height = 1;
4177 resourceDesc.DepthOrArraySize = 1;
4178 resourceDesc.MipLevels = 1;
4179 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4180 resourceDesc.SampleDesc = { 1, 0 };
4181 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4182 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4183 ID3D12Resource *resource =
nullptr;
4184 D3D12MA::Allocation *allocation =
nullptr;
4186 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4187 ? D3D12_HEAP_TYPE_UPLOAD
4188 : D3D12_HEAP_TYPE_DEFAULT;
4189 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4190 ? D3D12_RESOURCE_STATE_GENERIC_READ
4191 : D3D12_RESOURCE_STATE_COMMON;
4192 hr = rhiD->vma.createResource(heapType,
4198 reinterpret_cast<
void **>(&resource));
4201 if (!m_objectName.isEmpty()) {
4202 QString decoratedName = QString::fromUtf8(m_objectName);
4203 if (m_type == Dynamic) {
4204 decoratedName += QLatin1Char(
'/');
4205 decoratedName += QString::number(i);
4207 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4209 void *cpuMemPtr =
nullptr;
4210 if (m_type == Dynamic) {
4212 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4214 qWarning(
"Map() failed to dynamic buffer");
4215 resource->Release();
4217 allocation->Release();
4221 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4229 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4230 qPrintable(QSystemError::windowsComString(hr)),
4233 int(rhiD->vma.isUsingD3D12MA()));
4237 rhiD->registerResource(
this);
4241QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4244 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4245 QRHI_RES_RHI(QRhiD3D12);
4246 if (m_type == Dynamic) {
4247 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4248 executeHostWritesForFrameSlot(i);
4249 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4250 b.objects[i] = res->resource;
4252 b.objects[i] =
nullptr;
4254 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4257 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4258 b.objects[0] = res->resource;
4260 b.objects[0] =
nullptr;
4265char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4273 Q_ASSERT(m_type == Dynamic);
4274 QRHI_RES_RHI(QRhiD3D12);
4275 Q_ASSERT(rhiD->inFrame);
4276 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4277 return static_cast<
char *>(res->cpuMapPtr);
4282void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4287void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4289 if (pendingHostWrites[frameSlot].isEmpty())
4292 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4293 QRHI_RES_RHI(QRhiD3D12);
4294 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4295 Q_ASSERT(res->cpuMapPtr);
4296 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4297 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4299 pendingHostWrites[frameSlot].clear();
4302static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4304 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4306 case QRhiTexture::RGBA8:
4307 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4308 case QRhiTexture::BGRA8:
4309 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4310 case QRhiTexture::R8:
4311 return DXGI_FORMAT_R8_UNORM;
4312 case QRhiTexture::R8SI:
4313 return DXGI_FORMAT_R8_SINT;
4314 case QRhiTexture::R8UI:
4315 return DXGI_FORMAT_R8_UINT;
4316 case QRhiTexture::RG8:
4317 return DXGI_FORMAT_R8G8_UNORM;
4318 case QRhiTexture::R16:
4319 return DXGI_FORMAT_R16_UNORM;
4320 case QRhiTexture::RG16:
4321 return DXGI_FORMAT_R16G16_UNORM;
4322 case QRhiTexture::RED_OR_ALPHA8:
4323 return DXGI_FORMAT_R8_UNORM;
4325 case QRhiTexture::RGBA16F:
4326 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4327 case QRhiTexture::RGBA32F:
4328 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4329 case QRhiTexture::R16F:
4330 return DXGI_FORMAT_R16_FLOAT;
4331 case QRhiTexture::R32F:
4332 return DXGI_FORMAT_R32_FLOAT;
4334 case QRhiTexture::RGB10A2:
4335 return DXGI_FORMAT_R10G10B10A2_UNORM;
4337 case QRhiTexture::R32SI:
4338 return DXGI_FORMAT_R32_SINT;
4339 case QRhiTexture::R32UI:
4340 return DXGI_FORMAT_R32_UINT;
4341 case QRhiTexture::RG32SI:
4342 return DXGI_FORMAT_R32G32_SINT;
4343 case QRhiTexture::RG32UI:
4344 return DXGI_FORMAT_R32G32_UINT;
4345 case QRhiTexture::RGBA32SI:
4346 return DXGI_FORMAT_R32G32B32A32_SINT;
4347 case QRhiTexture::RGBA32UI:
4348 return DXGI_FORMAT_R32G32B32A32_UINT;
4350 case QRhiTexture::D16:
4351 return DXGI_FORMAT_R16_TYPELESS;
4352 case QRhiTexture::D24:
4353 return DXGI_FORMAT_R24G8_TYPELESS;
4354 case QRhiTexture::D24S8:
4355 return DXGI_FORMAT_R24G8_TYPELESS;
4356 case QRhiTexture::D32F:
4357 return DXGI_FORMAT_R32_TYPELESS;
4358 case QRhiTexture::Format::D32FS8:
4359 return DXGI_FORMAT_R32G8X24_TYPELESS;
4361 case QRhiTexture::BC1:
4362 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4363 case QRhiTexture::BC2:
4364 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4365 case QRhiTexture::BC3:
4366 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4367 case QRhiTexture::BC4:
4368 return DXGI_FORMAT_BC4_UNORM;
4369 case QRhiTexture::BC5:
4370 return DXGI_FORMAT_BC5_UNORM;
4371 case QRhiTexture::BC6H:
4372 return DXGI_FORMAT_BC6H_UF16;
4373 case QRhiTexture::BC7:
4374 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4376 case QRhiTexture::ETC2_RGB8:
4377 case QRhiTexture::ETC2_RGB8A1:
4378 case QRhiTexture::ETC2_RGBA8:
4379 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4380 return DXGI_FORMAT_R8G8B8A8_UNORM;
4382 case QRhiTexture::ASTC_4x4:
4383 case QRhiTexture::ASTC_5x4:
4384 case QRhiTexture::ASTC_5x5:
4385 case QRhiTexture::ASTC_6x5:
4386 case QRhiTexture::ASTC_6x6:
4387 case QRhiTexture::ASTC_8x5:
4388 case QRhiTexture::ASTC_8x6:
4389 case QRhiTexture::ASTC_8x8:
4390 case QRhiTexture::ASTC_10x5:
4391 case QRhiTexture::ASTC_10x6:
4392 case QRhiTexture::ASTC_10x8:
4393 case QRhiTexture::ASTC_10x10:
4394 case QRhiTexture::ASTC_12x10:
4395 case QRhiTexture::ASTC_12x12:
4396 qWarning(
"QRhiD3D12 does not support ASTC textures");
4397 return DXGI_FORMAT_R8G8B8A8_UNORM;
4402 return DXGI_FORMAT_R8G8B8A8_UNORM;
4405QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4407 const QSize &pixelSize,
4410 QRhiTexture::Format backingFormatHint)
4411 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4415QD3D12RenderBuffer::~QD3D12RenderBuffer()
4420void QD3D12RenderBuffer::destroy()
4422 if (handle.isNull())
4425 QRHI_RES_RHI(QRhiD3D12);
4428 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4429 else if (dsv.isValid())
4430 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4438 rhiD->unregisterResource(
this);
4441bool QD3D12RenderBuffer::create()
4443 if (!handle.isNull())
4446 if (m_pixelSize.isEmpty())
4449 QRHI_RES_RHI(QRhiD3D12);
4452 case QRhiRenderBuffer::Color:
4454 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4455 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4456 D3D12_RESOURCE_DESC resourceDesc = {};
4457 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4458 resourceDesc.Width = UINT64(m_pixelSize.width());
4459 resourceDesc.Height = UINT(m_pixelSize.height());
4460 resourceDesc.DepthOrArraySize = 1;
4461 resourceDesc.MipLevels = 1;
4462 resourceDesc.Format = dxgiFormat;
4463 resourceDesc.SampleDesc = sampleDesc;
4464 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4465 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4466 D3D12_CLEAR_VALUE clearValue = {};
4467 clearValue.Format = dxgiFormat;
4469 ID3D12Resource *resource =
nullptr;
4470 D3D12MA::Allocation *allocation =
nullptr;
4471 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4473 D3D12_RESOURCE_STATE_RENDER_TARGET,
4476 __uuidof(ID3D12Resource),
4477 reinterpret_cast<
void **>(&resource));
4479 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4482 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4483 rtv = rhiD->rtvPool.allocate(1);
4486 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4487 rtvDesc.Format = dxgiFormat;
4488 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4489 : D3D12_RTV_DIMENSION_TEXTURE2D;
4490 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4493 case QRhiRenderBuffer::DepthStencil:
4495 dxgiFormat = DS_FORMAT;
4496 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4497 D3D12_RESOURCE_DESC resourceDesc = {};
4498 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4499 resourceDesc.Width = UINT64(m_pixelSize.width());
4500 resourceDesc.Height = UINT(m_pixelSize.height());
4501 resourceDesc.DepthOrArraySize = 1;
4502 resourceDesc.MipLevels = 1;
4503 resourceDesc.Format = dxgiFormat;
4504 resourceDesc.SampleDesc = sampleDesc;
4505 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4506 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4507 if (m_flags.testFlag(UsedWithSwapChainOnly))
4508 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4509 D3D12_CLEAR_VALUE clearValue = {};
4510 clearValue.Format = dxgiFormat;
4511 clearValue.DepthStencil.Depth = 1.0f;
4512 clearValue.DepthStencil.Stencil = 0;
4513 ID3D12Resource *resource =
nullptr;
4514 D3D12MA::Allocation *allocation =
nullptr;
4515 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4517 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4520 __uuidof(ID3D12Resource),
4521 reinterpret_cast<
void **>(&resource));
4523 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4526 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4527 dsv = rhiD->dsvPool.allocate(1);
4530 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4531 dsvDesc.Format = dxgiFormat;
4532 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4533 : D3D12_DSV_DIMENSION_TEXTURE2D;
4534 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4539 if (!m_objectName.isEmpty()) {
4540 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4541 const QString name = QString::fromUtf8(m_objectName);
4542 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4547 rhiD->registerResource(
this);
4551QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4553 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4554 return m_backingFormatHint;
4556 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4559QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4560 int arraySize,
int sampleCount, Flags flags)
4561 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4565QD3D12Texture::~QD3D12Texture()
4570void QD3D12Texture::destroy()
4572 if (handle.isNull())
4575 QRHI_RES_RHI(QRhiD3D12);
4577 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4583 rhiD->unregisterResource(
this);
4586static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4589 case QRhiTexture::Format::D16:
4590 return DXGI_FORMAT_R16_FLOAT;
4591 case QRhiTexture::Format::D24:
4592 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4593 case QRhiTexture::Format::D24S8:
4594 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4595 case QRhiTexture::Format::D32F:
4596 return DXGI_FORMAT_R32_FLOAT;
4597 case QRhiTexture::Format::D32FS8:
4598 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4602 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4605static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4609 case QRhiTexture::Format::D16:
4610 return DXGI_FORMAT_D16_UNORM;
4611 case QRhiTexture::Format::D24:
4612 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4613 case QRhiTexture::Format::D24S8:
4614 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4615 case QRhiTexture::Format::D32F:
4616 return DXGI_FORMAT_D32_FLOAT;
4617 case QRhiTexture::Format::D32FS8:
4618 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4622 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4625static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4628 case QRhiTexture::Format::D16:
4629 case QRhiTexture::Format::D24:
4630 case QRhiTexture::Format::D24S8:
4631 case QRhiTexture::Format::D32F:
4632 case QRhiTexture::Format::D32FS8:
4639bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4641 if (!handle.isNull())
4644 QRHI_RES_RHI(QRhiD3D12);
4645 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4648 const bool isDepth = isDepthTextureFormat(m_format);
4649 const bool isCube = m_flags.testFlag(CubeMap);
4650 const bool is3D = m_flags.testFlag(ThreeDimensional);
4651 const bool isArray = m_flags.testFlag(TextureArray);
4652 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4653 const bool is1D = m_flags.testFlag(OneDimensional);
4655 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4656 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4658 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4660 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4661 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4663 srvFormat = dxgiFormat;
4664 rtFormat = dxgiFormat;
4666 if (m_writeViewFormat.format != UnknownFormat) {
4668 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4670 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4672 if (m_readViewFormat.format != UnknownFormat) {
4674 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4676 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4679 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4680 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4681 if (sampleDesc.Count > 1) {
4683 qWarning(
"Cubemap texture cannot be multisample");
4687 qWarning(
"3D texture cannot be multisample");
4691 qWarning(
"Multisample texture cannot have mipmaps");
4695 if (isDepth && hasMipMaps) {
4696 qWarning(
"Depth texture cannot have mipmaps");
4699 if (isCube && is3D) {
4700 qWarning(
"Texture cannot be both cube and 3D");
4703 if (isArray && is3D) {
4704 qWarning(
"Texture cannot be both array and 3D");
4707 if (isCube && is1D) {
4708 qWarning(
"Texture cannot be both cube and 1D");
4712 qWarning(
"Texture cannot be both 1D and 3D");
4715 if (m_depth > 1 && !is3D) {
4716 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4719 if (m_arraySize > 0 && !isArray) {
4720 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4723 if (m_arraySize < 1 && isArray) {
4724 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4729 *adjustedSize = size;
4734bool QD3D12Texture::finishCreate()
4736 QRHI_RES_RHI(QRhiD3D12);
4737 const bool isCube = m_flags.testFlag(CubeMap);
4738 const bool is3D = m_flags.testFlag(ThreeDimensional);
4739 const bool isArray = m_flags.testFlag(TextureArray);
4740 const bool is1D = m_flags.testFlag(OneDimensional);
4742 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4743 srvDesc.Format = srvFormat;
4744 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4747 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4748 srvDesc.TextureCube.MipLevels = mipLevelCount;
4752 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4753 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4754 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4755 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4756 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4758 srvDesc.Texture1DArray.FirstArraySlice = 0;
4759 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4762 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4763 srvDesc.Texture1D.MipLevels = mipLevelCount;
4765 }
else if (isArray) {
4766 if (sampleDesc.Count > 1) {
4767 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4768 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4769 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4770 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4772 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4773 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4776 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4777 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4778 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4779 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4780 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4782 srvDesc.Texture2DArray.FirstArraySlice = 0;
4783 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4787 if (sampleDesc.Count > 1) {
4788 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4790 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4791 srvDesc.Texture3D.MipLevels = mipLevelCount;
4793 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4794 srvDesc.Texture2D.MipLevels = mipLevelCount;
4799 srv = rhiD->cbvSrvUavPool.allocate(1);
4803 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4804 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4805 if (!m_objectName.isEmpty()) {
4806 const QString name = QString::fromUtf8(m_objectName);
4807 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4817bool QD3D12Texture::create()
4820 if (!prepareCreate(&size))
4823 const bool isDepth = isDepthTextureFormat(m_format);
4824 const bool isCube = m_flags.testFlag(CubeMap);
4825 const bool is3D = m_flags.testFlag(ThreeDimensional);
4826 const bool isArray = m_flags.testFlag(TextureArray);
4827 const bool is1D = m_flags.testFlag(OneDimensional);
4829 QRHI_RES_RHI(QRhiD3D12);
4831 bool needsOptimizedClearValueSpecified =
false;
4832 UINT resourceFlags = 0;
4833 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4835 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4837 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4838 needsOptimizedClearValueSpecified =
true;
4840 if (m_flags.testFlag(UsedWithGenerateMips)) {
4842 qWarning(
"Depth texture cannot have mipmaps generated");
4845 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4847 if (m_flags.testFlag(UsedWithLoadStore))
4848 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4850 D3D12_RESOURCE_DESC resourceDesc = {};
4851 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
4852 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
4853 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
4854 resourceDesc.Width = UINT64(size.width());
4855 resourceDesc.Height = UINT(size.height());
4856 resourceDesc.DepthOrArraySize = isCube ? 6
4857 : (isArray ? UINT(qMax(0, m_arraySize))
4858 : (is3D ? qMax(1, m_depth)
4860 resourceDesc.MipLevels = mipLevelCount;
4861 resourceDesc.Format = dxgiFormat;
4862 resourceDesc.SampleDesc = sampleDesc;
4863 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4864 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4865 D3D12_CLEAR_VALUE clearValue = {};
4866 clearValue.Format = dxgiFormat;
4868 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
4869 clearValue.DepthStencil.Depth = 1.0f;
4870 clearValue.DepthStencil.Stencil = 0;
4872 ID3D12Resource *resource =
nullptr;
4873 D3D12MA::Allocation *allocation =
nullptr;
4874 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4876 D3D12_RESOURCE_STATE_COMMON,
4877 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
4879 __uuidof(ID3D12Resource),
4880 reinterpret_cast<
void **>(&resource));
4882 qWarning(
"Failed to create texture: '%s'"
4883 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
4884 qPrintable(QSystemError::windowsComString(hr)),
4885 int(resourceDesc.Dimension),
4886 uint(resourceDesc.Width),
4887 uint(resourceDesc.Height),
4888 uint(resourceDesc.DepthOrArraySize),
4889 uint(resourceDesc.MipLevels),
4890 int(resourceDesc.Format),
4891 int(resourceDesc.SampleDesc.Count));
4895 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
4897 if (!finishCreate())
4900 rhiD->registerResource(
this);
4904bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
4909 if (!prepareCreate())
4912 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
4913 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
4915 QRHI_RES_RHI(QRhiD3D12);
4916 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
4918 if (!finishCreate())
4921 rhiD->registerResource(
this);
4925QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
4927 QRHI_RES_RHI(QRhiD3D12);
4928 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4929 return { quint64(res->resource),
int(res->state) };
4934void QD3D12Texture::setNativeLayout(
int layout)
4936 QRHI_RES_RHI(QRhiD3D12);
4937 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4938 res->state = D3D12_RESOURCE_STATES(layout);
4941QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
4942 AddressMode u, AddressMode v, AddressMode w)
4943 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
4947QD3D12Sampler::~QD3D12Sampler()
4952void QD3D12Sampler::destroy()
4954 shaderVisibleDescriptor = {};
4956 QRHI_RES_RHI(QRhiD3D12);
4958 rhiD->unregisterResource(
this);
4961static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
4963 if (minFilter == QRhiSampler::Nearest) {
4964 if (magFilter == QRhiSampler::Nearest) {
4965 if (mipFilter == QRhiSampler::Linear)
4966 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
4968 return D3D12_FILTER_MIN_MAG_MIP_POINT;
4970 if (mipFilter == QRhiSampler::Linear)
4971 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
4973 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
4976 if (magFilter == QRhiSampler::Nearest) {
4977 if (mipFilter == QRhiSampler::Linear)
4978 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
4980 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
4982 if (mipFilter == QRhiSampler::Linear)
4983 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
4985 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4988 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
4991static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
4994 case QRhiSampler::Repeat:
4995 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
4996 case QRhiSampler::ClampToEdge:
4997 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4998 case QRhiSampler::Mirror:
4999 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
5001 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5004static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5007 case QRhiSampler::Never:
5008 return D3D12_COMPARISON_FUNC_NEVER;
5009 case QRhiSampler::Less:
5010 return D3D12_COMPARISON_FUNC_LESS;
5011 case QRhiSampler::Equal:
5012 return D3D12_COMPARISON_FUNC_EQUAL;
5013 case QRhiSampler::LessOrEqual:
5014 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5015 case QRhiSampler::Greater:
5016 return D3D12_COMPARISON_FUNC_GREATER;
5017 case QRhiSampler::NotEqual:
5018 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5019 case QRhiSampler::GreaterOrEqual:
5020 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5021 case QRhiSampler::Always:
5022 return D3D12_COMPARISON_FUNC_ALWAYS;
5024 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5027bool QD3D12Sampler::create()
5030 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5031 if (m_compareOp != Never)
5032 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5033 desc.AddressU = toD3DAddressMode(m_addressU);
5034 desc.AddressV = toD3DAddressMode(m_addressV);
5035 desc.AddressW = toD3DAddressMode(m_addressW);
5036 desc.MaxAnisotropy = 1.0f;
5037 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5038 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5040 QRHI_RES_RHI(QRhiD3D12);
5041 rhiD->registerResource(
this,
false);
5045QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5047 if (!shaderVisibleDescriptor.isValid()) {
5048 QRHI_RES_RHI(QRhiD3D12);
5049 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5051 return shaderVisibleDescriptor;
5054QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5055 : QRhiShadingRateMap(rhi)
5059QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5064void QD3D12ShadingRateMap::destroy()
5066 if (handle.isNull())
5072bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5074 if (!handle.isNull())
5077 handle = QRHI_RES(QD3D12Texture, src)->handle;
5082QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5083 const QRhiTextureRenderTargetDescription &desc,
5085 : QRhiTextureRenderTarget(rhi, desc, flags),
5090QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5095void QD3D12TextureRenderTarget::destroy()
5097 if (!rtv[0].isValid() && !dsv.isValid())
5100 QRHI_RES_RHI(QRhiD3D12);
5101 if (dsv.isValid()) {
5102 if (ownsDsv && rhiD)
5103 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5107 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5108 if (rtv[i].isValid()) {
5109 if (ownsRtv[i] && rhiD)
5110 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5116 rhiD->unregisterResource(
this);
5119QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5123 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5125 rpD->colorAttachmentCount = 0;
5126 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5127 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5128 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5130 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5132 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5133 rpD->colorAttachmentCount += 1;
5136 rpD->hasDepthStencil =
false;
5137 if (m_desc.depthStencilBuffer()) {
5138 rpD->hasDepthStencil =
true;
5139 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5140 }
else if (m_desc.depthTexture()) {
5141 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5142 rpD->hasDepthStencil =
true;
5143 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5146 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5148 rpD->updateSerializedFormat();
5150 QRHI_RES_RHI(QRhiD3D12);
5151 rhiD->registerResource(rpD);
5155bool QD3D12TextureRenderTarget::create()
5157 if (rtv[0].isValid() || dsv.isValid())
5160 QRHI_RES_RHI(QRhiD3D12);
5161 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5162 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5163 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5164 d.colorAttCount = 0;
5167 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5168 d.colorAttCount += 1;
5169 const QRhiColorAttachment &colorAtt(*it);
5170 QRhiTexture *texture = colorAtt.texture();
5171 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5172 Q_ASSERT(texture || rb);
5174 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5175 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5177 qWarning(
"Could not look up texture handle for render target");
5180 const bool isMultiView = it->multiViewCount() >= 2;
5181 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5182 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5183 rtvDesc.Format = texD->rtFormat;
5184 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5185 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5186 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5187 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5188 rtvDesc.Texture2DArray.ArraySize = layerCount;
5189 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5190 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5191 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5192 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5193 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5194 rtvDesc.Texture1DArray.ArraySize = layerCount;
5196 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5197 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5199 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5200 if (texD->sampleDesc.Count > 1) {
5201 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5202 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5203 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5205 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5206 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5207 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5208 rtvDesc.Texture2DArray.ArraySize = layerCount;
5210 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5211 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5212 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5213 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5214 rtvDesc.Texture3D.WSize = layerCount;
5216 if (texD->sampleDesc.Count > 1) {
5217 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5219 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5220 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5223 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5224 if (!rtv[attIndex].isValid()) {
5225 qWarning(
"Failed to allocate RTV for texture render target");
5228 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5229 ownsRtv[attIndex] =
true;
5230 if (attIndex == 0) {
5231 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5232 d.sampleCount =
int(texD->sampleDesc.Count);
5235 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5236 ownsRtv[attIndex] =
false;
5237 rtv[attIndex] = rbD->rtv;
5238 if (attIndex == 0) {
5239 d.pixelSize = rbD->pixelSize();
5240 d.sampleCount =
int(rbD->sampleDesc.Count);
5247 if (hasDepthStencil) {
5248 if (m_desc.depthTexture()) {
5250 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5251 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5253 qWarning(
"Could not look up depth texture handle");
5256 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5257 dsvDesc.Format = depthTexD->rtFormat;
5258 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5259 : D3D12_DSV_DIMENSION_TEXTURE2D;
5260 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5261 if (depthTexD->sampleDesc.Count > 1) {
5262 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5263 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5264 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5265 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5267 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5268 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5271 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5272 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5273 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5274 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5276 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5277 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5281 dsv = rhiD->dsvPool.allocate(1);
5282 if (!dsv.isValid()) {
5283 qWarning(
"Failed to allocate DSV for texture render target");
5286 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5287 if (d.colorAttCount == 0) {
5288 d.pixelSize = depthTexD->pixelSize();
5289 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5293 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5294 dsv = depthRbD->dsv;
5295 if (d.colorAttCount == 0) {
5296 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5297 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5305 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5306 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5307 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5308 d.dsv = dsv.cpuHandle;
5309 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5311 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5313 rhiD->registerResource(
this);
5317QSize QD3D12TextureRenderTarget::pixelSize()
const
5319 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5320 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5325float QD3D12TextureRenderTarget::devicePixelRatio()
const
5330int QD3D12TextureRenderTarget::sampleCount()
const
5332 return d.sampleCount;
5335QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5336 : QRhiShaderResourceBindings(rhi)
5340QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5345void QD3D12ShaderResourceBindings::destroy()
5347 QRHI_RES_RHI(QRhiD3D12);
5349 rhiD->unregisterResource(
this);
5352bool QD3D12ShaderResourceBindings::create()
5354 QRHI_RES_RHI(QRhiD3D12);
5355 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5358 rhiD->updateLayoutDesc(
this);
5360 hasDynamicOffset =
false;
5361 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5362 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5363 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5364 hasDynamicOffset =
true;
5378 rhiD->registerResource(
this,
false);
5382void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5393void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5394 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5398 D3D12_ROOT_PARAMETER1 rootParam = {};
5399 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5400 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5401 rootParam.Descriptor.ShaderRegister = shaderRegister;
5402 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5403 visitorData.cbParams[s].append(rootParam);
5406void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5407 const QRhiShaderResourceBinding::TextureAndSampler &,
5410 D3D12_DESCRIPTOR_RANGE1 range = {};
5411 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5412 range.NumDescriptors = 1;
5413 range.BaseShaderRegister = shaderRegister;
5414 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5415 visitorData.currentSrvRangeOffset[s] += 1;
5416 visitorData.srvRanges[s].append(range);
5417 if (visitorData.srvRanges[s].count() == 1) {
5418 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5419 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5423void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5424 const QRhiShaderResourceBinding::TextureAndSampler &,
5430 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5431 if (rangeStoreIdx == 16) {
5432 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5435 D3D12_DESCRIPTOR_RANGE1 range = {};
5436 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5437 range.NumDescriptors = 1;
5438 range.BaseShaderRegister = shaderRegister;
5439 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5440 D3D12_ROOT_PARAMETER1 param = {};
5441 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5442 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5443 param.DescriptorTable.NumDescriptorRanges = 1;
5444 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5446 visitorData.samplerTables[s].append(param);
5449void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5450 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5451 QD3D12ShaderResourceVisitor::StorageOp,
5454 D3D12_DESCRIPTOR_RANGE1 range = {};
5455 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5456 range.NumDescriptors = 1;
5457 range.BaseShaderRegister = shaderRegister;
5458 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5459 visitorData.currentUavRangeOffset[s] += 1;
5460 visitorData.uavRanges[s].append(range);
5461 if (visitorData.uavRanges[s].count() == 1) {
5462 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5463 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5467void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5468 const QRhiShaderResourceBinding::Data::StorageImageData &,
5469 QD3D12ShaderResourceVisitor::StorageOp,
5472 D3D12_DESCRIPTOR_RANGE1 range = {};
5473 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5474 range.NumDescriptors = 1;
5475 range.BaseShaderRegister = shaderRegister;
5476 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5477 visitorData.currentUavRangeOffset[s] += 1;
5478 visitorData.uavRanges[s].append(range);
5479 if (visitorData.uavRanges[s].count() == 1) {
5480 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5481 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5485QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5488 QRHI_RES_RHI(QRhiD3D12);
5502 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5506 using namespace std::placeholders;
5507 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5508 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5509 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5510 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5511 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5535 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5536 for (
int s = 0; s < 6; ++s) {
5537 if (!visitorData.cbParams[s].isEmpty())
5538 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5540 for (
int s = 0; s < 6; ++s) {
5541 if (!visitorData.srvRanges[s].isEmpty()) {
5542 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5543 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5544 rootParams.append(visitorData.srvTables[s]);
5547 for (
int s = 0; s < 6; ++s) {
5548 if (!visitorData.samplerTables[s].isEmpty())
5549 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5551 for (
int s = 0; s < 6; ++s) {
5552 if (!visitorData.uavRanges[s].isEmpty()) {
5553 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5554 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5555 rootParams.append(visitorData.uavTables[s]);
5559 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5560 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5561 if (!rootParams.isEmpty()) {
5562 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5563 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5567 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5568 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5569 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5571 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5573 ID3DBlob *signature =
nullptr;
5574 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5576 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5579 ID3D12RootSignature *rootSig =
nullptr;
5580 hr = rhiD->dev->CreateRootSignature(0,
5581 signature->GetBufferPointer(),
5582 signature->GetBufferSize(),
5583 __uuidof(ID3D12RootSignature),
5584 reinterpret_cast<
void **>(&rootSig));
5585 signature->Release();
5587 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5591 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5603static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5605 const int smMajor = version / 10;
5606 const int smMinor = version % 10;
5607 target[0] = stage[0];
5608 target[1] = stage[1];
5610 target[3] =
'0' + smMajor;
5612 target[5] =
'0' + smMinor;
5616enum class HlslCompileFlag
5618 WithDebugInfo = 0x01
5621static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5623 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5625 qWarning(
"Unable to resolve function D3DCompile()");
5626 return QByteArray();
5629 ID3DBlob *bytecode =
nullptr;
5630 ID3DBlob *errors =
nullptr;
5631 UINT d3dCompileFlags = 0;
5632 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5633 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5635 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5636 nullptr,
nullptr,
nullptr,
5637 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5638 if (FAILED(hr) || !bytecode) {
5639 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5641 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5642 int(errors->GetBufferSize()));
5645 return QByteArray();
5649 result.resize(
int(bytecode->GetBufferSize()));
5650 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5651 bytecode->Release();
5655#ifdef QRHI_D3D12_HAS_DXC
5658#define DXC_CP_UTF8 65001
5661#ifndef DXC_ARG_DEBUG
5662#define DXC_ARG_DEBUG L"-Zi"
5665static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5667 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5668 IDxcCompiler *compiler = dxc.first;
5670 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5671 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5672 return QByteArray();
5674 IDxcLibrary *library = dxc.second;
5676 return QByteArray();
5678 IDxcBlobEncoding *sourceBlob =
nullptr;
5679 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5680 UINT32(hlslSource.shader().size()),
5684 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5686 qPrintable(QSystemError::windowsComString(hr)));
5687 return QByteArray();
5690 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5691 const QString targetStr = QString::fromLatin1(target);
5693 QVarLengthArray<LPCWSTR, 4> argPtrs;
5695 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5696 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5697 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5700 IDxcOperationResult *result =
nullptr;
5701 hr = compiler->Compile(sourceBlob,
5703 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5704 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5705 argPtrs.data(), argPtrs.count(),
5709 sourceBlob->Release();
5711 result->GetStatus(&hr);
5713 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5715 qPrintable(QSystemError::windowsComString(hr)));
5717 IDxcBlobEncoding *errorsBlob =
nullptr;
5718 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5720 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5721 int(errorsBlob->GetBufferSize()));
5722 errorsBlob->Release();
5726 return QByteArray();
5729 IDxcBlob *bytecode =
nullptr;
5730 if FAILED(result->GetResult(&bytecode)) {
5731 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5733 qPrintable(QSystemError::windowsComString(hr)));
5734 return QByteArray();
5738 ba.resize(
int(bytecode->GetBufferSize()));
5739 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5740 bytecode->Release();
5746static QByteArray compileHlslShaderSource(
const QShader &shader,
5747 QShader::Variant shaderVariant,
5750 QShaderKey *usedShaderKey)
5753 const int shaderModelMax = 67;
5754 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5755 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5756 QShaderKey key = { type, sm, shaderVariant };
5757 QShaderCode intermediateBytecodeShader = shader.shader(key);
5758 if (!intermediateBytecodeShader.shader().isEmpty()) {
5760 *usedShaderKey = key;
5761 return intermediateBytecodeShader.shader();
5766 QShaderCode hlslSource;
5768 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5769 key = { QShader::HlslShader, sm, shaderVariant };
5770 hlslSource = shader.shader(key);
5771 if (!hlslSource.shader().isEmpty())
5775 if (hlslSource.shader().isEmpty()) {
5776 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5777 return QByteArray();
5781 *usedShaderKey = key;
5784 switch (shader.stage()) {
5785 case QShader::VertexStage:
5786 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5788 case QShader::TessellationControlStage:
5789 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5791 case QShader::TessellationEvaluationStage:
5792 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5794 case QShader::GeometryStage:
5795 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5797 case QShader::FragmentStage:
5798 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5800 case QShader::ComputeStage:
5801 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5805 if (key.sourceVersion().version() >= 60) {
5806#ifdef QRHI_D3D12_HAS_DXC
5807 return dxcCompile(hlslSource, target, flags, error);
5809 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5810 "but the Qt build has no support for DXC. "
5811 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5815 return legacyCompile(hlslSource, target, flags, error);
5818static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5821 if (c.testFlag(QRhiGraphicsPipeline::R))
5822 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5823 if (c.testFlag(QRhiGraphicsPipeline::G))
5824 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5825 if (c.testFlag(QRhiGraphicsPipeline::B))
5826 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5827 if (c.testFlag(QRhiGraphicsPipeline::A))
5828 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5832static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
5841 case QRhiGraphicsPipeline::Zero:
5842 return D3D12_BLEND_ZERO;
5843 case QRhiGraphicsPipeline::One:
5844 return D3D12_BLEND_ONE;
5845 case QRhiGraphicsPipeline::SrcColor:
5846 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
5847 case QRhiGraphicsPipeline::OneMinusSrcColor:
5848 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
5849 case QRhiGraphicsPipeline::DstColor:
5850 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
5851 case QRhiGraphicsPipeline::OneMinusDstColor:
5852 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
5853 case QRhiGraphicsPipeline::SrcAlpha:
5854 return D3D12_BLEND_SRC_ALPHA;
5855 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
5856 return D3D12_BLEND_INV_SRC_ALPHA;
5857 case QRhiGraphicsPipeline::DstAlpha:
5858 return D3D12_BLEND_DEST_ALPHA;
5859 case QRhiGraphicsPipeline::OneMinusDstAlpha:
5860 return D3D12_BLEND_INV_DEST_ALPHA;
5861 case QRhiGraphicsPipeline::ConstantColor:
5862 case QRhiGraphicsPipeline::ConstantAlpha:
5863 return D3D12_BLEND_BLEND_FACTOR;
5864 case QRhiGraphicsPipeline::OneMinusConstantColor:
5865 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
5866 return D3D12_BLEND_INV_BLEND_FACTOR;
5867 case QRhiGraphicsPipeline::SrcAlphaSaturate:
5868 return D3D12_BLEND_SRC_ALPHA_SAT;
5869 case QRhiGraphicsPipeline::Src1Color:
5870 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
5871 case QRhiGraphicsPipeline::OneMinusSrc1Color:
5872 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
5873 case QRhiGraphicsPipeline::Src1Alpha:
5874 return D3D12_BLEND_SRC1_ALPHA;
5875 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
5876 return D3D12_BLEND_INV_SRC1_ALPHA;
5878 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
5881static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
5884 case QRhiGraphicsPipeline::Add:
5885 return D3D12_BLEND_OP_ADD;
5886 case QRhiGraphicsPipeline::Subtract:
5887 return D3D12_BLEND_OP_SUBTRACT;
5888 case QRhiGraphicsPipeline::ReverseSubtract:
5889 return D3D12_BLEND_OP_REV_SUBTRACT;
5890 case QRhiGraphicsPipeline::Min:
5891 return D3D12_BLEND_OP_MIN;
5892 case QRhiGraphicsPipeline::Max:
5893 return D3D12_BLEND_OP_MAX;
5895 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
5898static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
5901 case QRhiGraphicsPipeline::None:
5902 return D3D12_CULL_MODE_NONE;
5903 case QRhiGraphicsPipeline::Front:
5904 return D3D12_CULL_MODE_FRONT;
5905 case QRhiGraphicsPipeline::Back:
5906 return D3D12_CULL_MODE_BACK;
5908 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
5911static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
5914 case QRhiGraphicsPipeline::Fill:
5915 return D3D12_FILL_MODE_SOLID;
5916 case QRhiGraphicsPipeline::Line:
5917 return D3D12_FILL_MODE_WIREFRAME;
5919 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
5922static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
5925 case QRhiGraphicsPipeline::Never:
5926 return D3D12_COMPARISON_FUNC_NEVER;
5927 case QRhiGraphicsPipeline::Less:
5928 return D3D12_COMPARISON_FUNC_LESS;
5929 case QRhiGraphicsPipeline::Equal:
5930 return D3D12_COMPARISON_FUNC_EQUAL;
5931 case QRhiGraphicsPipeline::LessOrEqual:
5932 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5933 case QRhiGraphicsPipeline::Greater:
5934 return D3D12_COMPARISON_FUNC_GREATER;
5935 case QRhiGraphicsPipeline::NotEqual:
5936 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5937 case QRhiGraphicsPipeline::GreaterOrEqual:
5938 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5939 case QRhiGraphicsPipeline::Always:
5940 return D3D12_COMPARISON_FUNC_ALWAYS;
5942 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
5945static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
5948 case QRhiGraphicsPipeline::StencilZero:
5949 return D3D12_STENCIL_OP_ZERO;
5950 case QRhiGraphicsPipeline::Keep:
5951 return D3D12_STENCIL_OP_KEEP;
5952 case QRhiGraphicsPipeline::Replace:
5953 return D3D12_STENCIL_OP_REPLACE;
5954 case QRhiGraphicsPipeline::IncrementAndClamp:
5955 return D3D12_STENCIL_OP_INCR_SAT;
5956 case QRhiGraphicsPipeline::DecrementAndClamp:
5957 return D3D12_STENCIL_OP_DECR_SAT;
5958 case QRhiGraphicsPipeline::Invert:
5959 return D3D12_STENCIL_OP_INVERT;
5960 case QRhiGraphicsPipeline::IncrementAndWrap:
5961 return D3D12_STENCIL_OP_INCR;
5962 case QRhiGraphicsPipeline::DecrementAndWrap:
5963 return D3D12_STENCIL_OP_DECR;
5965 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
5968static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
5971 case QRhiGraphicsPipeline::Triangles:
5972 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
5973 case QRhiGraphicsPipeline::TriangleStrip:
5974 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5975 case QRhiGraphicsPipeline::TriangleFan:
5976 qWarning(
"Triangle fans are not supported with D3D");
5977 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5978 case QRhiGraphicsPipeline::Lines:
5979 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
5980 case QRhiGraphicsPipeline::LineStrip:
5981 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
5982 case QRhiGraphicsPipeline::Points:
5983 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
5984 case QRhiGraphicsPipeline::Patches:
5985 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
5986 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
5988 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
5991static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
5994 case QRhiGraphicsPipeline::Triangles:
5995 case QRhiGraphicsPipeline::TriangleStrip:
5996 case QRhiGraphicsPipeline::TriangleFan:
5997 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
5998 case QRhiGraphicsPipeline::Lines:
5999 case QRhiGraphicsPipeline::LineStrip:
6000 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
6001 case QRhiGraphicsPipeline::Points:
6002 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6003 case QRhiGraphicsPipeline::Patches:
6004 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6006 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6009static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6012 case QRhiVertexInputAttribute::Float4:
6013 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6014 case QRhiVertexInputAttribute::Float3:
6015 return DXGI_FORMAT_R32G32B32_FLOAT;
6016 case QRhiVertexInputAttribute::Float2:
6017 return DXGI_FORMAT_R32G32_FLOAT;
6018 case QRhiVertexInputAttribute::Float:
6019 return DXGI_FORMAT_R32_FLOAT;
6020 case QRhiVertexInputAttribute::UNormByte4:
6021 return DXGI_FORMAT_R8G8B8A8_UNORM;
6022 case QRhiVertexInputAttribute::UNormByte2:
6023 return DXGI_FORMAT_R8G8_UNORM;
6024 case QRhiVertexInputAttribute::UNormByte:
6025 return DXGI_FORMAT_R8_UNORM;
6026 case QRhiVertexInputAttribute::UInt4:
6027 return DXGI_FORMAT_R32G32B32A32_UINT;
6028 case QRhiVertexInputAttribute::UInt3:
6029 return DXGI_FORMAT_R32G32B32_UINT;
6030 case QRhiVertexInputAttribute::UInt2:
6031 return DXGI_FORMAT_R32G32_UINT;
6032 case QRhiVertexInputAttribute::UInt:
6033 return DXGI_FORMAT_R32_UINT;
6034 case QRhiVertexInputAttribute::SInt4:
6035 return DXGI_FORMAT_R32G32B32A32_SINT;
6036 case QRhiVertexInputAttribute::SInt3:
6037 return DXGI_FORMAT_R32G32B32_SINT;
6038 case QRhiVertexInputAttribute::SInt2:
6039 return DXGI_FORMAT_R32G32_SINT;
6040 case QRhiVertexInputAttribute::SInt:
6041 return DXGI_FORMAT_R32_SINT;
6042 case QRhiVertexInputAttribute::Half4:
6044 case QRhiVertexInputAttribute::Half3:
6045 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6046 case QRhiVertexInputAttribute::Half2:
6047 return DXGI_FORMAT_R16G16_FLOAT;
6048 case QRhiVertexInputAttribute::Half:
6049 return DXGI_FORMAT_R16_FLOAT;
6050 case QRhiVertexInputAttribute::UShort4:
6052 case QRhiVertexInputAttribute::UShort3:
6053 return DXGI_FORMAT_R16G16B16A16_UINT;
6054 case QRhiVertexInputAttribute::UShort2:
6055 return DXGI_FORMAT_R16G16_UINT;
6056 case QRhiVertexInputAttribute::UShort:
6057 return DXGI_FORMAT_R16_UINT;
6058 case QRhiVertexInputAttribute::SShort4:
6060 case QRhiVertexInputAttribute::SShort3:
6061 return DXGI_FORMAT_R16G16B16A16_SINT;
6062 case QRhiVertexInputAttribute::SShort2:
6063 return DXGI_FORMAT_R16G16_SINT;
6064 case QRhiVertexInputAttribute::SShort:
6065 return DXGI_FORMAT_R16_SINT;
6067 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6070QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6071 : QRhiGraphicsPipeline(rhi)
6075QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6080void QD3D12GraphicsPipeline::destroy()
6082 if (handle.isNull())
6085 QRHI_RES_RHI(QRhiD3D12);
6087 rhiD->releaseQueue.deferredReleasePipeline(handle);
6088 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6095 rhiD->unregisterResource(
this);
6098bool QD3D12GraphicsPipeline::create()
6100 if (!handle.isNull())
6103 QRHI_RES_RHI(QRhiD3D12);
6104 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6107 rhiD->pipelineCreationStart();
6109 QByteArray shaderBytecode[5];
6110 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6111 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6112 stageData[d3dStage].valid =
true;
6113 stageData[d3dStage].stage = d3dStage;
6114 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6115 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6116 shaderBytecode[d3dStage] = cacheIt->bytecode;
6117 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6120 QShaderKey shaderKey;
6121 int compileFlags = 0;
6122 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6123 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6124 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6125 shaderStage.shaderVariant(),
6129 if (bytecode.isEmpty()) {
6130 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6134 shaderBytecode[d3dStage] = bytecode;
6135 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6136 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6137 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6141 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6143 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6144 if (rootSigHandle.isNull()) {
6145 qWarning(
"Failed to create root signature");
6149 ID3D12RootSignature *rootSig =
nullptr;
6150 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6151 rootSig = rs->rootSig;
6153 qWarning(
"Cannot create graphics pipeline state without root signature");
6157 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6158 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6159 if (rpD->colorAttachmentCount > 0) {
6160 format = DXGI_FORMAT(rpD->colorFormat[0]);
6161 }
else if (rpD->hasDepthStencil) {
6162 format = DXGI_FORMAT(rpD->dsFormat);
6164 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6167 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6170 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6171 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6172 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6173 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6174 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6175 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6176 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6177 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6178 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6179 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6180 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6181 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6182 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6183 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6184 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6185 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6186 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6189 stream.rootSig.object = rootSig;
6191 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6192 QByteArrayList matrixSliceSemantics;
6193 if (!shaderBytecode[VS].isEmpty()) {
6194 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6197 D3D12_INPUT_ELEMENT_DESC desc = {};
6202 const int matrixSlice = it->matrixSlice();
6203 if (matrixSlice < 0) {
6204 desc.SemanticName =
"TEXCOORD";
6205 desc.SemanticIndex = UINT(it->location());
6209 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6210 matrixSliceSemantics.append(sem);
6211 desc.SemanticName = matrixSliceSemantics.last().constData();
6212 desc.SemanticIndex = UINT(matrixSlice);
6214 desc.Format = toD3DAttributeFormat(it->format());
6215 desc.InputSlot = UINT(it->binding());
6216 desc.AlignedByteOffset = it->offset();
6217 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6218 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6219 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6220 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6222 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6224 inputDescs.append(desc);
6228 stream.inputLayout.object.NumElements = inputDescs.count();
6229 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6231 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
6233 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
6234 topology = toD3DTopology(m_topology, m_patchControlPointCount);
6236 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6237 const int d3dStage = qd3d12_stage(shaderStage.type());
6240 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6241 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6244 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6245 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6248 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6249 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6252 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6253 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6256 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6257 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6265 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6266 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6267 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6268 stream.rasterizerState.object.DepthBias = m_depthBias;
6269 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6270 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
6271 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6273 stream.depthStencilState.object.DepthEnable = m_depthTest;
6274 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6275 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6276 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6277 if (m_stencilTest) {
6278 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6279 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6280 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6281 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6282 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6283 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6284 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6285 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6286 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6287 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6290 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6291 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6292 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6293 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6294 blend.BlendEnable = b.enable;
6295 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6296 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6297 blend.BlendOp = toD3DBlendOp(b.opColor);
6298 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6299 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6300 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6301 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6302 stream.blendState.object.RenderTarget[i] = blend;
6304 if (m_targetBlends.isEmpty()) {
6305 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6306 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6307 stream.blendState.object.RenderTarget[0] = blend;
6310 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6311 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6312 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6314 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6316 stream.sampleDesc.object = sampleDesc;
6318 stream.sampleMask.object = 0xFFFFFFFF;
6320 viewInstanceMask = 0;
6321 const bool isMultiView = m_multiViewCount >= 2;
6322 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6323 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6325 for (
int i = 0; i < m_multiViewCount; ++i) {
6326 viewInstanceMask |= (1 << i);
6327 viewInstanceLocations.append({ 0, UINT(i) });
6329 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6332 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6334 ID3D12PipelineState *pso =
nullptr;
6335 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6337 qWarning(
"Failed to create graphics pipeline state: %s",
6338 qPrintable(QSystemError::windowsComString(hr)));
6339 rhiD->rootSignaturePool.remove(rootSigHandle);
6344 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6346 rhiD->pipelineCreationEnd();
6348 rhiD->registerResource(
this);
6352QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6353 : QRhiComputePipeline(rhi)
6357QD3D12ComputePipeline::~QD3D12ComputePipeline()
6362void QD3D12ComputePipeline::destroy()
6364 if (handle.isNull())
6367 QRHI_RES_RHI(QRhiD3D12);
6369 rhiD->releaseQueue.deferredReleasePipeline(handle);
6370 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6377 rhiD->unregisterResource(
this);
6380bool QD3D12ComputePipeline::create()
6382 if (!handle.isNull())
6385 QRHI_RES_RHI(QRhiD3D12);
6386 rhiD->pipelineCreationStart();
6388 stageData.valid =
true;
6389 stageData.stage = CS;
6391 QByteArray shaderBytecode;
6392 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6393 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6394 shaderBytecode = cacheIt->bytecode;
6395 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6398 QShaderKey shaderKey;
6399 int compileFlags = 0;
6400 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6401 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6402 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6403 m_shaderStage.shaderVariant(),
6407 if (bytecode.isEmpty()) {
6408 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6412 shaderBytecode = bytecode;
6413 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6414 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6415 stageData.nativeResourceBindingMap });
6418 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6420 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6421 if (rootSigHandle.isNull()) {
6422 qWarning(
"Failed to create root signature");
6426 ID3D12RootSignature *rootSig =
nullptr;
6427 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6428 rootSig = rs->rootSig;
6430 qWarning(
"Cannot create compute pipeline state without root signature");
6435 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6436 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6438 stream.rootSig.object = rootSig;
6439 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6440 stream.CS.object.BytecodeLength = shaderBytecode.size();
6441 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6442 ID3D12PipelineState *pso =
nullptr;
6443 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6445 qWarning(
"Failed to create compute pipeline state: %s",
6446 qPrintable(QSystemError::windowsComString(hr)));
6447 rhiD->rootSignaturePool.remove(rootSigHandle);
6452 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6454 rhiD->pipelineCreationEnd();
6456 rhiD->registerResource(
this);
6463QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6464 : QRhiRenderPassDescriptor(rhi)
6466 serializedFormatData.reserve(16);
6469QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6474void QD3D12RenderPassDescriptor::destroy()
6476 QRHI_RES_RHI(QRhiD3D12);
6478 rhiD->unregisterResource(
this);
6481bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6486 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6488 if (colorAttachmentCount != o->colorAttachmentCount)
6491 if (hasDepthStencil != o->hasDepthStencil)
6494 for (
int i = 0; i < colorAttachmentCount; ++i) {
6495 if (colorFormat[i] != o->colorFormat[i])
6499 if (hasDepthStencil) {
6500 if (dsFormat != o->dsFormat)
6504 if (hasShadingRateMap != o->hasShadingRateMap)
6510void QD3D12RenderPassDescriptor::updateSerializedFormat()
6512 serializedFormatData.clear();
6513 auto p = std::back_inserter(serializedFormatData);
6515 *p++ = colorAttachmentCount;
6516 *p++ = hasDepthStencil;
6517 for (
int i = 0; i < colorAttachmentCount; ++i)
6518 *p++ = colorFormat[i];
6519 *p++ = hasDepthStencil ? dsFormat : 0;
6522QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6524 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6525 rpD->colorAttachmentCount = colorAttachmentCount;
6526 rpD->hasDepthStencil = hasDepthStencil;
6527 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6528 rpD->dsFormat = dsFormat;
6529 rpD->hasShadingRateMap = hasShadingRateMap;
6531 rpD->updateSerializedFormat();
6533 QRHI_RES_RHI(QRhiD3D12);
6534 rhiD->registerResource(rpD);
6538QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6540 return serializedFormatData;
6543QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6544 : QRhiCommandBuffer(rhi)
6549QD3D12CommandBuffer::~QD3D12CommandBuffer()
6554void QD3D12CommandBuffer::destroy()
6559const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6561 nativeHandlesStruct.commandList = cmdList;
6562 return &nativeHandlesStruct;
6565QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6566 : QRhiSwapChainRenderTarget(rhi, swapchain),
6571QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6576void QD3D12SwapChainRenderTarget::destroy()
6581QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6586float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6591int QD3D12SwapChainRenderTarget::sampleCount()
const
6593 return d.sampleCount;
6596QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6597 : QRhiSwapChain(rhi),
6598 rtWrapper(rhi,
this),
6599 rtWrapperRight(rhi,
this),
6604QD3D12SwapChain::~QD3D12SwapChain()
6609void QD3D12SwapChain::destroy()
6616 swapChain->Release();
6617 swapChain =
nullptr;
6618 sourceSwapChain1->Release();
6619 sourceSwapChain1 =
nullptr;
6621 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6622 FrameResources &fr(frameRes[i]);
6624 fr.fence->Release();
6626 CloseHandle(fr.fenceEvent);
6628 fr.cmdList->Release();
6633 dcompVisual->Release();
6634 dcompVisual =
nullptr;
6638 dcompTarget->Release();
6639 dcompTarget =
nullptr;
6642 if (frameLatencyWaitableObject) {
6643 CloseHandle(frameLatencyWaitableObject);
6644 frameLatencyWaitableObject =
nullptr;
6647 QDxgiVSyncService::instance()->unregisterWindow(window);
6649 QRHI_RES_RHI(QRhiD3D12);
6651 rhiD->swapchains.remove(
this);
6652 rhiD->unregisterResource(
this);
6656void QD3D12SwapChain::releaseBuffers()
6658 QRHI_RES_RHI(QRhiD3D12);
6660 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6661 rhiD->resourcePool.remove(colorBuffers[i]);
6662 rhiD->rtvPool.release(rtvs[i], 1);
6664 rhiD->rtvPool.release(rtvsRight[i], 1);
6665 if (!msaaBuffers[i].isNull())
6666 rhiD->resourcePool.remove(msaaBuffers[i]);
6667 if (msaaRtvs[i].isValid())
6668 rhiD->rtvPool.release(msaaRtvs[i], 1);
6672void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6674 FrameResources &fr(frameRes[frameSlot]);
6675 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6676 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6677 WaitForSingleObject(fr.fenceEvent, INFINITE);
6681void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6683 QRHI_RES_RHI(QRhiD3D12);
6684 FrameResources &fr(frameRes[currentFrameSlot]);
6685 fr.fenceCounter += 1u;
6686 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6689QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6694QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6699QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6701 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6704QSize QD3D12SwapChain::surfacePixelSize()
6707 return m_window->size() * m_window->devicePixelRatio();
6710bool QD3D12SwapChain::isFormatSupported(Format f)
6716 qWarning(
"Attempted to call isFormatSupported() without a window set");
6720 QRHI_RES_RHI(QRhiD3D12);
6721 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6722 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6727QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6729 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6732 QRHI_RES_RHI(QRhiD3D12);
6733 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6738QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6743 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6744 rpD->colorAttachmentCount = 1;
6745 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6746 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6747 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6749 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6751 rpD->updateSerializedFormat();
6753 QRHI_RES_RHI(QRhiD3D12);
6754 rhiD->registerResource(rpD);
6758bool QRhiD3D12::ensureDirectCompositionDevice()
6763 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6764 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6765 return dcompDevice ?
true :
false;
6768static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6769static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6771void QD3D12SwapChain::chooseFormats()
6773 colorFormat = DEFAULT_FORMAT;
6774 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6775 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6776 QRHI_RES_RHI(QRhiD3D12);
6777 if (m_format != SDR) {
6778 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6781 case HDRExtendedSrgbLinear:
6782 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6783 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6784 srgbAdjustedColorFormat = colorFormat;
6787 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6788 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6789 srgbAdjustedColorFormat = colorFormat;
6798 qWarning(
"The output associated with the window is not HDR capable "
6799 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6802 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6805bool QD3D12SwapChain::createOrResize()
6811 const bool needsRegistration = !window || window != m_window;
6814 if (window && window != m_window)
6818 m_currentPixelSize = surfacePixelSize();
6819 pixelSize = m_currentPixelSize;
6821 if (pixelSize.isEmpty())
6824 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6826 QRHI_RES_RHI(QRhiD3D12);
6827 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6829 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6830 if (rhiD->ensureDirectCompositionDevice()) {
6832 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6834 qWarning(
"Failed to create Direct Composition target for the window: %s",
6835 qPrintable(QSystemError::windowsComString(hr)));
6838 if (dcompTarget && !dcompVisual) {
6839 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
6841 qWarning(
"Failed to create DirectComposition visual: %s",
6842 qPrintable(QSystemError::windowsComString(hr)));
6847 if (window->requestedFormat().alphaBufferSize() <= 0)
6848 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
6849 "This may lead to problems.");
6852 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
6854 if (swapInterval == 0 && rhiD->supportsAllowTearing)
6855 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
6859 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
6860 && swapInterval != 0
6861 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
6862 if (useFrameLatencyWaitableObject)
6863 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6868 DXGI_SWAP_CHAIN_DESC1 desc = {};
6869 desc.Width = UINT(pixelSize.width());
6870 desc.Height = UINT(pixelSize.height());
6871 desc.Format = colorFormat;
6872 desc.SampleDesc.Count = 1;
6873 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6874 desc.BufferCount = BUFFER_COUNT;
6875 desc.Flags = swapChainFlags;
6876 desc.Scaling = DXGI_SCALING_NONE;
6877 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6878 desc.Stereo = stereo;
6884 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
6889 desc.Scaling = DXGI_SCALING_STRETCH;
6893 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6895 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6900 if (FAILED(hr) && m_format != SDR) {
6901 colorFormat = DEFAULT_FORMAT;
6902 desc.Format = DEFAULT_FORMAT;
6904 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6906 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6909 if (SUCCEEDED(hr)) {
6910 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
6911 qWarning(
"IDXGISwapChain3 not available");
6914 if (m_format != SDR) {
6915 hr = swapChain->SetColorSpace1(hdrColorSpace);
6917 qWarning(
"Failed to set color space on swapchain: %s",
6918 qPrintable(QSystemError::windowsComString(hr)));
6921 if (useFrameLatencyWaitableObject) {
6922 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
6923 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
6926 hr = dcompVisual->SetContent(swapChain);
6927 if (SUCCEEDED(hr)) {
6928 hr = dcompTarget->SetRoot(dcompVisual);
6930 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
6931 qPrintable(QSystemError::windowsComString(hr)));
6934 qWarning(
"Failed to set content for Direct Composition visual: %s",
6935 qPrintable(QSystemError::windowsComString(hr)));
6939 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
6943 qWarning(
"Failed to create D3D12 swapchain: %s"
6944 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
6945 qPrintable(QSystemError::windowsComString(hr)),
6946 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
6947 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
6951 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6952 hr = rhiD->dev->CreateFence(0,
6953 D3D12_FENCE_FLAG_NONE,
6954 __uuidof(ID3D12Fence),
6955 reinterpret_cast<
void **>(&frameRes[i].fence));
6957 qWarning(
"Failed to create fence for swapchain: %s",
6958 qPrintable(QSystemError::windowsComString(hr)));
6961 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
6963 frameRes[i].fenceCounter = 0;
6967 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
6968 UINT(pixelSize.width()),
6969 UINT(pixelSize.height()),
6972 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
6973 qWarning(
"Device loss detected in ResizeBuffers()");
6974 rhiD->deviceLost =
true;
6976 }
else if (FAILED(hr)) {
6977 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
6982 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6983 ID3D12Resource *colorBuffer;
6984 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
6986 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
6987 i, qPrintable(QSystemError::windowsComString(hr)));
6990 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
6991 rtvs[i] = rhiD->rtvPool.allocate(1);
6992 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6993 rtvDesc.Format = srgbAdjustedColorFormat;
6994 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6995 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
6998 rtvsRight[i] = rhiD->rtvPool.allocate(1);
6999 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7000 rtvDesc.Format = srgbAdjustedColorFormat;
7001 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
7002 rtvDesc.Texture2DArray.ArraySize = 1;
7003 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7004 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7008 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7009 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7010 m_depthStencil->sampleCount(), m_sampleCount);
7012 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7013 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7014 m_depthStencil->setPixelSize(pixelSize);
7015 if (!m_depthStencil->create())
7016 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7017 pixelSize.width(), pixelSize.height());
7019 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7020 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7021 pixelSize.width(), pixelSize.height());
7025 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7027 if (sampleDesc.Count > 1) {
7028 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7029 D3D12_RESOURCE_DESC resourceDesc = {};
7030 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7031 resourceDesc.Width = UINT64(pixelSize.width());
7032 resourceDesc.Height = UINT(pixelSize.height());
7033 resourceDesc.DepthOrArraySize = 1;
7034 resourceDesc.MipLevels = 1;
7035 resourceDesc.Format = srgbAdjustedColorFormat;
7036 resourceDesc.SampleDesc = sampleDesc;
7037 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7038 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7039 D3D12_CLEAR_VALUE clearValue = {};
7040 clearValue.Format = colorFormat;
7041 ID3D12Resource *resource =
nullptr;
7042 D3D12MA::Allocation *allocation =
nullptr;
7043 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7045 D3D12_RESOURCE_STATE_RENDER_TARGET,
7048 __uuidof(ID3D12Resource),
7049 reinterpret_cast<
void **>(&resource));
7051 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7054 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7055 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7056 if (!msaaRtvs[i].isValid())
7058 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7059 rtvDesc.Format = srgbAdjustedColorFormat;
7060 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7061 : D3D12_RTV_DIMENSION_TEXTURE2D;
7062 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7066 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7067 currentFrameSlot = 0;
7068 lastFrameLatencyWaitSlot = -1;
7070 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7071 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7072 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7073 rtD->d.pixelSize = pixelSize;
7074 rtD->d.dpr =
float(window->devicePixelRatio());
7075 rtD->d.sampleCount =
int(sampleDesc.Count);
7076 rtD->d.colorAttCount = 1;
7077 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7079 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7080 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7081 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7082 rtDr->d.pixelSize = pixelSize;
7083 rtDr->d.dpr =
float(window->devicePixelRatio());
7084 rtDr->d.sampleCount =
int(sampleDesc.Count);
7085 rtDr->d.colorAttCount = 1;
7086 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7088 QDxgiVSyncService::instance()->registerWindow(window);
7090 if (needsRegistration || !rhiD->swapchains.contains(
this))
7091 rhiD->swapchains.insert(
this);
7093 rhiD->registerResource(
this);