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 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
533 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
535 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
536 sigDesc.ByteStride =
sizeof(D3D12_DRAW_ARGUMENTS);
537 sigDesc.NumArgumentDescs = 1;
538 sigDesc.pArgumentDescs = &arg;
540 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawCommandSignature));
542 qWarning(
"Failed to create draw command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
548 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
549 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
551 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
552 sigDesc.ByteStride =
sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
553 sigDesc.NumArgumentDescs = 1;
554 sigDesc.pArgumentDescs = &arg;
556 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawIndexedCommandSignature));
558 qWarning(
"Failed to create draw indexed command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
564 offscreenActive =
false;
566 nativeHandlesStruct.dev = dev;
567 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
568 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
569 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
570 nativeHandlesStruct.commandQueue = cmdQueue;
575void QRhiD3D12::destroy()
577 if (!deviceLost && fullFence && fullFenceEvent)
580 releaseQueue.releaseAll();
582 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
583 if (offscreenCb[i]) {
584 if (offscreenCb[i]->cmdList)
585 offscreenCb[i]->cmdList->Release();
586 delete offscreenCb[i];
587 offscreenCb[i] =
nullptr;
591 timestampQueryHeap.destroy();
592 timestampReadbackArea.destroy();
594 shaderVisibleCbvSrvUavHeap.destroy();
596 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
597 smallStagingAreas[i].destroy();
600 mipmapGen3D.destroy();
601 samplerMgr.destroy();
602 resourcePool.destroy();
603 pipelinePool.destroy();
604 rootSignaturePool.destroy();
607 cbvSrvUavPool.destroy();
609 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
610 if (cmdAllocators[i]) {
611 cmdAllocators[i]->Release();
612 cmdAllocators[i] =
nullptr;
616 if (fullFenceEvent) {
617 CloseHandle(fullFenceEvent);
618 fullFenceEvent =
nullptr;
622 fullFence->Release();
626 if (!importedCommandQueue) {
635 if (!importedDevice) {
643 dcompDevice->Release();
644 dcompDevice =
nullptr;
648 activeAdapter->Release();
649 activeAdapter =
nullptr;
653 dxgiFactory->Release();
654 dxgiFactory =
nullptr;
658 importedDevice =
false;
659 importedCommandQueue =
false;
661 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
663 if (drawCommandSignature) {
664 drawCommandSignature->Release();
665 drawCommandSignature =
nullptr;
668 if (drawIndexedCommandSignature) {
669 drawIndexedCommandSignature->Release();
670 drawIndexedCommandSignature =
nullptr;
674QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
676 LUID requestedLuid = {};
678 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
679 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
680 if (adapterLuid.LowPart || adapterLuid.HighPart)
681 requestedLuid = adapterLuid;
684 IDXGIFactory2 *dxgi =
nullptr;
685 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
688 QRhi::AdapterList list;
689 IDXGIAdapter1 *adapter;
690 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
691 DXGI_ADAPTER_DESC1 desc;
692 adapter->GetDesc1(&desc);
694 if (requestedLuid.LowPart || requestedLuid.HighPart) {
695 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
696 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
701 QD3D12Adapter *a =
new QD3D12Adapter;
702 a->luid = desc.AdapterLuid;
703 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
711QRhiDriverInfo QD3D12Adapter::info()
const
716QList<
int> QRhiD3D12::supportedSampleCounts()
const
718 return { 1, 2, 4, 8 };
721QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
724 switch (sampleCount) {
727 if (caps.vrsAdditionalRates) {
728 sizes.append(QSize(4, 4));
729 sizes.append(QSize(4, 2));
730 sizes.append(QSize(2, 4));
732 sizes.append(QSize(2, 2));
733 sizes.append(QSize(2, 1));
734 sizes.append(QSize(1, 2));
737 if (caps.vrsAdditionalRates)
738 sizes.append(QSize(2, 4));
739 sizes.append(QSize(2, 2));
740 sizes.append(QSize(2, 1));
741 sizes.append(QSize(1, 2));
744 sizes.append(QSize(2, 2));
745 sizes.append(QSize(2, 1));
746 sizes.append(QSize(1, 2));
751 sizes.append(QSize(1, 1));
755QRhiSwapChain *QRhiD3D12::createSwapChain()
757 return new QD3D12SwapChain(
this);
760QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
762 return new QD3D12Buffer(
this, type, usage, size);
765int QRhiD3D12::ubufAlignment()
const
767 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
770bool QRhiD3D12::isYUpInFramebuffer()
const
775bool QRhiD3D12::isYUpInNDC()
const
780bool QRhiD3D12::isClipDepthZeroToOne()
const
785QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
790 if (m.isIdentity()) {
792 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
793 0.0f, 1.0f, 0.0f, 0.0f,
794 0.0f, 0.0f, 0.5f, 0.5f,
795 0.0f, 0.0f, 0.0f, 1.0f);
800bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
804 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
810bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
813 case QRhi::MultisampleTexture:
815 case QRhi::MultisampleRenderBuffer:
817 case QRhi::DebugMarkers:
818#ifdef QRHI_D3D12_HAS_OLD_PIX
823 case QRhi::Timestamps:
825 case QRhi::Instancing:
827 case QRhi::CustomInstanceStepRate:
829 case QRhi::PrimitiveRestart:
831 case QRhi::NonDynamicUniformBuffers:
833 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
835 case QRhi::NPOTTextureRepeat:
837 case QRhi::RedOrAlpha8IsRed:
839 case QRhi::ElementIndexUint:
843 case QRhi::WideLines:
845 case QRhi::VertexShaderPointSize:
847 case QRhi::BaseVertex:
849 case QRhi::BaseInstance:
851 case QRhi::TriangleFanTopology:
853 case QRhi::ReadBackNonUniformBuffer:
855 case QRhi::ReadBackNonBaseMipLevel:
857 case QRhi::TexelFetch:
859 case QRhi::RenderToNonBaseMipLevel:
861 case QRhi::IntAttributes:
863 case QRhi::ScreenSpaceDerivatives:
865 case QRhi::ReadBackAnyTextureFormat:
867 case QRhi::PipelineCacheDataLoadSave:
869 case QRhi::ImageDataStride:
871 case QRhi::RenderBufferImport:
873 case QRhi::ThreeDimensionalTextures:
875 case QRhi::RenderTo3DTextureSlice:
877 case QRhi::TextureArrays:
879 case QRhi::Tessellation:
881 case QRhi::GeometryShader:
883 case QRhi::TextureArrayRange:
885 case QRhi::NonFillPolygonMode:
887 case QRhi::OneDimensionalTextures:
889 case QRhi::OneDimensionalTextureMipmaps:
891 case QRhi::HalfAttributes:
893 case QRhi::RenderToOneDimensionalTexture:
895 case QRhi::ThreeDimensionalTextureMipmaps:
897 case QRhi::MultiView:
898 return caps.multiView;
899 case QRhi::TextureViewFormat:
900 return caps.textureViewFormat;
901 case QRhi::ResolveDepthStencil:
905 case QRhi::VariableRateShading:
907 case QRhi::VariableRateShadingMap:
908 case QRhi::VariableRateShadingMapWithTexture:
910 case QRhi::PerRenderTargetBlending:
911 case QRhi::SampleVariables:
913 case QRhi::InstanceIndexIncludesBaseInstance:
915 case QRhi::DepthClamp:
917 case QRhi::DrawIndirect:
918 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
919 case QRhi::DrawIndirectMulti:
920 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
921 case QRhi::ShaderDrawParameters:
927int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
930 case QRhi::TextureSizeMin:
932 case QRhi::TextureSizeMax:
934 case QRhi::MaxColorAttachments:
936 case QRhi::FramesInFlight:
937 return QD3D12_FRAMES_IN_FLIGHT;
938 case QRhi::MaxAsyncReadbackFrames:
939 return QD3D12_FRAMES_IN_FLIGHT;
940 case QRhi::MaxThreadGroupsPerDimension:
942 case QRhi::MaxThreadsPerThreadGroup:
944 case QRhi::MaxThreadGroupX:
946 case QRhi::MaxThreadGroupY:
948 case QRhi::MaxThreadGroupZ:
950 case QRhi::TextureArraySizeMax:
952 case QRhi::MaxUniformBufferRange:
954 case QRhi::MaxVertexInputs:
956 case QRhi::MaxVertexOutputs:
958 case QRhi::ShadingRateImageTileSize:
959 return shadingRateImageTileSize;
964const QRhiNativeHandles *QRhiD3D12::nativeHandles()
966 return &nativeHandlesStruct;
969QRhiDriverInfo QRhiD3D12::driverInfo()
const
971 return driverInfoStruct;
974QRhiStats QRhiD3D12::statistics()
977 result.totalPipelineCreationTime = totalPipelineCreationTime();
979 D3D12MA::Budget budgets[2];
980 vma.getBudget(&budgets[0], &budgets[1]);
981 for (
int i = 0; i < 2; ++i) {
982 const D3D12MA::Statistics &stats(budgets[i].Stats);
983 result.blockCount += stats.BlockCount;
984 result.allocCount += stats.AllocationCount;
985 result.usedBytes += stats.AllocationBytes;
986 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
987 result.totalUsageBytes += budgets[i].UsageBytes;
993bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
999void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1004void QRhiD3D12::releaseCachedResources()
1006 shaderBytecodeCache.data.clear();
1009bool QRhiD3D12::isDeviceLost()
const
1014QByteArray QRhiD3D12::pipelineCacheData()
1019void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1024QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1025 int sampleCount, QRhiRenderBuffer::Flags flags,
1026 QRhiTexture::Format backingFormatHint)
1028 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1031QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1032 const QSize &pixelSize,
int depth,
int arraySize,
1033 int sampleCount, QRhiTexture::Flags flags)
1035 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1038QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1039 QRhiSampler::Filter mipmapMode,
1040 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1042 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1045QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1046 QRhiTextureRenderTarget::Flags flags)
1048 return new QD3D12TextureRenderTarget(
this, desc, flags);
1051QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1053 return new QD3D12ShadingRateMap(
this);
1056QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1058 return new QD3D12GraphicsPipeline(
this);
1061QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1063 return new QD3D12ComputePipeline(
this);
1066QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1068 return new QD3D12ShaderResourceBindings(
this);
1071void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1073 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1074 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1075 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1076 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1078 if (pipelineChanged) {
1079 cbD->currentGraphicsPipeline = psD;
1080 cbD->currentComputePipeline =
nullptr;
1081 cbD->currentPipelineGeneration = psD->generation;
1083 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1084 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1085 cbD->cmdList->SetPipelineState(pipeline->pso);
1086 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1087 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1090 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1092 if (psD->viewInstanceMask)
1093 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1095 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1096 setDefaultScissor(cbD);
1100void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
1101 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1104 int dynamicOffsetCount,
1105 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1107 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1108 quint32 offset = d.offset;
1109 if (d.hasDynamicOffset) {
1110 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1111 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1112 if (dynOfs.first == binding) {
1113 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1114 offset += dynOfs.second;
1118 QRHI_RES_RHI(QRhiD3D12);
1119 visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
1122void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
1123 const QRhiShaderResourceBinding::TextureAndSampler &d,
1126 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1127 visitorData.srvs[s].append(texD->srv);
1130void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
1131 const QRhiShaderResourceBinding::TextureAndSampler &d,
1134 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
1135 visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
1138void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
1139 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1140 QD3D12ShaderResourceVisitor::StorageOp,
1143 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1145 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1146 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1147 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1148 uavDesc.Buffer.FirstElement = d.offset / 4;
1149 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1150 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1151 visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
1154void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
1155 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1156 QD3D12ShaderResourceVisitor::StorageOp,
1159 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1160 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1161 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1162 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1163 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1164 uavDesc.Format = texD->rtFormat;
1166 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1167 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1168 uavDesc.Texture2DArray.FirstArraySlice = 0;
1169 uavDesc.Texture2DArray.ArraySize = 6;
1170 }
else if (isArray) {
1171 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1172 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1173 uavDesc.Texture2DArray.FirstArraySlice = 0;
1174 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1176 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1177 uavDesc.Texture3D.MipSlice = UINT(d.level);
1178 uavDesc.Texture3D.WSize = UINT(-1);
1180 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1181 uavDesc.Texture2D.MipSlice = UINT(d.level);
1183 visitorData.uavs[s].append({ texD->handle, uavDesc });
1186void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1187 int dynamicOffsetCount,
1188 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1190 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1191 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1192 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1193 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1197 srb = gfxPsD->m_shaderResourceBindings;
1199 srb = compPsD->m_shaderResourceBindings;
1202 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1204 bool pipelineChanged =
false;
1206 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD;
1207 srbD->lastUsedGraphicsPipeline = gfxPsD;
1209 pipelineChanged = srbD->lastUsedComputePipeline != compPsD;
1210 srbD->lastUsedComputePipeline = compPsD;
1213 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1214 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1216 case QRhiShaderResourceBinding::UniformBuffer:
1218 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1219 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1220 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1221 sanityCheckResourceOwnership(bufD);
1222 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1225 case QRhiShaderResourceBinding::SampledTexture:
1226 case QRhiShaderResourceBinding::Texture:
1227 case QRhiShaderResourceBinding::Sampler:
1229 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1230 for (
int elem = 0; elem < data->count; ++elem) {
1231 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1232 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1236 Q_ASSERT(texD || samplerD);
1237 sanityCheckResourceOwnership(texD);
1238 sanityCheckResourceOwnership(samplerD);
1241 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1242 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1243 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1244 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1246 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1248 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1249 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1254 case QRhiShaderResourceBinding::ImageLoad:
1255 case QRhiShaderResourceBinding::ImageStore:
1256 case QRhiShaderResourceBinding::ImageLoadStore:
1258 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1259 sanityCheckResourceOwnership(texD);
1260 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1261 if (res->uavUsage) {
1262 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1264 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1266 if (b->type == QRhiShaderResourceBinding::ImageStore
1267 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1270 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1275 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1276 res->uavUsage |= QD3D12Resource::UavUsageRead;
1277 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1278 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1279 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1280 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1284 case QRhiShaderResourceBinding::BufferLoad:
1285 case QRhiShaderResourceBinding::BufferStore:
1286 case QRhiShaderResourceBinding::BufferLoadStore:
1288 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1289 sanityCheckResourceOwnership(bufD);
1290 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1291 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1292 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1293 if (res->uavUsage) {
1294 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1296 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1298 if (b->type == QRhiShaderResourceBinding::BufferStore
1299 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1302 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1307 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1308 res->uavUsage |= QD3D12Resource::UavUsageRead;
1309 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1310 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1311 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1312 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1319 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1320 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1322 if (pipelineChanged || srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1323 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1329 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1331 QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
1334 using namespace std::placeholders;
1335 visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1336 visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
1337 visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
1338 visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
1339 visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
1343 quint32 cbvSrvUavCount = 0;
1344 for (
int s = 0; s < 6; ++s) {
1346 cbvSrvUavCount += visitorData.srvs[s].count();
1347 cbvSrvUavCount += visitorData.uavs[s].count();
1350 bool gotNewHeap =
false;
1351 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1352 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1360 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1361 " per-frame slice size is now %u,"
1362 " if this happens frequently then that's not great.",
1363 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1364 bindShaderVisibleHeaps(cbD);
1367 int rootParamIndex = 0;
1368 for (
int s = 0; s < 6; ++s) {
1369 if (!visitorData.cbufs[s].isEmpty()) {
1370 for (
int i = 0, count = visitorData.cbufs[s].count(); i < count; ++i) {
1371 const auto &cbuf(visitorData.cbufs[s][i]);
1372 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.first)) {
1373 quint32 offset = cbuf.second;
1374 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1375 if (cbD->currentGraphicsPipeline)
1376 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1378 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1380 rootParamIndex += 1;
1384 for (
int s = 0; s < 6; ++s) {
1385 if (!visitorData.srvs[s].isEmpty()) {
1386 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1387 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[s].count());
1388 for (
int i = 0, count = visitorData.srvs[s].count(); i < count; ++i) {
1389 const auto &srv(visitorData.srvs[s][i]);
1390 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc, i).cpuHandle, srv.cpuHandle,
1391 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1394 if (cbD->currentGraphicsPipeline)
1395 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1396 else if (cbD->currentComputePipeline)
1397 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1399 rootParamIndex += 1;
1402 for (
int s = 0; s < 6; ++s) {
1405 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.samplers[s]) {
1406 if (cbD->currentGraphicsPipeline)
1407 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1408 else if (cbD->currentComputePipeline)
1409 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1411 rootParamIndex += 1;
1414 for (
int s = 0; s < 6; ++s) {
1415 if (!visitorData.uavs[s].isEmpty()) {
1416 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1417 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[s].count());
1418 for (
int i = 0, count = visitorData.uavs[s].count(); i < count; ++i) {
1419 const auto &uav(visitorData.uavs[s][i]);
1420 if (QD3D12Resource *res = resourcePool.lookupRef(uav.first)) {
1421 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.second,
1422 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1424 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1425 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1429 if (cbD->currentGraphicsPipeline)
1430 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1431 else if (cbD->currentComputePipeline)
1432 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1434 rootParamIndex += 1;
1439 cbD->currentGraphicsSrb = srb;
1440 cbD->currentComputeSrb =
nullptr;
1442 cbD->currentGraphicsSrb =
nullptr;
1443 cbD->currentComputeSrb = srb;
1445 cbD->currentSrbGeneration = srbD->generation;
1449void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1450 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1451 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1453 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1454 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1456 bool needsBindVBuf =
false;
1457 for (
int i = 0; i < bindingCount; ++i) {
1458 const int inputSlot = startBinding + i;
1459 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1460 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1461 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1463 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1465 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1466 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1468 needsBindVBuf =
true;
1469 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1470 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1474 if (needsBindVBuf) {
1475 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1476 vbv.reserve(bindingCount);
1478 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1479 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1480 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1482 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1483 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1484 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1485 const quint32 offset = bindings[i].second;
1486 const quint32 stride = inputLayout.bindingAt(i)->stride();
1488 if (bufD->m_type != QRhiBuffer::Dynamic) {
1489 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1490 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1493 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1495 res->resource->GetGPUVirtualAddress() + offset,
1496 UINT(res->desc.Width - offset),
1502 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1506 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1507 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1508 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1510 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1512 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1513 : DXGI_FORMAT_R32_UINT;
1514 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1515 || cbD->currentIndexOffset != indexOffset
1516 || cbD->currentIndexFormat != dxgiFormat)
1518 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1519 cbD->currentIndexOffset = indexOffset;
1520 cbD->currentIndexFormat = dxgiFormat;
1522 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1523 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1524 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1527 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1528 const D3D12_INDEX_BUFFER_VIEW ibv = {
1529 res->resource->GetGPUVirtualAddress() + indexOffset,
1530 UINT(res->desc.Width - indexOffset),
1533 cbD->cmdList->IASetIndexBuffer(&ibv);
1539void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1541 cbD->hasCustomScissorSet =
false;
1543 const QSize outputSize = cbD->currentTarget->pixelSize();
1544 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1545 float x = 0, y = 0, w = 0, h = 0;
1547 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1550 w = outputSize.width();
1551 h = outputSize.height();
1554 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1563 cbD->cmdList->RSSetScissorRects(1, &r);
1566void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1568 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1569 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1570 Q_ASSERT(cbD->currentTarget);
1571 const QSize outputSize = cbD->currentTarget->pixelSize();
1575 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1583 v.MinDepth = viewport.minDepth();
1584 v.MaxDepth = viewport.maxDepth();
1585 cbD->cmdList->RSSetViewports(1, &v);
1587 cbD->currentViewport = viewport;
1588 if (cbD->currentGraphicsPipeline
1589 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1591 setDefaultScissor(cbD);
1595void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1597 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1598 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1599 Q_ASSERT(cbD->currentTarget);
1600 const QSize outputSize = cbD->currentTarget->pixelSize();
1604 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1613 cbD->cmdList->RSSetScissorRects(1, &r);
1615 cbD->hasCustomScissorSet =
true;
1618void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1620 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1621 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1622 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1623 cbD->cmdList->OMSetBlendFactor(v);
1626void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1628 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1629 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1630 cbD->cmdList->OMSetStencilRef(refValue);
1633static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1635 if (coarsePixelSize == QSize(1, 2))
1636 return D3D12_SHADING_RATE_1X2;
1637 if (coarsePixelSize == QSize(2, 1))
1638 return D3D12_SHADING_RATE_2X1;
1639 if (coarsePixelSize == QSize(2, 2))
1640 return D3D12_SHADING_RATE_2X2;
1641 if (coarsePixelSize == QSize(2, 4))
1642 return D3D12_SHADING_RATE_2X4;
1643 if (coarsePixelSize == QSize(4, 2))
1644 return D3D12_SHADING_RATE_4X2;
1645 if (coarsePixelSize == QSize(4, 4))
1646 return D3D12_SHADING_RATE_4X4;
1647 return D3D12_SHADING_RATE_1X1;
1650void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
1652 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1653 cbD->hasShadingRateSet =
false;
1655#ifdef QRHI_D3D12_CL5_AVAILABLE
1659 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1660 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
1661 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
1662 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
1663 cbD->hasShadingRateSet =
true;
1666 Q_UNUSED(coarsePixelSize);
1667 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
1671void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1672 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1674 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1675 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1676 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
1679void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1680 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1682 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1683 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1684 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
1685 firstIndex, vertexOffset,
1689void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
1690 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
1692 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1693 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1695 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
1696 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
1697 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
1699 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
1701 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
1702 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1704 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
1707 ID3D12Resource *indirectBufferRes = indirectRes->resource;
1709 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
1711 if (canUseMulti && drawCount > 1) {
1712 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
1713 indirectBufferRes, indirectBufferOffset,
1716 UINT offset = indirectBufferOffset;
1717 for (quint32 i = 0; i < drawCount; ++i) {
1718 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
1719 indirectBufferRes, offset,
1726void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
1727 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
1729 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1730 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1732 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
1733 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
1734 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
1736 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
1738 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
1739 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1741 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
1744 ID3D12Resource *indirectBufferRes = indirectRes->resource;
1746 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
1748 if (canUseMulti && drawCount > 1) {
1749 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
1750 indirectBufferRes, indirectBufferOffset,
1753 UINT offset = indirectBufferOffset;
1754 for (quint32 i = 0; i < drawCount; ++i) {
1755 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
1756 indirectBufferRes, offset,
1763void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
1768 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1769#ifdef QRHI_D3D12_HAS_OLD_PIX
1770 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
1777void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
1782 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1783#ifdef QRHI_D3D12_HAS_OLD_PIX
1784 PIXEndEvent(cbD->cmdList);
1790void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
1795 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1796#ifdef QRHI_D3D12_HAS_OLD_PIX
1797 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
1804const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
1806 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
1809void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
1814void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
1816 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1817 cbD->resetPerPassState();
1818 bindShaderVisibleHeaps(cbD);
1819 if (cbD->currentTarget) {
1820 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
1821 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1824 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1828double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
1830 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1831 return cbD->lastGpuTime;
1834static void calculateGpuTime(QD3D12CommandBuffer *cbD,
1835 int timestampPairStartIndex,
1836 const quint8 *readbackBufPtr,
1837 quint64 timestampTicksPerSecond)
1839 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
1840 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
1841 const quint64 startTime = *p++;
1842 const quint64 endTime = *p;
1843 if (startTime < endTime) {
1844 const quint64 ticks = endTime - startTime;
1845 const double timeSec = ticks /
double(timestampTicksPerSecond);
1846 cbD->lastGpuTime = timeSec;
1850QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
1854 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1855 currentSwapChain = swapChainD;
1856 currentFrameSlot = swapChainD->currentFrameSlot;
1857 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1870 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1871 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1873 if (swapChainD->frameLatencyWaitableObject) {
1875 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
1876 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
1877 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
1881 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1883 qWarning(
"Failed to reset command allocator: %s",
1884 qPrintable(QSystemError::windowsComString(hr)));
1885 return QRhi::FrameOpError;
1888 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1889 return QRhi::FrameOpError;
1891 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1892 cbD->cmdList = fr.cmdList;
1894 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1895 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1896 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1898 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1899 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1901 if (swapChainD->stereo) {
1902 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1903 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1904 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
1906 swapChainD->rtWrapperRight.d.dsv =
1907 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
1914 releaseQueue.executeDeferredReleases(currentFrameSlot);
1920 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1922 smallStagingAreas[currentFrameSlot].head = 0;
1924 bindShaderVisibleHeaps(cbD);
1926 finishActiveReadbacks();
1928 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1931 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1932 calculateGpuTime(cbD,
1933 timestampPairStartIndex,
1934 timestampReadbackArea.mem.p,
1935 timestampTicksPerSecond);
1937 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1938 D3D12_QUERY_TYPE_TIMESTAMP,
1939 timestampPairStartIndex);
1942 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
1944 return QRhi::FrameOpSuccess;
1947QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
1949 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1950 Q_ASSERT(currentSwapChain == swapChainD);
1951 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1953 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1954 if (swapChainD->sampleDesc.Count > 1) {
1955 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1956 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1957 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1958 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1959 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1960 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
1962 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
1965 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1966 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1968 if (timestampQueryHeap.isValid()) {
1969 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1970 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1971 D3D12_QUERY_TYPE_TIMESTAMP,
1972 timestampPairStartIndex + 1);
1973 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1974 D3D12_QUERY_TYPE_TIMESTAMP,
1975 timestampPairStartIndex,
1977 timestampReadbackArea.mem.buffer,
1978 timestampPairStartIndex *
sizeof(quint64));
1981 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1982 HRESULT hr = cmdList->Close();
1984 qWarning(
"Failed to close command list: %s",
1985 qPrintable(QSystemError::windowsComString(hr)));
1986 return QRhi::FrameOpError;
1989 ID3D12CommandList *execList[] = { cmdList };
1990 cmdQueue->ExecuteCommandLists(1, execList);
1992 if (!flags.testFlag(QRhi::SkipPresent)) {
1993 UINT presentFlags = 0;
1994 if (swapChainD->swapInterval == 0
1995 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1997 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1999 if (!swapChainD->swapChain) {
2000 qWarning(
"Failed to present, no swapchain");
2001 return QRhi::FrameOpError;
2003 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2004 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2005 qWarning(
"Device loss detected in Present()");
2007 return QRhi::FrameOpDeviceLost;
2008 }
else if (FAILED(hr)) {
2009 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2010 return QRhi::FrameOpError;
2013 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2014 dcompDevice->Commit();
2017 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2024 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2026 if (!flags.testFlag(QRhi::SkipPresent)) {
2030 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2031 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2034 currentSwapChain =
nullptr;
2035 return QRhi::FrameOpSuccess;
2038QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2051 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2053 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2054 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2056 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2058 qWarning(
"Failed to reset command allocator: %s",
2059 qPrintable(QSystemError::windowsComString(hr)));
2060 return QRhi::FrameOpError;
2063 if (!offscreenCb[currentFrameSlot])
2064 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2065 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2066 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2067 return QRhi::FrameOpError;
2069 releaseQueue.executeDeferredReleases(currentFrameSlot);
2071 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2072 smallStagingAreas[currentFrameSlot].head = 0;
2074 bindShaderVisibleHeaps(cbD);
2076 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2077 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2078 D3D12_QUERY_TYPE_TIMESTAMP,
2079 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2082 offscreenActive =
true;
2085 return QRhi::FrameOpSuccess;
2088QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2091 Q_ASSERT(offscreenActive);
2092 offscreenActive =
false;
2094 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2095 if (timestampQueryHeap.isValid()) {
2096 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2097 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2098 D3D12_QUERY_TYPE_TIMESTAMP,
2099 timestampPairStartIndex + 1);
2100 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2101 D3D12_QUERY_TYPE_TIMESTAMP,
2102 timestampPairStartIndex,
2104 timestampReadbackArea.mem.buffer,
2105 timestampPairStartIndex *
sizeof(quint64));
2108 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2109 HRESULT hr = cmdList->Close();
2111 qWarning(
"Failed to close command list: %s",
2112 qPrintable(QSystemError::windowsComString(hr)));
2113 return QRhi::FrameOpError;
2116 ID3D12CommandList *execList[] = { cmdList };
2117 cmdQueue->ExecuteCommandLists(1, execList);
2119 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2126 finishActiveReadbacks(
true);
2129 if (timestampQueryHeap.isValid()) {
2130 calculateGpuTime(cbD,
2131 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2132 timestampReadbackArea.mem.p,
2133 timestampTicksPerSecond);
2136 return QRhi::FrameOpSuccess;
2139QRhi::FrameOpResult QRhiD3D12::finish()
2141 QD3D12CommandBuffer *cbD =
nullptr;
2143 if (offscreenActive) {
2144 Q_ASSERT(!currentSwapChain);
2145 cbD = offscreenCb[currentFrameSlot];
2147 Q_ASSERT(currentSwapChain);
2148 cbD = ¤tSwapChain->cbWrapper;
2151 return QRhi::FrameOpError;
2153 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2155 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2156 HRESULT hr = cmdList->Close();
2158 qWarning(
"Failed to close command list: %s",
2159 qPrintable(QSystemError::windowsComString(hr)));
2160 return QRhi::FrameOpError;
2163 ID3D12CommandList *execList[] = { cmdList };
2164 cmdQueue->ExecuteCommandLists(1, execList);
2166 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2173 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2175 qWarning(
"Failed to reset command allocator: %s",
2176 qPrintable(QSystemError::windowsComString(hr)));
2177 return QRhi::FrameOpError;
2180 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2181 return QRhi::FrameOpError;
2185 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2186 smallStagingAreas[currentFrameSlot].head = 0;
2188 bindShaderVisibleHeaps(cbD);
2191 releaseQueue.releaseAll();
2192 finishActiveReadbacks(
true);
2194 return QRhi::FrameOpSuccess;
2197void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2199 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2200 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2201 enqueueResourceUpdates(cbD, resourceUpdates);
2204void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2205 QRhiRenderTarget *rt,
2206 const QColor &colorClearValue,
2207 const QRhiDepthStencilClearValue &depthStencilClearValue,
2208 QRhiResourceUpdateBatch *resourceUpdates,
2209 QRhiCommandBuffer::BeginPassFlags)
2211 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2212 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2214 if (resourceUpdates)
2215 enqueueResourceUpdates(cbD, resourceUpdates);
2217 QD3D12RenderTargetData *rtD = rtData(rt);
2218 bool wantsColorClear =
true;
2219 bool wantsDsClear =
true;
2220 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2221 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2222 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2223 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2224 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2227 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2228 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2229 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2230 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2232 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2234 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2236 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2238 if (rtTex->m_desc.depthStencilBuffer()) {
2239 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2240 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2241 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2242 }
else if (rtTex->m_desc.depthTexture()) {
2243 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2244 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2246 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2248 Q_ASSERT(currentSwapChain);
2249 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2250 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
2251 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2252 D3D12_RESOURCE_STATE_RENDER_TARGET);
2253 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2256 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2259 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2261 if (rtD->colorAttCount && wantsColorClear) {
2262 float clearColor[4] = {
2263 colorClearValue.redF(),
2264 colorClearValue.greenF(),
2265 colorClearValue.blueF(),
2266 colorClearValue.alphaF()
2268 for (
int i = 0; i < rtD->colorAttCount; ++i)
2269 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2271 if (rtD->dsAttCount && wantsDsClear) {
2272 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2273 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2274 depthStencilClearValue.depthClearValue(),
2275 UINT8(depthStencilClearValue.stencilClearValue()),
2280 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2281 cbD->currentTarget = rt;
2283 bool hasShadingRateMapSet =
false;
2284#ifdef QRHI_D3D12_CL5_AVAILABLE
2285 if (rtD->rp->hasShadingRateMap) {
2286 cbD->setShadingRate(QSize(1, 1));
2287 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2288 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2289 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2290 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2291 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2292 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2293 cbD->cmdList->RSSetShadingRateImage(res->resource);
2294 hasShadingRateMapSet =
true;
2296 }
else if (cbD->hasShadingRateMapSet) {
2297 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2298 cbD->setShadingRate(QSize(1, 1));
2299 }
else if (cbD->hasShadingRateSet) {
2300 cbD->setShadingRate(QSize(1, 1));
2304 cbD->resetPerPassState();
2307 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2310void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2312 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2313 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2315 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2316 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2317 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2320 const QRhiColorAttachment &colorAtt(*it);
2321 if (!colorAtt.resolveTexture())
2324 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2325 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2329 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2330 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2331 Q_ASSERT(srcTexD || srcRbD);
2332 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2337 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2338 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2339 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2342 if (srcTexD->sampleDesc.Count <= 1) {
2343 qWarning(
"Cannot resolve a non-multisample texture");
2346 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2347 qWarning(
"Resolve source and destination sizes do not match");
2351 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2352 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2353 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2356 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2357 qWarning(
"Resolve source and destination sizes do not match");
2362 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2363 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2364 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2366 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2367 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2368 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2369 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2370 UINT(colorAtt.resolveLayer()) + resolveIdx,
2371 dstTexD->mipLevelCount);
2372 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
2373 srcRes->resource, srcSubresource,
2374 dstTexD->dxgiFormat);
2377 if (rtTex->m_desc.depthResolveTexture())
2378 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2381 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2382 cbD->currentTarget =
nullptr;
2384 if (resourceUpdates)
2385 enqueueResourceUpdates(cbD, resourceUpdates);
2388void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2389 QRhiResourceUpdateBatch *resourceUpdates,
2390 QRhiCommandBuffer::BeginPassFlags)
2392 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2393 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2395 if (resourceUpdates)
2396 enqueueResourceUpdates(cbD, resourceUpdates);
2398 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2400 cbD->resetPerPassState();
2403void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2405 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2406 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2408 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2410 if (resourceUpdates)
2411 enqueueResourceUpdates(cbD, resourceUpdates);
2414void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2416 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2417 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2418 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2419 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2421 if (pipelineChanged) {
2422 cbD->currentGraphicsPipeline =
nullptr;
2423 cbD->currentComputePipeline = psD;
2424 cbD->currentPipelineGeneration = psD->generation;
2426 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2427 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2428 cbD->cmdList->SetPipelineState(pipeline->pso);
2429 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2430 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2435void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2437 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2438 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2439 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2442bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2443 quint32 descriptorCount,
2444 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2445 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2448 capacity = descriptorCount;
2449 this->heapType = heapType;
2450 this->heapFlags = heapFlags;
2452 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2453 heapDesc.Type = heapType;
2454 heapDesc.NumDescriptors = capacity;
2455 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2457 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2459 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2461 capacity = descriptorByteSize = 0;
2465 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2466 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2467 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2468 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2473void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2474 quint32 offsetInDescriptors,
2475 quint32 descriptorCount)
2479 capacity = descriptorCount;
2480 heapType = other.heapType;
2481 heapFlags = other.heapFlags;
2482 descriptorByteSize = other.descriptorByteSize;
2483 heapStart = incremented(other.heapStart, offsetInDescriptors);
2486void QD3D12DescriptorHeap::destroy()
2495void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2498 releaseQueue->deferredReleaseDescriptorHeap(heap);
2504QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2506 Q_ASSERT(count > 0);
2507 if (head + count > capacity) {
2508 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2512 return at(head - count);
2515QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2517 const quint32 startOffset = index * descriptorByteSize;
2518 QD3D12Descriptor result;
2519 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2520 if (heapStart.gpuHandle.ptr != 0)
2521 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2525bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2527 QD3D12DescriptorHeap firstHeap;
2528 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2530 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2531 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2532 this->device = device;
2533 this->debugName = debugName;
2537void QD3D12CpuDescriptorPool::destroy()
2541 static bool leakCheck =
true;
2544 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2547 for (
const HeapWithMap &heap : std::as_const(heaps)) {
2548 const int leakedDescriptorCount = heap.map.count(
true);
2549 if (leakedDescriptorCount > 0) {
2550 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2551 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2552 &heap.heap,
this, debugName, leakedDescriptorCount);
2556 for (HeapWithMap &heap : heaps)
2557 heap.heap.destroy();
2561QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2563 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2565 HeapWithMap &last(heaps.last());
2566 if (last.heap.head + count <= last.heap.capacity) {
2567 quint32 firstIndex = last.heap.head;
2568 for (quint32 i = 0; i < count; ++i)
2569 last.map.setBit(firstIndex + i);
2570 return last.heap.get(count);
2573 for (HeapWithMap &heap : heaps) {
2574 quint32 freeCount = 0;
2575 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2576 if (heap.map.testBit(i)) {
2580 if (freeCount == count) {
2581 quint32 firstIndex = i - (freeCount - 1);
2582 for (quint32 j = 0; j < count; ++j) {
2583 heap.map.setBit(firstIndex + j);
2584 return heap.heap.at(firstIndex);
2591 QD3D12DescriptorHeap newHeap;
2592 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2595 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2597 for (quint32 i = 0; i < count; ++i)
2598 heaps.last().map.setBit(i);
2600 return heaps.last().heap.get(count);
2603void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
2605 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2606 if (!descriptor.isValid())
2609 const SIZE_T addr = descriptor.cpuHandle.ptr;
2610 for (HeapWithMap &heap : heaps) {
2611 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
2612 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2613 if (addr >= begin && addr < end) {
2614 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
2615 for (quint32 i = 0; i < count; ++i)
2616 heap.map.setBit(firstIndex + i,
false);
2621 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2622 quint64(descriptor.cpuHandle.ptr));
2625bool QD3D12QueryHeap::create(ID3D12Device *device,
2627 D3D12_QUERY_HEAP_TYPE heapType)
2629 capacity = queryCount;
2631 D3D12_QUERY_HEAP_DESC heapDesc = {};
2632 heapDesc.Type = heapType;
2633 heapDesc.Count = capacity;
2635 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
2637 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2646void QD3D12QueryHeap::destroy()
2655bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
2657 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2658 D3D12_RESOURCE_DESC resourceDesc = {};
2659 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2660 resourceDesc.Width = capacity;
2661 resourceDesc.Height = 1;
2662 resourceDesc.DepthOrArraySize = 1;
2663 resourceDesc.MipLevels = 1;
2664 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2665 resourceDesc.SampleDesc = { 1, 0 };
2666 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2667 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2668 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2669 HRESULT hr = rhi->vma.createResource(heapType,
2671 D3D12_RESOURCE_STATES(state),
2674 __uuidof(ID3D12Resource),
2675 reinterpret_cast<
void **>(&resource));
2677 qWarning(
"Failed to create buffer for staging area: %s",
2678 qPrintable(QSystemError::windowsComString(hr)));
2682 hr = resource->Map(0,
nullptr, &p);
2684 qWarning(
"Failed to map buffer for staging area: %s",
2685 qPrintable(QSystemError::windowsComString(hr)));
2690 mem.p =
static_cast<quint8 *>(p);
2691 mem.gpuAddr = resource->GetGPUVirtualAddress();
2692 mem.buffer = resource;
2693 mem.bufferOffset = 0;
2695 this->capacity = capacity;
2701void QD3D12StagingArea::destroy()
2704 resource->Release();
2708 allocation->Release();
2709 allocation =
nullptr;
2714void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2717 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
2721QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
2723 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
2724 if (head + allocSize > capacity) {
2725 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2726 allocSize, byteSize, capacity, remainingCapacity());
2729 const quint32 offset = head;
2733 mem.gpuAddr + offset,
2742void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
2744 DeferredReleaseEntry e;
2749void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
2750 QD3D12CpuDescriptorPool *pool,
2751 const QD3D12Descriptor &viewsStart,
2754 DeferredReleaseEntry e;
2755 e.type = DeferredReleaseEntry::Resource;
2757 e.poolForViews = pool;
2758 e.viewsStart = viewsStart;
2759 e.viewCount = viewCount;
2763void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
2765 DeferredReleaseEntry e;
2766 e.type = DeferredReleaseEntry::Pipeline;
2771void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
2773 DeferredReleaseEntry e;
2774 e.type = DeferredReleaseEntry::RootSignature;
2779void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2781 DeferredReleaseEntry e;
2782 e.type = DeferredReleaseEntry::Callback;
2783 e.callback = callback;
2784 e.callbackUserData = userData;
2788void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2789 D3D12MA::Allocation *allocation)
2791 DeferredReleaseEntry e;
2792 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2793 e.resourceAndAllocation = { resource, allocation };
2797void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2799 DeferredReleaseEntry e;
2800 e.type = DeferredReleaseEntry::DescriptorHeap;
2801 e.descriptorHeap = heap;
2805void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
2806 const QD3D12Descriptor &viewsStart,
2809 DeferredReleaseEntry e;
2810 e.type = DeferredReleaseEntry::Views;
2811 e.poolForViews = pool;
2812 e.viewsStart = viewsStart;
2813 e.viewCount = viewCount;
2817void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2819 for (DeferredReleaseEntry &e : queue) {
2820 if (!e.frameSlotToBeReleasedIn.has_value())
2821 e.frameSlotToBeReleasedIn = frameSlot;
2825void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2827 for (
int i = queue.count() - 1; i >= 0; --i) {
2828 const DeferredReleaseEntry &e(queue[i]);
2829 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2831 case DeferredReleaseEntry::Resource:
2832 resourcePool->remove(e.handle);
2833 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
2834 e.poolForViews->release(e.viewsStart, e.viewCount);
2836 case DeferredReleaseEntry::Pipeline:
2837 pipelinePool->remove(e.handle);
2839 case DeferredReleaseEntry::RootSignature:
2840 rootSignaturePool->remove(e.handle);
2842 case DeferredReleaseEntry::Callback:
2843 e.callback(e.callbackUserData);
2845 case DeferredReleaseEntry::ResourceAndAllocation:
2848 e.resourceAndAllocation.first->Release();
2849 if (e.resourceAndAllocation.second)
2850 e.resourceAndAllocation.second->Release();
2852 case DeferredReleaseEntry::DescriptorHeap:
2853 e.descriptorHeap->Release();
2855 case DeferredReleaseEntry::Views:
2856 e.poolForViews->release(e.viewsStart, e.viewCount);
2864void QD3D12ReleaseQueue::releaseAll()
2866 executeDeferredReleases(0,
true);
2869void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2870 D3D12_RESOURCE_STATES stateAfter)
2872 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2873 if (stateAfter != res->state) {
2874 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
2875 res->state = stateAfter;
2880void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2882 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
2883 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2884 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
2885 D3D12_RESOURCE_BARRIER barrier = {};
2886 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2887 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2888 barrier.Transition.pResource = res->resource;
2889 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2890 barrier.Transition.StateBefore = trb.stateBefore;
2891 barrier.Transition.StateAfter = trb.stateAfter;
2892 barriers.append(barrier);
2895 transitionResourceBarriers.clear();
2896 if (!barriers.isEmpty())
2897 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
2900void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2901 const QD3D12ObjectHandle &resourceHandle,
2903 D3D12_RESOURCE_STATES stateBefore,
2904 D3D12_RESOURCE_STATES stateAfter)
2906 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2907 D3D12_RESOURCE_BARRIER barrier = {};
2908 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2909 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2910 barrier.Transition.pResource = res->resource;
2911 barrier.Transition.Subresource = subresource;
2912 barrier.Transition.StateBefore = stateBefore;
2913 barrier.Transition.StateAfter = stateAfter;
2914 cbD->cmdList->ResourceBarrier(1, &barrier);
2918void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2919 const QD3D12ObjectHandle &resourceHandle)
2921 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2922 D3D12_RESOURCE_BARRIER barrier = {};
2923 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2924 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2925 barrier.UAV.pResource = res->resource;
2926 cbD->cmdList->ResourceBarrier(1, &barrier);
2930void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
2932 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2934 data.insert(key, s);
2937bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
2938 D3D12_DESCRIPTOR_HEAP_TYPE type,
2939 quint32 perFrameDescriptorCount)
2941 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2943 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2946 const quint32 CBV_SRV_UAV_MAX = 1000000;
2947 const quint32 SAMPLER_MAX = 2048;
2948 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2949 size = qMin(size, CBV_SRV_UAV_MAX);
2950 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2951 size = qMin(size, SAMPLER_MAX);
2953 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2954 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
2958 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
2959 quint32 currentOffsetInDescriptors = 0;
2960 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
2961 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2962 currentOffsetInDescriptors += perFrameDescriptorCount;
2968void QD3D12ShaderVisibleDescriptorHeap::destroy()
2973void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2975 heap.destroyWithDeferredRelease(releaseQueue);
2978static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
2981 return { binding, binding };
2983 auto it = map.constFind(binding);
2984 if (it != map.cend())
2993void QD3D12ShaderResourceVisitor::visit()
2995 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2996 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
2997 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
2999 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
3000 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3004 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3008 case QRhiShaderResourceBinding::UniformBuffer:
3010 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3011 if (shaderRegister >= 0 && uniformBuffer)
3012 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3015 case QRhiShaderResourceBinding::SampledTexture:
3017 Q_ASSERT(bd->u.stex.count > 0);
3018 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3019 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
3020 for (
int i = 0; i < bd->u.stex.count; ++i) {
3021 if (textureBaseShaderRegister >= 0 && texture)
3022 texture(sd->stage, bd->u.stex.texSamplers[i], textureBaseShaderRegister + i);
3023 if (samplerBaseShaderRegister >= 0 && sampler)
3024 sampler(sd->stage, bd->u.stex.texSamplers[i], samplerBaseShaderRegister + i);
3028 case QRhiShaderResourceBinding::Texture:
3030 Q_ASSERT(bd->u.stex.count > 0);
3031 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3032 if (baseShaderRegister >= 0 && texture) {
3033 for (
int i = 0; i < bd->u.stex.count; ++i)
3034 texture(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
3038 case QRhiShaderResourceBinding::Sampler:
3040 Q_ASSERT(bd->u.stex.count > 0);
3041 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3042 if (baseShaderRegister >= 0 && sampler) {
3043 for (
int i = 0; i < bd->u.stex.count; ++i)
3044 sampler(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
3048 case QRhiShaderResourceBinding::ImageLoad:
3050 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3051 if (shaderRegister >= 0 && storageImage)
3052 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3055 case QRhiShaderResourceBinding::ImageStore:
3057 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3058 if (shaderRegister >= 0 && storageImage)
3059 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3062 case QRhiShaderResourceBinding::ImageLoadStore:
3064 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3065 if (shaderRegister >= 0 && storageImage)
3066 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3069 case QRhiShaderResourceBinding::BufferLoad:
3071 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3072 if (shaderRegister >= 0 && storageBuffer)
3073 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3076 case QRhiShaderResourceBinding::BufferStore:
3078 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3079 if (shaderRegister >= 0 && storageBuffer)
3080 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3083 case QRhiShaderResourceBinding::BufferLoadStore:
3085 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3086 if (shaderRegister >= 0 && storageBuffer)
3087 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3095bool QD3D12SamplerManager::create(ID3D12Device *device)
3098 if (!shaderVisibleSamplerHeap.create(device,
3099 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3100 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3102 qWarning(
"Could not create shader-visible SAMPLER heap");
3106 this->device = device;
3110void QD3D12SamplerManager::destroy()
3113 shaderVisibleSamplerHeap.destroy();
3118QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3120 auto it = gpuMap.constFind({desc});
3121 if (it != gpuMap.cend())
3124 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3125 if (descriptor.isValid()) {
3126 device->CreateSampler(&desc, descriptor.cpuHandle);
3127 gpuMap.insert({desc}, descriptor);
3129 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3130 " this should not happen, maximum number of unique samplers is %u",
3131 shaderVisibleSamplerHeap.heap.capacity);
3137bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3141 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3142 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3145 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3146 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3147 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3150 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3151 descriptorRanges[0].NumDescriptors = 1;
3152 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3153 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3154 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3155 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3156 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3159 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3160 descriptorRanges[1].NumDescriptors = 4;
3161 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3162 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3163 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3164 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3167 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3168 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3169 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3170 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3171 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3172 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3174 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3175 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3176 rsDesc.Desc_1_1.NumParameters = 3;
3177 rsDesc.Desc_1_1.pParameters = rootParams;
3178 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3179 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3181 ID3DBlob *signature =
nullptr;
3182 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3184 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3187 ID3D12RootSignature *rootSig =
nullptr;
3188 hr = rhiD->dev->CreateRootSignature(0,
3189 signature->GetBufferPointer(),
3190 signature->GetBufferSize(),
3191 __uuidof(ID3D12RootSignature),
3192 reinterpret_cast<
void **>(&rootSig));
3193 signature->Release();
3195 qWarning(
"Failed to create root signature: %s",
3196 qPrintable(QSystemError::windowsComString(hr)));
3200 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3202 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3203 psoDesc.pRootSignature = rootSig;
3204 psoDesc.CS.pShaderBytecode = g_csMipmap;
3205 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3206 ID3D12PipelineState *pso =
nullptr;
3207 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3208 __uuidof(ID3D12PipelineState),
3209 reinterpret_cast<
void **>(&pso));
3211 qWarning(
"Failed to create compute pipeline state: %s",
3212 qPrintable(QSystemError::windowsComString(hr)));
3213 rhiD->rootSignaturePool.remove(rootSigHandle);
3218 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3223void QD3D12MipmapGenerator::destroy()
3225 rhiD->pipelinePool.remove(pipelineHandle);
3226 pipelineHandle = {};
3227 rhiD->rootSignaturePool.remove(rootSigHandle);
3231void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3233 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3236 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3239 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3243 const quint32 mipLevelCount = res->desc.MipLevels;
3244 if (mipLevelCount < 2)
3247 if (res->desc.SampleDesc.Count > 1) {
3248 qWarning(
"Cannot generate mipmaps for MSAA texture");
3252 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3254 qWarning(
"Cannot generate mipmaps for 1D texture");
3258 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3259 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3260 && res->desc.DepthOrArraySize > 1;
3261 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3264 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3268 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3269 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3271 cbD->cmdList->SetPipelineState(pipeline->pso);
3272 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3274 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3277 quint32 srcMipLevel;
3278 quint32 numMipLevels;
3283 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3284 std::optional<QD3D12StagingArea> ownStagingArea;
3285 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3286 ownStagingArea = QD3D12StagingArea();
3287 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3288 qWarning(
"Could not create staging area for mipmap generation");
3292 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3293 ? &ownStagingArea.value()
3294 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3296 bool gotNewHeap =
false;
3297 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3298 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3299 rhiD->currentFrameSlot,
3300 (1 + 4) * mipLevelCount * layerCount,
3303 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3307 rhiD->bindShaderVisibleHeaps(cbD);
3309 for (quint32 layer = 0; layer < layerCount; ++layer) {
3310 for (quint32 level = 0; level < mipLevelCount ;) {
3311 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3312 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3313 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3314 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3316 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3317 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3318 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3319 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3321 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3322 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3323 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3324 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3326 CBufData cbufData = {
3329 1.0f /
float(levelPlusOneMipWidth),
3330 1.0f /
float(levelPlusOneMipHeight)
3333 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3334 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3335 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3337 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3338 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3339 srvDesc.Format = res->desc.Format;
3340 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3341 if (isCubeOrArray) {
3342 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3343 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3344 srvDesc.Texture2DArray.FirstArraySlice = layer;
3345 srvDesc.Texture2DArray.ArraySize = 1;
3347 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3348 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3350 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3351 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3353 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3354 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3356 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3357 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3358 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3359 uavDesc.Format = res->desc.Format;
3360 if (isCubeOrArray) {
3361 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3362 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3363 uavDesc.Texture2DArray.FirstArraySlice = layer;
3364 uavDesc.Texture2DArray.ArraySize = 1;
3366 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3367 uavDesc.Texture2D.MipSlice = uavMipLevel;
3369 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3370 uavCpuHandle.ptr += descriptorByteSize;
3372 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3374 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3376 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3377 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3378 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3379 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3381 level += numGenMips;
3385 if (ownStagingArea.has_value())
3386 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3389bool QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
3393 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3394 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3397 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3398 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3399 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3402 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3403 descriptorRanges[0].NumDescriptors = 1;
3404 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3405 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3406 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3407 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3408 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3411 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3412 descriptorRanges[1].NumDescriptors = 1;
3413 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3414 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3415 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3416 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3419 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3420 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3421 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3422 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3423 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3424 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3426 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3427 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3428 rsDesc.Desc_1_1.NumParameters = 3;
3429 rsDesc.Desc_1_1.pParameters = rootParams;
3430 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3431 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3433 ID3DBlob *signature =
nullptr;
3434 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3436 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3439 ID3D12RootSignature *rootSig =
nullptr;
3440 hr = rhiD->dev->CreateRootSignature(0,
3441 signature->GetBufferPointer(),
3442 signature->GetBufferSize(),
3443 __uuidof(ID3D12RootSignature),
3444 reinterpret_cast<
void **>(&rootSig));
3445 signature->Release();
3447 qWarning(
"Failed to create root signature: %s",
3448 qPrintable(QSystemError::windowsComString(hr)));
3452 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3454 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3455 psoDesc.pRootSignature = rootSig;
3456 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
3457 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
3458 ID3D12PipelineState *pso =
nullptr;
3459 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3460 __uuidof(ID3D12PipelineState),
3461 reinterpret_cast<
void **>(&pso));
3463 qWarning(
"Failed to create compute pipeline state: %s",
3464 qPrintable(QSystemError::windowsComString(hr)));
3465 rhiD->rootSignaturePool.remove(rootSigHandle);
3470 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3475void QD3D12MipmapGenerator3D::destroy()
3477 rhiD->pipelinePool.remove(pipelineHandle);
3478 pipelineHandle = {};
3479 rhiD->rootSignaturePool.remove(rootSigHandle);
3483void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3485 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3488 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3491 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3495 const quint32 mipLevelCount = res->desc.MipLevels;
3496 if (mipLevelCount < 2)
3499 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3501 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
3505 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3506 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3508 cbD->cmdList->SetPipelineState(pipeline->pso);
3509 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3511 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3517 quint32 srcMipLevel;
3520 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
3521 std::optional<QD3D12StagingArea> ownStagingArea;
3522 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3523 ownStagingArea = QD3D12StagingArea();
3524 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3525 qWarning(
"Could not create staging area for mipmap generation");
3529 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3530 ? &ownStagingArea.value()
3531 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3533 bool gotNewHeap =
false;
3534 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3535 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3536 rhiD->currentFrameSlot,
3537 (1 + 1) * mipLevelCount,
3540 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3544 rhiD->bindShaderVisibleHeaps(cbD);
3546 for (quint32 level = 0; level < mipLevelCount; ++level) {
3547 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
3548 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3549 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3550 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3552 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
3553 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
3554 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
3556 CBufData cbufData = {
3557 1.0f /
float(levelPlusOneMipWidth),
3558 1.0f /
float(levelPlusOneMipHeight),
3559 1.0f /
float(levelPlusOneMipDepth),
3563 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3564 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3565 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3567 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3568 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3569 srvDesc.Format = res->desc.Format;
3570 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3571 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
3572 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
3574 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3575 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3577 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3578 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3579 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
3580 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3581 uavDesc.Format = res->desc.Format;
3582 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
3583 uavDesc.Texture3D.MipSlice = uavMipLevel;
3584 uavDesc.Texture3D.WSize = UINT(-1);
3585 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3586 uavCpuHandle.ptr += descriptorByteSize;
3587 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3589 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
3591 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3592 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3593 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3594 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3597 if (ownStagingArea.has_value())
3598 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3601bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
3603 this->device = device;
3610 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
3614 DXGI_ADAPTER_DESC1 desc;
3615 adapter->GetDesc1(&desc);
3616 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
3619 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3620 allocatorDesc.pDevice = device;
3621 allocatorDesc.pAdapter = adapter;
3624 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
3625 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3627 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
3628 qPrintable(QSystemError::windowsComString(hr)));
3634void QD3D12MemoryAllocator::destroy()
3637 allocator->Release();
3638 allocator =
nullptr;
3642HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
3643 const D3D12_RESOURCE_DESC *resourceDesc,
3644 D3D12_RESOURCE_STATES initialState,
3645 const D3D12_CLEAR_VALUE *optimizedClearValue,
3646 D3D12MA::Allocation **maybeAllocation,
3647 REFIID riidResource,
3651 D3D12MA::ALLOCATION_DESC allocDesc = {};
3652 allocDesc.HeapType = heapType;
3653 return allocator->CreateResource(&allocDesc,
3656 optimizedClearValue,
3661 *maybeAllocation =
nullptr;
3662 D3D12_HEAP_PROPERTIES heapProps = {};
3663 heapProps.Type = heapType;
3664 return device->CreateCommittedResource(&heapProps,
3665 D3D12_HEAP_FLAG_NONE,
3668 optimizedClearValue,
3674void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
3677 allocator->GetBudget(localBudget, nonLocalBudget);
3680 *nonLocalBudget = {};
3684void QRhiD3D12::waitGpu()
3686 fullFenceCounter += 1u;
3687 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
3688 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
3689 WaitForSingleObject(fullFenceEvent, INFINITE);
3693DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
3695 DXGI_SAMPLE_DESC desc;
3699 const int s = effectiveSampleCount(sampleCount);
3702 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
3703 msaaInfo.Format = format;
3704 msaaInfo.SampleCount = UINT(s);
3705 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
3706 if (msaaInfo.NumQualityLevels > 0) {
3707 desc.Count = UINT(s);
3708 desc.Quality = msaaInfo.NumQualityLevels - 1;
3710 qWarning(
"No quality levels for multisampling with sample count %d", s);
3718bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
3720 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
3722 HRESULT hr = dev->CreateCommandList(0,
3723 D3D12_COMMAND_LIST_TYPE_DIRECT,
3726 __uuidof(D3D12GraphicsCommandList),
3727 reinterpret_cast<
void **>(cmdList));
3729 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3733 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
3735 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3742static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
3745 case DXGI_FORMAT_R8G8B8A8_UNORM:
3746 return QRhiTexture::RGBA8;
3747 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
3749 (*flags) |= QRhiTexture::sRGB;
3750 return QRhiTexture::RGBA8;
3751 case DXGI_FORMAT_B8G8R8A8_UNORM:
3752 return QRhiTexture::BGRA8;
3753 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
3755 (*flags) |= QRhiTexture::sRGB;
3756 return QRhiTexture::BGRA8;
3757 case DXGI_FORMAT_R16G16B16A16_FLOAT:
3758 return QRhiTexture::RGBA16F;
3759 case DXGI_FORMAT_R32G32B32A32_FLOAT:
3760 return QRhiTexture::RGBA32F;
3761 case DXGI_FORMAT_R10G10B10A2_UNORM:
3762 return QRhiTexture::RGB10A2;
3764 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
3767 return QRhiTexture::UnknownFormat;
3770void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
3772 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
3774 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
3775 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
3776 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
3777 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3778 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
3779 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3780 if (u.offset == 0 && u.data.size() == bufD->m_size)
3781 bufD->pendingHostWrites[i].clear();
3782 bufD->pendingHostWrites[i].append({ u.offset, u.data });
3784 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
3785 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3786 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
3787 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3795 QD3D12StagingArea::Allocation stagingAlloc;
3796 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3797 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3798 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3800 std::optional<QD3D12StagingArea> ownStagingArea;
3801 if (!stagingAlloc.isValid()) {
3802 ownStagingArea = QD3D12StagingArea();
3803 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3805 stagingAlloc = ownStagingArea->get(allocSize);
3806 if (!stagingAlloc.isValid()) {
3807 ownStagingArea->destroy();
3812 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3814 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3815 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3817 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3818 cbD->cmdList->CopyBufferRegion(res->resource,
3820 stagingAlloc.buffer,
3821 stagingAlloc.bufferOffset + u.offset,
3825 if (ownStagingArea.has_value())
3826 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3827 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
3828 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3829 if (bufD->m_type == QRhiBuffer::Dynamic) {
3830 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3831 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3832 Q_ASSERT(res->cpuMapPtr);
3833 u.result->data.resize(u.readSize);
3834 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
3836 if (u.result->completed)
3837 u.result->completed();
3839 QD3D12Readback readback;
3840 readback.frameSlot = currentFrameSlot;
3841 readback.result = u.result;
3842 readback.byteSize = u.readSize;
3843 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3844 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3845 if (u.result->completed)
3846 u.result->completed();
3849 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3850 if (!stagingAlloc.isValid()) {
3851 readback.staging.destroy();
3852 if (u.result->completed)
3853 u.result->completed();
3856 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3857 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3858 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3859 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3860 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
3861 activeReadbacks.append(readback);
3863 readback.staging.destroy();
3864 if (u.result->completed)
3865 u.result->completed();
3871 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
3872 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
3873 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
3874 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3875 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3876 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
3879 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3880 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3881 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
3882 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
3883 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
3884 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
3885 footprint.Format = res->desc.Format;
3886 footprint.Depth = 1;
3887 quint32 totalBytes = 0;
3889 const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
3890 : subresDesc.sourceSize();
3891 const QPoint srcPos = subresDesc.sourceTopLeft();
3892 QPoint dstPos = subresDesc.destinationTopLeft();
3894 if (!subresDesc.image().isNull()) {
3895 const QImage img = subresDesc.image();
3896 const int bpl = img.bytesPerLine();
3897 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3898 totalBytes = footprint.RowPitch * img.height();
3899 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3902 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3903 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3904 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3905 totalBytes = footprint.RowPitch * rowCount;
3906 }
else if (!subresDesc.data().isEmpty()) {
3908 if (subresDesc.dataStride())
3909 bpl = subresDesc.dataStride();
3911 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3912 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3913 totalBytes = footprint.RowPitch * subresSize.height();
3915 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
3919 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
3920 QD3D12StagingArea::Allocation stagingAlloc;
3921 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3922 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3924 std::optional<QD3D12StagingArea> ownStagingArea;
3925 if (!stagingAlloc.isValid()) {
3926 ownStagingArea = QD3D12StagingArea();
3927 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3929 stagingAlloc = ownStagingArea->get(allocSize);
3930 if (!stagingAlloc.isValid()) {
3931 ownStagingArea->destroy();
3936 D3D12_TEXTURE_COPY_LOCATION dst;
3937 dst.pResource = res->resource;
3938 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3939 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
3940 D3D12_TEXTURE_COPY_LOCATION src;
3941 src.pResource = stagingAlloc.buffer;
3942 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3943 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3947 if (!subresDesc.image().isNull()) {
3948 const QImage img = subresDesc.image();
3949 const int bpc = qMax(1, img.depth() / 8);
3950 const int bpl = img.bytesPerLine();
3952 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
3953 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
3954 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
3955 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
3957 footprint.Width = size.width();
3958 footprint.Height = size.height();
3962 srcBox.right = UINT(size.width());
3963 srcBox.bottom = UINT(size.height());
3967 const uchar *imgPtr = img.constBits();
3968 const quint32 lineBytes = size.width() * bpc;
3969 for (
int y = 0, h = size.height(); y < h; ++y) {
3970 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3971 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3974 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3977 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3979 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3980 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3985 srcBox.right = aligned(subresSize.width(), blockDim.width());
3986 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3991 footprint.Width = aligned(subresSize.width(), blockDim.width());
3992 footprint.Height = aligned(subresSize.height(), blockDim.height());
3994 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3995 const QByteArray imgData = subresDesc.data();
3996 const char *imgPtr = imgData.constData();
3997 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3998 for (
int y = 0; y < rowCount; ++y)
3999 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
4000 }
else if (!subresDesc.data().isEmpty()) {
4003 srcBox.right = subresSize.width();
4004 srcBox.bottom = subresSize.height();
4008 footprint.Width = subresSize.width();
4009 footprint.Height = subresSize.height();
4012 if (subresDesc.dataStride())
4013 bpl = subresDesc.dataStride();
4015 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4017 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4018 const QByteArray data = subresDesc.data();
4019 const char *imgPtr = data.constData();
4020 for (
int y = 0, h = subresSize.height(); y < h; ++y)
4021 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
4024 src.PlacedFootprint.Footprint = footprint;
4026 cbD->cmdList->CopyTextureRegion(&dst,
4029 is3D ? UINT(layer) : 0u,
4033 if (ownStagingArea.has_value())
4034 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4038 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4039 Q_ASSERT(u.src && u.dst);
4040 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4041 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4042 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4043 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4044 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4045 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4046 if (!srcRes || !dstRes)
4049 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4050 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4051 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4053 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4054 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4055 srcD->mipLevelCount);
4056 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4057 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4058 dstD->mipLevelCount);
4059 const QPoint dp = u.desc.destinationTopLeft();
4060 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4061 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4062 const QPoint sp = u.desc.sourceTopLeft();
4065 srcBox.left = UINT(sp.x());
4066 srcBox.top = UINT(sp.y());
4067 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4069 srcBox.right = srcBox.left + UINT(copySize.width());
4070 srcBox.bottom = srcBox.top + UINT(copySize.height());
4071 srcBox.back = srcBox.front + 1;
4073 D3D12_TEXTURE_COPY_LOCATION src;
4074 src.pResource = srcRes->resource;
4075 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4076 src.SubresourceIndex = srcSubresource;
4077 D3D12_TEXTURE_COPY_LOCATION dst;
4078 dst.pResource = dstRes->resource;
4079 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4080 dst.SubresourceIndex = dstSubresource;
4082 cbD->cmdList->CopyTextureRegion(&dst,
4085 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4088 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4089 QD3D12Readback readback;
4090 readback.frameSlot = currentFrameSlot;
4091 readback.result = u.result;
4093 QD3D12ObjectHandle srcHandle;
4096 if (u.rb.texture()) {
4097 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4098 if (texD->sampleDesc.Count > 1) {
4099 qWarning(
"Multisample texture cannot be read back");
4102 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4103 if (u.rb.rect().isValid())
4106 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4107 readback.format = texD->m_format;
4108 srcHandle = texD->handle;
4110 Q_ASSERT(currentSwapChain);
4111 if (u.rb.rect().isValid())
4114 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4115 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4116 if (readback.format == QRhiTexture::UnknownFormat)
4118 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4120 readback.pixelSize = rect.size();
4122 textureFormatInfo(readback.format,
4124 &readback.bytesPerLine,
4128 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4132 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4133 is3D ? 0u : UINT(u.rb.layer()),
4134 srcRes->desc.MipLevels);
4135 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4138 UINT64 totalBytes = 0;
4139 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4140 &layout,
nullptr,
nullptr, &totalBytes);
4141 readback.stagingRowPitch = layout.Footprint.RowPitch;
4143 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
4144 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4145 if (u.result->completed)
4146 u.result->completed();
4149 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
4150 if (!stagingAlloc.isValid()) {
4151 readback.staging.destroy();
4152 if (u.result->completed)
4153 u.result->completed();
4156 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4158 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4159 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4161 D3D12_TEXTURE_COPY_LOCATION dst;
4162 dst.pResource = stagingAlloc.buffer;
4163 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4164 dst.PlacedFootprint.Offset = 0;
4165 dst.PlacedFootprint.Footprint = layout.Footprint;
4167 D3D12_TEXTURE_COPY_LOCATION src;
4168 src.pResource = srcRes->resource;
4169 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4170 src.SubresourceIndex = subresource;
4172 D3D12_BOX srcBox = {};
4173 srcBox.left = UINT(rect.left());
4174 srcBox.top = UINT(rect.top());
4175 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4177 srcBox.right = srcBox.left + UINT(rect.width());
4178 srcBox.bottom = srcBox.top + UINT(rect.height());
4179 srcBox.back = srcBox.front + 1;
4181 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4182 activeReadbacks.append(readback);
4183 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4184 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4185 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4186 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4187 mipmapGen3D.generate(cbD, texD->handle);
4189 mipmapGen.generate(cbD, texD->handle);
4196void QRhiD3D12::finishActiveReadbacks(
bool forced)
4198 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4200 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4201 QD3D12Readback &readback(activeReadbacks[i]);
4202 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4203 readback.result->format = readback.format;
4204 readback.result->pixelSize = readback.pixelSize;
4205 readback.result->data.resize(
int(readback.byteSize));
4207 if (readback.format != QRhiTexture::UnknownFormat) {
4208 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4209 const quint8 *srcPtr = readback.staging.mem.p;
4210 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4211 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4212 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4214 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4217 readback.staging.destroy();
4219 if (readback.result->completed)
4220 completedCallbacks.append(readback.result->completed);
4222 activeReadbacks.remove(i);
4226 for (
auto f : completedCallbacks)
4230bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4231 D3D12_DESCRIPTOR_HEAP_TYPE type,
4233 quint32 neededDescriptorCount,
4241 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4242 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4243 neededDescriptorCount);
4244 QD3D12ShaderVisibleDescriptorHeap newHeap;
4245 if (!newHeap.create(dev, type, newPerFrameSize)) {
4246 qWarning(
"Could not create new shader-visible descriptor heap");
4249 h->destroyWithDeferredRelease(&releaseQueue);
4256void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4258 ID3D12DescriptorHeap *heaps[] = {
4259 shaderVisibleCbvSrvUavHeap.heap.heap,
4260 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4262 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4265QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4266 : QRhiBuffer(rhi, type, usage, size)
4270QD3D12Buffer::~QD3D12Buffer()
4275void QD3D12Buffer::destroy()
4277 if (handles[0].isNull())
4280 QRHI_RES_RHI(QRhiD3D12);
4289 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4291 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4293 pendingHostWrites[i].clear();
4297 rhiD->unregisterResource(
this);
4300bool QD3D12Buffer::create()
4302 if (!handles[0].isNull())
4305 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4306 qWarning(
"UniformBuffer must always be Dynamic");
4310 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4311 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4315 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4316 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4318 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4319 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4320 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4322 QRHI_RES_RHI(QRhiD3D12);
4324 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4325 if (i == 0 || m_type == Dynamic) {
4326 D3D12_RESOURCE_DESC resourceDesc = {};
4327 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4328 resourceDesc.Width = roundedSize;
4329 resourceDesc.Height = 1;
4330 resourceDesc.DepthOrArraySize = 1;
4331 resourceDesc.MipLevels = 1;
4332 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4333 resourceDesc.SampleDesc = { 1, 0 };
4334 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4335 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4336 ID3D12Resource *resource =
nullptr;
4337 D3D12MA::Allocation *allocation =
nullptr;
4339 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4340 ? D3D12_HEAP_TYPE_UPLOAD
4341 : D3D12_HEAP_TYPE_DEFAULT;
4342 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4343 ? D3D12_RESOURCE_STATE_GENERIC_READ
4344 : D3D12_RESOURCE_STATE_COMMON;
4345 hr = rhiD->vma.createResource(heapType,
4351 reinterpret_cast<
void **>(&resource));
4354 if (!m_objectName.isEmpty()) {
4355 QString decoratedName = QString::fromUtf8(m_objectName);
4356 if (m_type == Dynamic) {
4357 decoratedName += QLatin1Char(
'/');
4358 decoratedName += QString::number(i);
4360 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4362 void *cpuMemPtr =
nullptr;
4363 if (m_type == Dynamic) {
4365 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4367 qWarning(
"Map() failed to dynamic buffer");
4368 resource->Release();
4370 allocation->Release();
4374 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4382 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4383 qPrintable(QSystemError::windowsComString(hr)),
4386 int(rhiD->vma.isUsingD3D12MA()));
4390 rhiD->registerResource(
this);
4394QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4397 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4398 QRHI_RES_RHI(QRhiD3D12);
4399 if (m_type == Dynamic) {
4400 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4401 executeHostWritesForFrameSlot(i);
4402 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4403 b.objects[i] = res->resource;
4405 b.objects[i] =
nullptr;
4407 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4410 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4411 b.objects[0] = res->resource;
4413 b.objects[0] =
nullptr;
4418char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4426 Q_ASSERT(m_type == Dynamic);
4427 QRHI_RES_RHI(QRhiD3D12);
4428 Q_ASSERT(rhiD->inFrame);
4429 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4430 return static_cast<
char *>(res->cpuMapPtr);
4435void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4440void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4442 if (pendingHostWrites[frameSlot].isEmpty())
4445 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4446 QRHI_RES_RHI(QRhiD3D12);
4447 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4448 Q_ASSERT(res->cpuMapPtr);
4449 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4450 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4452 pendingHostWrites[frameSlot].clear();
4455static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4457 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4459 case QRhiTexture::RGBA8:
4460 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4461 case QRhiTexture::BGRA8:
4462 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4463 case QRhiTexture::R8:
4464 return DXGI_FORMAT_R8_UNORM;
4465 case QRhiTexture::R8SI:
4466 return DXGI_FORMAT_R8_SINT;
4467 case QRhiTexture::R8UI:
4468 return DXGI_FORMAT_R8_UINT;
4469 case QRhiTexture::RG8:
4470 return DXGI_FORMAT_R8G8_UNORM;
4471 case QRhiTexture::R16:
4472 return DXGI_FORMAT_R16_UNORM;
4473 case QRhiTexture::RG16:
4474 return DXGI_FORMAT_R16G16_UNORM;
4475 case QRhiTexture::RED_OR_ALPHA8:
4476 return DXGI_FORMAT_R8_UNORM;
4478 case QRhiTexture::RGBA16F:
4479 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4480 case QRhiTexture::RGBA32F:
4481 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4482 case QRhiTexture::R16F:
4483 return DXGI_FORMAT_R16_FLOAT;
4484 case QRhiTexture::R32F:
4485 return DXGI_FORMAT_R32_FLOAT;
4487 case QRhiTexture::RGB10A2:
4488 return DXGI_FORMAT_R10G10B10A2_UNORM;
4490 case QRhiTexture::R32SI:
4491 return DXGI_FORMAT_R32_SINT;
4492 case QRhiTexture::R32UI:
4493 return DXGI_FORMAT_R32_UINT;
4494 case QRhiTexture::RG32SI:
4495 return DXGI_FORMAT_R32G32_SINT;
4496 case QRhiTexture::RG32UI:
4497 return DXGI_FORMAT_R32G32_UINT;
4498 case QRhiTexture::RGBA32SI:
4499 return DXGI_FORMAT_R32G32B32A32_SINT;
4500 case QRhiTexture::RGBA32UI:
4501 return DXGI_FORMAT_R32G32B32A32_UINT;
4503 case QRhiTexture::D16:
4504 return DXGI_FORMAT_R16_TYPELESS;
4505 case QRhiTexture::D24:
4506 return DXGI_FORMAT_R24G8_TYPELESS;
4507 case QRhiTexture::D24S8:
4508 return DXGI_FORMAT_R24G8_TYPELESS;
4509 case QRhiTexture::D32F:
4510 return DXGI_FORMAT_R32_TYPELESS;
4511 case QRhiTexture::Format::D32FS8:
4512 return DXGI_FORMAT_R32G8X24_TYPELESS;
4514 case QRhiTexture::BC1:
4515 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4516 case QRhiTexture::BC2:
4517 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4518 case QRhiTexture::BC3:
4519 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4520 case QRhiTexture::BC4:
4521 return DXGI_FORMAT_BC4_UNORM;
4522 case QRhiTexture::BC5:
4523 return DXGI_FORMAT_BC5_UNORM;
4524 case QRhiTexture::BC6H:
4525 return DXGI_FORMAT_BC6H_UF16;
4526 case QRhiTexture::BC7:
4527 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4529 case QRhiTexture::ETC2_RGB8:
4530 case QRhiTexture::ETC2_RGB8A1:
4531 case QRhiTexture::ETC2_RGBA8:
4532 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4533 return DXGI_FORMAT_R8G8B8A8_UNORM;
4535 case QRhiTexture::ASTC_4x4:
4536 case QRhiTexture::ASTC_5x4:
4537 case QRhiTexture::ASTC_5x5:
4538 case QRhiTexture::ASTC_6x5:
4539 case QRhiTexture::ASTC_6x6:
4540 case QRhiTexture::ASTC_8x5:
4541 case QRhiTexture::ASTC_8x6:
4542 case QRhiTexture::ASTC_8x8:
4543 case QRhiTexture::ASTC_10x5:
4544 case QRhiTexture::ASTC_10x6:
4545 case QRhiTexture::ASTC_10x8:
4546 case QRhiTexture::ASTC_10x10:
4547 case QRhiTexture::ASTC_12x10:
4548 case QRhiTexture::ASTC_12x12:
4549 qWarning(
"QRhiD3D12 does not support ASTC textures");
4550 return DXGI_FORMAT_R8G8B8A8_UNORM;
4555 return DXGI_FORMAT_R8G8B8A8_UNORM;
4558QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4560 const QSize &pixelSize,
4563 QRhiTexture::Format backingFormatHint)
4564 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4568QD3D12RenderBuffer::~QD3D12RenderBuffer()
4573void QD3D12RenderBuffer::destroy()
4575 if (handle.isNull())
4578 QRHI_RES_RHI(QRhiD3D12);
4581 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4582 else if (dsv.isValid())
4583 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4591 rhiD->unregisterResource(
this);
4594bool QD3D12RenderBuffer::create()
4596 if (!handle.isNull())
4599 if (m_pixelSize.isEmpty())
4602 QRHI_RES_RHI(QRhiD3D12);
4605 case QRhiRenderBuffer::Color:
4607 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4608 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4609 D3D12_RESOURCE_DESC resourceDesc = {};
4610 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4611 resourceDesc.Width = UINT64(m_pixelSize.width());
4612 resourceDesc.Height = UINT(m_pixelSize.height());
4613 resourceDesc.DepthOrArraySize = 1;
4614 resourceDesc.MipLevels = 1;
4615 resourceDesc.Format = dxgiFormat;
4616 resourceDesc.SampleDesc = sampleDesc;
4617 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4618 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4619 D3D12_CLEAR_VALUE clearValue = {};
4620 clearValue.Format = dxgiFormat;
4622 ID3D12Resource *resource =
nullptr;
4623 D3D12MA::Allocation *allocation =
nullptr;
4624 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4626 D3D12_RESOURCE_STATE_RENDER_TARGET,
4629 __uuidof(ID3D12Resource),
4630 reinterpret_cast<
void **>(&resource));
4632 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4635 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4636 rtv = rhiD->rtvPool.allocate(1);
4639 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4640 rtvDesc.Format = dxgiFormat;
4641 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4642 : D3D12_RTV_DIMENSION_TEXTURE2D;
4643 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4646 case QRhiRenderBuffer::DepthStencil:
4648 dxgiFormat = DS_FORMAT;
4649 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4650 D3D12_RESOURCE_DESC resourceDesc = {};
4651 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4652 resourceDesc.Width = UINT64(m_pixelSize.width());
4653 resourceDesc.Height = UINT(m_pixelSize.height());
4654 resourceDesc.DepthOrArraySize = 1;
4655 resourceDesc.MipLevels = 1;
4656 resourceDesc.Format = dxgiFormat;
4657 resourceDesc.SampleDesc = sampleDesc;
4658 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4659 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4660 if (m_flags.testFlag(UsedWithSwapChainOnly))
4661 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4662 D3D12_CLEAR_VALUE clearValue = {};
4663 clearValue.Format = dxgiFormat;
4664 clearValue.DepthStencil.Depth = 1.0f;
4665 clearValue.DepthStencil.Stencil = 0;
4666 ID3D12Resource *resource =
nullptr;
4667 D3D12MA::Allocation *allocation =
nullptr;
4668 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4670 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4673 __uuidof(ID3D12Resource),
4674 reinterpret_cast<
void **>(&resource));
4676 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4679 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4680 dsv = rhiD->dsvPool.allocate(1);
4683 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4684 dsvDesc.Format = dxgiFormat;
4685 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4686 : D3D12_DSV_DIMENSION_TEXTURE2D;
4687 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4692 if (!m_objectName.isEmpty()) {
4693 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4694 const QString name = QString::fromUtf8(m_objectName);
4695 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4700 rhiD->registerResource(
this);
4704QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4706 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4707 return m_backingFormatHint;
4709 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4712QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4713 int arraySize,
int sampleCount, Flags flags)
4714 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4718QD3D12Texture::~QD3D12Texture()
4723void QD3D12Texture::destroy()
4725 if (handle.isNull())
4728 QRHI_RES_RHI(QRhiD3D12);
4730 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4736 rhiD->unregisterResource(
this);
4739static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4742 case QRhiTexture::Format::D16:
4743 return DXGI_FORMAT_R16_FLOAT;
4744 case QRhiTexture::Format::D24:
4745 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4746 case QRhiTexture::Format::D24S8:
4747 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4748 case QRhiTexture::Format::D32F:
4749 return DXGI_FORMAT_R32_FLOAT;
4750 case QRhiTexture::Format::D32FS8:
4751 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4755 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4758static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4762 case QRhiTexture::Format::D16:
4763 return DXGI_FORMAT_D16_UNORM;
4764 case QRhiTexture::Format::D24:
4765 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4766 case QRhiTexture::Format::D24S8:
4767 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4768 case QRhiTexture::Format::D32F:
4769 return DXGI_FORMAT_D32_FLOAT;
4770 case QRhiTexture::Format::D32FS8:
4771 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4775 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4778static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4781 case QRhiTexture::Format::D16:
4782 case QRhiTexture::Format::D24:
4783 case QRhiTexture::Format::D24S8:
4784 case QRhiTexture::Format::D32F:
4785 case QRhiTexture::Format::D32FS8:
4792bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4794 if (!handle.isNull())
4797 QRHI_RES_RHI(QRhiD3D12);
4798 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4801 const bool isDepth = isDepthTextureFormat(m_format);
4802 const bool isCube = m_flags.testFlag(CubeMap);
4803 const bool is3D = m_flags.testFlag(ThreeDimensional);
4804 const bool isArray = m_flags.testFlag(TextureArray);
4805 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4806 const bool is1D = m_flags.testFlag(OneDimensional);
4808 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4809 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4811 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4813 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4814 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4816 srvFormat = dxgiFormat;
4817 rtFormat = dxgiFormat;
4819 if (m_writeViewFormat.format != UnknownFormat) {
4821 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4823 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4825 if (m_readViewFormat.format != UnknownFormat) {
4827 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4829 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4832 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4833 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4834 if (sampleDesc.Count > 1) {
4836 qWarning(
"Cubemap texture cannot be multisample");
4840 qWarning(
"3D texture cannot be multisample");
4844 qWarning(
"Multisample texture cannot have mipmaps");
4848 if (isDepth && hasMipMaps) {
4849 qWarning(
"Depth texture cannot have mipmaps");
4852 if (isCube && is3D) {
4853 qWarning(
"Texture cannot be both cube and 3D");
4856 if (isArray && is3D) {
4857 qWarning(
"Texture cannot be both array and 3D");
4860 if (isCube && is1D) {
4861 qWarning(
"Texture cannot be both cube and 1D");
4865 qWarning(
"Texture cannot be both 1D and 3D");
4868 if (m_depth > 1 && !is3D) {
4869 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4872 if (m_arraySize > 0 && !isArray) {
4873 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4876 if (m_arraySize < 1 && isArray) {
4877 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4882 *adjustedSize = size;
4887bool QD3D12Texture::finishCreate()
4889 QRHI_RES_RHI(QRhiD3D12);
4890 const bool isCube = m_flags.testFlag(CubeMap);
4891 const bool is3D = m_flags.testFlag(ThreeDimensional);
4892 const bool isArray = m_flags.testFlag(TextureArray);
4893 const bool is1D = m_flags.testFlag(OneDimensional);
4895 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4896 srvDesc.Format = srvFormat;
4897 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4900 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4901 srvDesc.TextureCube.MipLevels = mipLevelCount;
4905 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4906 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4907 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4908 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4909 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4911 srvDesc.Texture1DArray.FirstArraySlice = 0;
4912 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4915 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4916 srvDesc.Texture1D.MipLevels = mipLevelCount;
4918 }
else if (isArray) {
4919 if (sampleDesc.Count > 1) {
4920 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4921 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4922 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4923 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4925 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4926 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4929 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4930 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4931 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4932 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4933 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4935 srvDesc.Texture2DArray.FirstArraySlice = 0;
4936 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4940 if (sampleDesc.Count > 1) {
4941 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4943 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4944 srvDesc.Texture3D.MipLevels = mipLevelCount;
4946 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4947 srvDesc.Texture2D.MipLevels = mipLevelCount;
4952 srv = rhiD->cbvSrvUavPool.allocate(1);
4956 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4957 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4958 if (!m_objectName.isEmpty()) {
4959 const QString name = QString::fromUtf8(m_objectName);
4960 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4970bool QD3D12Texture::create()
4973 if (!prepareCreate(&size))
4976 const bool isDepth = isDepthTextureFormat(m_format);
4977 const bool isCube = m_flags.testFlag(CubeMap);
4978 const bool is3D = m_flags.testFlag(ThreeDimensional);
4979 const bool isArray = m_flags.testFlag(TextureArray);
4980 const bool is1D = m_flags.testFlag(OneDimensional);
4982 QRHI_RES_RHI(QRhiD3D12);
4984 bool needsOptimizedClearValueSpecified =
false;
4985 UINT resourceFlags = 0;
4986 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4988 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4990 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4991 needsOptimizedClearValueSpecified =
true;
4993 if (m_flags.testFlag(UsedWithGenerateMips)) {
4995 qWarning(
"Depth texture cannot have mipmaps generated");
4998 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5000 if (m_flags.testFlag(UsedWithLoadStore))
5001 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5003 D3D12_RESOURCE_DESC resourceDesc = {};
5004 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
5005 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
5006 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
5007 resourceDesc.Width = UINT64(size.width());
5008 resourceDesc.Height = UINT(size.height());
5009 resourceDesc.DepthOrArraySize = isCube ? 6
5010 : (isArray ? UINT(qMax(0, m_arraySize))
5011 : (is3D ? qMax(1, m_depth)
5013 resourceDesc.MipLevels = mipLevelCount;
5014 resourceDesc.Format = dxgiFormat;
5015 resourceDesc.SampleDesc = sampleDesc;
5016 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5017 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5018 D3D12_CLEAR_VALUE clearValue = {};
5019 clearValue.Format = dxgiFormat;
5021 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
5022 clearValue.DepthStencil.Depth = 1.0f;
5023 clearValue.DepthStencil.Stencil = 0;
5025 ID3D12Resource *resource =
nullptr;
5026 D3D12MA::Allocation *allocation =
nullptr;
5027 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5029 D3D12_RESOURCE_STATE_COMMON,
5030 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
5032 __uuidof(ID3D12Resource),
5033 reinterpret_cast<
void **>(&resource));
5035 qWarning(
"Failed to create texture: '%s'"
5036 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
5037 qPrintable(QSystemError::windowsComString(hr)),
5038 int(resourceDesc.Dimension),
5039 uint(resourceDesc.Width),
5040 uint(resourceDesc.Height),
5041 uint(resourceDesc.DepthOrArraySize),
5042 uint(resourceDesc.MipLevels),
5043 int(resourceDesc.Format),
5044 int(resourceDesc.SampleDesc.Count));
5048 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
5050 if (!finishCreate())
5053 rhiD->registerResource(
this);
5057bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
5062 if (!prepareCreate())
5065 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
5066 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
5068 QRHI_RES_RHI(QRhiD3D12);
5069 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
5071 if (!finishCreate())
5074 rhiD->registerResource(
this);
5078QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
5080 QRHI_RES_RHI(QRhiD3D12);
5081 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5082 return { quint64(res->resource),
int(res->state) };
5087void QD3D12Texture::setNativeLayout(
int layout)
5089 QRHI_RES_RHI(QRhiD3D12);
5090 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5091 res->state = D3D12_RESOURCE_STATES(layout);
5094QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
5095 AddressMode u, AddressMode v, AddressMode w)
5096 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5100QD3D12Sampler::~QD3D12Sampler()
5105void QD3D12Sampler::destroy()
5107 shaderVisibleDescriptor = {};
5109 QRHI_RES_RHI(QRhiD3D12);
5111 rhiD->unregisterResource(
this);
5114static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
5116 if (minFilter == QRhiSampler::Nearest) {
5117 if (magFilter == QRhiSampler::Nearest) {
5118 if (mipFilter == QRhiSampler::Linear)
5119 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
5121 return D3D12_FILTER_MIN_MAG_MIP_POINT;
5123 if (mipFilter == QRhiSampler::Linear)
5124 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
5126 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
5129 if (magFilter == QRhiSampler::Nearest) {
5130 if (mipFilter == QRhiSampler::Linear)
5131 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
5133 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
5135 if (mipFilter == QRhiSampler::Linear)
5136 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
5138 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
5141 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
5144static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
5147 case QRhiSampler::Repeat:
5148 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
5149 case QRhiSampler::ClampToEdge:
5150 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
5151 case QRhiSampler::Mirror:
5152 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
5154 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5157static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5160 case QRhiSampler::Never:
5161 return D3D12_COMPARISON_FUNC_NEVER;
5162 case QRhiSampler::Less:
5163 return D3D12_COMPARISON_FUNC_LESS;
5164 case QRhiSampler::Equal:
5165 return D3D12_COMPARISON_FUNC_EQUAL;
5166 case QRhiSampler::LessOrEqual:
5167 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5168 case QRhiSampler::Greater:
5169 return D3D12_COMPARISON_FUNC_GREATER;
5170 case QRhiSampler::NotEqual:
5171 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5172 case QRhiSampler::GreaterOrEqual:
5173 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5174 case QRhiSampler::Always:
5175 return D3D12_COMPARISON_FUNC_ALWAYS;
5177 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5180bool QD3D12Sampler::create()
5183 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5184 if (m_compareOp != Never)
5185 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5186 desc.AddressU = toD3DAddressMode(m_addressU);
5187 desc.AddressV = toD3DAddressMode(m_addressV);
5188 desc.AddressW = toD3DAddressMode(m_addressW);
5189 desc.MaxAnisotropy = 1.0f;
5190 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5191 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5193 QRHI_RES_RHI(QRhiD3D12);
5194 rhiD->registerResource(
this,
false);
5198QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5200 if (!shaderVisibleDescriptor.isValid()) {
5201 QRHI_RES_RHI(QRhiD3D12);
5202 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5204 return shaderVisibleDescriptor;
5207QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5208 : QRhiShadingRateMap(rhi)
5212QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5217void QD3D12ShadingRateMap::destroy()
5219 if (handle.isNull())
5225bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5227 if (!handle.isNull())
5230 handle = QRHI_RES(QD3D12Texture, src)->handle;
5235QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5236 const QRhiTextureRenderTargetDescription &desc,
5238 : QRhiTextureRenderTarget(rhi, desc, flags),
5243QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5248void QD3D12TextureRenderTarget::destroy()
5250 if (!rtv[0].isValid() && !dsv.isValid())
5253 QRHI_RES_RHI(QRhiD3D12);
5254 if (dsv.isValid()) {
5255 if (ownsDsv && rhiD)
5256 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5260 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5261 if (rtv[i].isValid()) {
5262 if (ownsRtv[i] && rhiD)
5263 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5269 rhiD->unregisterResource(
this);
5272QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5276 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5278 rpD->colorAttachmentCount = 0;
5279 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5280 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5281 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5283 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5285 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5286 rpD->colorAttachmentCount += 1;
5289 rpD->hasDepthStencil =
false;
5290 if (m_desc.depthStencilBuffer()) {
5291 rpD->hasDepthStencil =
true;
5292 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5293 }
else if (m_desc.depthTexture()) {
5294 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5295 rpD->hasDepthStencil =
true;
5296 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5299 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5301 rpD->updateSerializedFormat();
5303 QRHI_RES_RHI(QRhiD3D12);
5304 rhiD->registerResource(rpD);
5308bool QD3D12TextureRenderTarget::create()
5310 if (rtv[0].isValid() || dsv.isValid())
5313 QRHI_RES_RHI(QRhiD3D12);
5314 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5315 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5316 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5317 d.colorAttCount = 0;
5320 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5321 d.colorAttCount += 1;
5322 const QRhiColorAttachment &colorAtt(*it);
5323 QRhiTexture *texture = colorAtt.texture();
5324 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5325 Q_ASSERT(texture || rb);
5327 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5328 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5330 qWarning(
"Could not look up texture handle for render target");
5333 const bool isMultiView = it->multiViewCount() >= 2;
5334 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5335 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5336 rtvDesc.Format = texD->rtFormat;
5337 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5338 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5339 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5340 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5341 rtvDesc.Texture2DArray.ArraySize = layerCount;
5342 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5343 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5344 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5345 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5346 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5347 rtvDesc.Texture1DArray.ArraySize = layerCount;
5349 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5350 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5352 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5353 if (texD->sampleDesc.Count > 1) {
5354 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5355 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5356 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5358 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5359 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5360 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5361 rtvDesc.Texture2DArray.ArraySize = layerCount;
5363 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5364 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5365 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5366 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5367 rtvDesc.Texture3D.WSize = layerCount;
5369 if (texD->sampleDesc.Count > 1) {
5370 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5372 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5373 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5376 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5377 if (!rtv[attIndex].isValid()) {
5378 qWarning(
"Failed to allocate RTV for texture render target");
5381 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5382 ownsRtv[attIndex] =
true;
5383 if (attIndex == 0) {
5384 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5385 d.sampleCount =
int(texD->sampleDesc.Count);
5388 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5389 ownsRtv[attIndex] =
false;
5390 rtv[attIndex] = rbD->rtv;
5391 if (attIndex == 0) {
5392 d.pixelSize = rbD->pixelSize();
5393 d.sampleCount =
int(rbD->sampleDesc.Count);
5400 if (hasDepthStencil) {
5401 if (m_desc.depthTexture()) {
5403 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5404 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5406 qWarning(
"Could not look up depth texture handle");
5409 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5410 dsvDesc.Format = depthTexD->rtFormat;
5411 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
5412 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5413 if (isMultisample) {
5414 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5415 if (m_desc.depthLayer() >= 0) {
5416 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
5417 dsvDesc.Texture2DMSArray.ArraySize = 1;
5418 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5419 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5420 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5422 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5423 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5426 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5427 if (m_desc.depthLayer() >= 0) {
5428 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
5429 dsvDesc.Texture2DArray.ArraySize = 1;
5430 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5431 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5432 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5434 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5435 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5440 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5441 : D3D12_DSV_DIMENSION_TEXTURE2D;
5443 dsv = rhiD->dsvPool.allocate(1);
5444 if (!dsv.isValid()) {
5445 qWarning(
"Failed to allocate DSV for texture render target");
5448 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5449 if (d.colorAttCount == 0) {
5450 d.pixelSize = depthTexD->pixelSize();
5451 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5455 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5456 dsv = depthRbD->dsv;
5457 if (d.colorAttCount == 0) {
5458 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5459 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5467 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5468 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5469 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5470 d.dsv = dsv.cpuHandle;
5471 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5473 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5475 rhiD->registerResource(
this);
5479QSize QD3D12TextureRenderTarget::pixelSize()
const
5481 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5482 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5487float QD3D12TextureRenderTarget::devicePixelRatio()
const
5492int QD3D12TextureRenderTarget::sampleCount()
const
5494 return d.sampleCount;
5497QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5498 : QRhiShaderResourceBindings(rhi)
5502QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5507void QD3D12ShaderResourceBindings::destroy()
5509 QRHI_RES_RHI(QRhiD3D12);
5511 rhiD->unregisterResource(
this);
5514bool QD3D12ShaderResourceBindings::create()
5516 QRHI_RES_RHI(QRhiD3D12);
5517 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5520 rhiD->updateLayoutDesc(
this);
5522 hasDynamicOffset =
false;
5523 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5524 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5525 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5526 hasDynamicOffset =
true;
5540 rhiD->registerResource(
this,
false);
5544void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5555void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5556 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5560 D3D12_ROOT_PARAMETER1 rootParam = {};
5561 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5562 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5563 rootParam.Descriptor.ShaderRegister = shaderRegister;
5564 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5565 visitorData.cbParams[s].append(rootParam);
5568void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5569 const QRhiShaderResourceBinding::TextureAndSampler &,
5572 D3D12_DESCRIPTOR_RANGE1 range = {};
5573 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5574 range.NumDescriptors = 1;
5575 range.BaseShaderRegister = shaderRegister;
5576 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5577 visitorData.currentSrvRangeOffset[s] += 1;
5578 visitorData.srvRanges[s].append(range);
5579 if (visitorData.srvRanges[s].count() == 1) {
5580 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5581 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5585void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5586 const QRhiShaderResourceBinding::TextureAndSampler &,
5592 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5593 if (rangeStoreIdx == 16) {
5594 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5597 D3D12_DESCRIPTOR_RANGE1 range = {};
5598 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5599 range.NumDescriptors = 1;
5600 range.BaseShaderRegister = shaderRegister;
5601 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5602 D3D12_ROOT_PARAMETER1 param = {};
5603 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5604 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5605 param.DescriptorTable.NumDescriptorRanges = 1;
5606 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5608 visitorData.samplerTables[s].append(param);
5611void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5612 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5613 QD3D12ShaderResourceVisitor::StorageOp,
5616 D3D12_DESCRIPTOR_RANGE1 range = {};
5617 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5618 range.NumDescriptors = 1;
5619 range.BaseShaderRegister = shaderRegister;
5620 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5621 visitorData.currentUavRangeOffset[s] += 1;
5622 visitorData.uavRanges[s].append(range);
5623 if (visitorData.uavRanges[s].count() == 1) {
5624 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5625 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5629void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5630 const QRhiShaderResourceBinding::Data::StorageImageData &,
5631 QD3D12ShaderResourceVisitor::StorageOp,
5634 D3D12_DESCRIPTOR_RANGE1 range = {};
5635 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5636 range.NumDescriptors = 1;
5637 range.BaseShaderRegister = shaderRegister;
5638 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5639 visitorData.currentUavRangeOffset[s] += 1;
5640 visitorData.uavRanges[s].append(range);
5641 if (visitorData.uavRanges[s].count() == 1) {
5642 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5643 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5647QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5650 QRHI_RES_RHI(QRhiD3D12);
5664 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5668 using namespace std::placeholders;
5669 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5670 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5671 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5672 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5673 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5697 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5698 for (
int s = 0; s < 6; ++s) {
5699 if (!visitorData.cbParams[s].isEmpty())
5700 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5702 for (
int s = 0; s < 6; ++s) {
5703 if (!visitorData.srvRanges[s].isEmpty()) {
5704 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5705 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5706 rootParams.append(visitorData.srvTables[s]);
5709 for (
int s = 0; s < 6; ++s) {
5710 if (!visitorData.samplerTables[s].isEmpty())
5711 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5713 for (
int s = 0; s < 6; ++s) {
5714 if (!visitorData.uavRanges[s].isEmpty()) {
5715 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5716 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5717 rootParams.append(visitorData.uavTables[s]);
5721 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5722 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5723 if (!rootParams.isEmpty()) {
5724 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5725 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5729 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5730 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5731 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5733 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5735 ID3DBlob *signature =
nullptr;
5736 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5738 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5741 ID3D12RootSignature *rootSig =
nullptr;
5742 hr = rhiD->dev->CreateRootSignature(0,
5743 signature->GetBufferPointer(),
5744 signature->GetBufferSize(),
5745 __uuidof(ID3D12RootSignature),
5746 reinterpret_cast<
void **>(&rootSig));
5747 signature->Release();
5749 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5753 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5765static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5767 const int smMajor = version / 10;
5768 const int smMinor = version % 10;
5769 target[0] = stage[0];
5770 target[1] = stage[1];
5772 target[3] =
'0' + smMajor;
5774 target[5] =
'0' + smMinor;
5778enum class HlslCompileFlag
5780 WithDebugInfo = 0x01
5783static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5785 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5787 qWarning(
"Unable to resolve function D3DCompile()");
5788 return QByteArray();
5791 ID3DBlob *bytecode =
nullptr;
5792 ID3DBlob *errors =
nullptr;
5793 UINT d3dCompileFlags = 0;
5794 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5795 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5797 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5798 nullptr,
nullptr,
nullptr,
5799 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5800 if (FAILED(hr) || !bytecode) {
5801 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5803 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5804 int(errors->GetBufferSize()));
5807 return QByteArray();
5811 result.resize(
int(bytecode->GetBufferSize()));
5812 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5813 bytecode->Release();
5817#ifdef QRHI_D3D12_HAS_DXC
5820#define DXC_CP_UTF8 65001
5823#ifndef DXC_ARG_DEBUG
5824#define DXC_ARG_DEBUG L"-Zi"
5827static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5829 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5830 IDxcCompiler *compiler = dxc.first;
5832 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5833 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5834 return QByteArray();
5836 IDxcLibrary *library = dxc.second;
5838 return QByteArray();
5840 IDxcBlobEncoding *sourceBlob =
nullptr;
5841 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5842 UINT32(hlslSource.shader().size()),
5846 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5848 qPrintable(QSystemError::windowsComString(hr)));
5849 return QByteArray();
5852 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5853 const QString targetStr = QString::fromLatin1(target);
5855 QVarLengthArray<LPCWSTR, 4> argPtrs;
5857 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5858 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5859 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5862 IDxcOperationResult *result =
nullptr;
5863 hr = compiler->Compile(sourceBlob,
5865 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5866 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5867 argPtrs.data(), argPtrs.count(),
5871 sourceBlob->Release();
5873 result->GetStatus(&hr);
5875 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5877 qPrintable(QSystemError::windowsComString(hr)));
5879 IDxcBlobEncoding *errorsBlob =
nullptr;
5880 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5882 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5883 int(errorsBlob->GetBufferSize()));
5884 errorsBlob->Release();
5888 return QByteArray();
5891 IDxcBlob *bytecode =
nullptr;
5892 if FAILED(result->GetResult(&bytecode)) {
5893 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5895 qPrintable(QSystemError::windowsComString(hr)));
5896 return QByteArray();
5900 ba.resize(
int(bytecode->GetBufferSize()));
5901 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5902 bytecode->Release();
5908static QByteArray compileHlslShaderSource(
const QShader &shader,
5909 QShader::Variant shaderVariant,
5912 QShaderKey *usedShaderKey)
5915 const int shaderModelMax = 67;
5916 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5917 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5918 QShaderKey key = { type, sm, shaderVariant };
5919 QShaderCode intermediateBytecodeShader = shader.shader(key);
5920 if (!intermediateBytecodeShader.shader().isEmpty()) {
5922 *usedShaderKey = key;
5923 return intermediateBytecodeShader.shader();
5928 QShaderCode hlslSource;
5930 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5931 key = { QShader::HlslShader, sm, shaderVariant };
5932 hlslSource = shader.shader(key);
5933 if (!hlslSource.shader().isEmpty())
5937 if (hlslSource.shader().isEmpty()) {
5938 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5939 return QByteArray();
5943 *usedShaderKey = key;
5946 switch (shader.stage()) {
5947 case QShader::VertexStage:
5948 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5950 case QShader::TessellationControlStage:
5951 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5953 case QShader::TessellationEvaluationStage:
5954 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5956 case QShader::GeometryStage:
5957 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5959 case QShader::FragmentStage:
5960 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5962 case QShader::ComputeStage:
5963 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5967 if (key.sourceVersion().version() >= 60) {
5968#ifdef QRHI_D3D12_HAS_DXC
5969 return dxcCompile(hlslSource, target, flags, error);
5971 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5972 "but the Qt build has no support for DXC. "
5973 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5977 return legacyCompile(hlslSource, target, flags, error);
5980static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5983 if (c.testFlag(QRhiGraphicsPipeline::R))
5984 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5985 if (c.testFlag(QRhiGraphicsPipeline::G))
5986 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5987 if (c.testFlag(QRhiGraphicsPipeline::B))
5988 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5989 if (c.testFlag(QRhiGraphicsPipeline::A))
5990 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5994static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
6003 case QRhiGraphicsPipeline::Zero:
6004 return D3D12_BLEND_ZERO;
6005 case QRhiGraphicsPipeline::One:
6006 return D3D12_BLEND_ONE;
6007 case QRhiGraphicsPipeline::SrcColor:
6008 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
6009 case QRhiGraphicsPipeline::OneMinusSrcColor:
6010 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
6011 case QRhiGraphicsPipeline::DstColor:
6012 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
6013 case QRhiGraphicsPipeline::OneMinusDstColor:
6014 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
6015 case QRhiGraphicsPipeline::SrcAlpha:
6016 return D3D12_BLEND_SRC_ALPHA;
6017 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6018 return D3D12_BLEND_INV_SRC_ALPHA;
6019 case QRhiGraphicsPipeline::DstAlpha:
6020 return D3D12_BLEND_DEST_ALPHA;
6021 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6022 return D3D12_BLEND_INV_DEST_ALPHA;
6023 case QRhiGraphicsPipeline::ConstantColor:
6024 case QRhiGraphicsPipeline::ConstantAlpha:
6025 return D3D12_BLEND_BLEND_FACTOR;
6026 case QRhiGraphicsPipeline::OneMinusConstantColor:
6027 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6028 return D3D12_BLEND_INV_BLEND_FACTOR;
6029 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6030 return D3D12_BLEND_SRC_ALPHA_SAT;
6031 case QRhiGraphicsPipeline::Src1Color:
6032 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
6033 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6034 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
6035 case QRhiGraphicsPipeline::Src1Alpha:
6036 return D3D12_BLEND_SRC1_ALPHA;
6037 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6038 return D3D12_BLEND_INV_SRC1_ALPHA;
6040 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
6043static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
6046 case QRhiGraphicsPipeline::Add:
6047 return D3D12_BLEND_OP_ADD;
6048 case QRhiGraphicsPipeline::Subtract:
6049 return D3D12_BLEND_OP_SUBTRACT;
6050 case QRhiGraphicsPipeline::ReverseSubtract:
6051 return D3D12_BLEND_OP_REV_SUBTRACT;
6052 case QRhiGraphicsPipeline::Min:
6053 return D3D12_BLEND_OP_MIN;
6054 case QRhiGraphicsPipeline::Max:
6055 return D3D12_BLEND_OP_MAX;
6057 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
6060static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
6063 case QRhiGraphicsPipeline::None:
6064 return D3D12_CULL_MODE_NONE;
6065 case QRhiGraphicsPipeline::Front:
6066 return D3D12_CULL_MODE_FRONT;
6067 case QRhiGraphicsPipeline::Back:
6068 return D3D12_CULL_MODE_BACK;
6070 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
6073static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
6076 case QRhiGraphicsPipeline::Fill:
6077 return D3D12_FILL_MODE_SOLID;
6078 case QRhiGraphicsPipeline::Line:
6079 return D3D12_FILL_MODE_WIREFRAME;
6081 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
6084static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
6087 case QRhiGraphicsPipeline::Never:
6088 return D3D12_COMPARISON_FUNC_NEVER;
6089 case QRhiGraphicsPipeline::Less:
6090 return D3D12_COMPARISON_FUNC_LESS;
6091 case QRhiGraphicsPipeline::Equal:
6092 return D3D12_COMPARISON_FUNC_EQUAL;
6093 case QRhiGraphicsPipeline::LessOrEqual:
6094 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6095 case QRhiGraphicsPipeline::Greater:
6096 return D3D12_COMPARISON_FUNC_GREATER;
6097 case QRhiGraphicsPipeline::NotEqual:
6098 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6099 case QRhiGraphicsPipeline::GreaterOrEqual:
6100 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6101 case QRhiGraphicsPipeline::Always:
6102 return D3D12_COMPARISON_FUNC_ALWAYS;
6104 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
6107static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
6110 case QRhiGraphicsPipeline::StencilZero:
6111 return D3D12_STENCIL_OP_ZERO;
6112 case QRhiGraphicsPipeline::Keep:
6113 return D3D12_STENCIL_OP_KEEP;
6114 case QRhiGraphicsPipeline::Replace:
6115 return D3D12_STENCIL_OP_REPLACE;
6116 case QRhiGraphicsPipeline::IncrementAndClamp:
6117 return D3D12_STENCIL_OP_INCR_SAT;
6118 case QRhiGraphicsPipeline::DecrementAndClamp:
6119 return D3D12_STENCIL_OP_DECR_SAT;
6120 case QRhiGraphicsPipeline::Invert:
6121 return D3D12_STENCIL_OP_INVERT;
6122 case QRhiGraphicsPipeline::IncrementAndWrap:
6123 return D3D12_STENCIL_OP_INCR;
6124 case QRhiGraphicsPipeline::DecrementAndWrap:
6125 return D3D12_STENCIL_OP_DECR;
6127 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
6130static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
6133 case QRhiGraphicsPipeline::Triangles:
6134 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
6135 case QRhiGraphicsPipeline::TriangleStrip:
6136 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6137 case QRhiGraphicsPipeline::TriangleFan:
6138 qWarning(
"Triangle fans are not supported with D3D");
6139 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6140 case QRhiGraphicsPipeline::Lines:
6141 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
6142 case QRhiGraphicsPipeline::LineStrip:
6143 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
6144 case QRhiGraphicsPipeline::Points:
6145 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
6146 case QRhiGraphicsPipeline::Patches:
6147 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
6148 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
6150 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
6153static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
6156 case QRhiGraphicsPipeline::Triangles:
6157 case QRhiGraphicsPipeline::TriangleStrip:
6158 case QRhiGraphicsPipeline::TriangleFan:
6159 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
6160 case QRhiGraphicsPipeline::Lines:
6161 case QRhiGraphicsPipeline::LineStrip:
6162 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
6163 case QRhiGraphicsPipeline::Points:
6164 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6165 case QRhiGraphicsPipeline::Patches:
6166 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6168 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6171static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6174 case QRhiVertexInputAttribute::Float4:
6175 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6176 case QRhiVertexInputAttribute::Float3:
6177 return DXGI_FORMAT_R32G32B32_FLOAT;
6178 case QRhiVertexInputAttribute::Float2:
6179 return DXGI_FORMAT_R32G32_FLOAT;
6180 case QRhiVertexInputAttribute::Float:
6181 return DXGI_FORMAT_R32_FLOAT;
6182 case QRhiVertexInputAttribute::UNormByte4:
6183 return DXGI_FORMAT_R8G8B8A8_UNORM;
6184 case QRhiVertexInputAttribute::UNormByte2:
6185 return DXGI_FORMAT_R8G8_UNORM;
6186 case QRhiVertexInputAttribute::UNormByte:
6187 return DXGI_FORMAT_R8_UNORM;
6188 case QRhiVertexInputAttribute::UInt4:
6189 return DXGI_FORMAT_R32G32B32A32_UINT;
6190 case QRhiVertexInputAttribute::UInt3:
6191 return DXGI_FORMAT_R32G32B32_UINT;
6192 case QRhiVertexInputAttribute::UInt2:
6193 return DXGI_FORMAT_R32G32_UINT;
6194 case QRhiVertexInputAttribute::UInt:
6195 return DXGI_FORMAT_R32_UINT;
6196 case QRhiVertexInputAttribute::SInt4:
6197 return DXGI_FORMAT_R32G32B32A32_SINT;
6198 case QRhiVertexInputAttribute::SInt3:
6199 return DXGI_FORMAT_R32G32B32_SINT;
6200 case QRhiVertexInputAttribute::SInt2:
6201 return DXGI_FORMAT_R32G32_SINT;
6202 case QRhiVertexInputAttribute::SInt:
6203 return DXGI_FORMAT_R32_SINT;
6204 case QRhiVertexInputAttribute::Half4:
6206 case QRhiVertexInputAttribute::Half3:
6207 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6208 case QRhiVertexInputAttribute::Half2:
6209 return DXGI_FORMAT_R16G16_FLOAT;
6210 case QRhiVertexInputAttribute::Half:
6211 return DXGI_FORMAT_R16_FLOAT;
6212 case QRhiVertexInputAttribute::UShort4:
6214 case QRhiVertexInputAttribute::UShort3:
6215 return DXGI_FORMAT_R16G16B16A16_UINT;
6216 case QRhiVertexInputAttribute::UShort2:
6217 return DXGI_FORMAT_R16G16_UINT;
6218 case QRhiVertexInputAttribute::UShort:
6219 return DXGI_FORMAT_R16_UINT;
6220 case QRhiVertexInputAttribute::SShort4:
6222 case QRhiVertexInputAttribute::SShort3:
6223 return DXGI_FORMAT_R16G16B16A16_SINT;
6224 case QRhiVertexInputAttribute::SShort2:
6225 return DXGI_FORMAT_R16G16_SINT;
6226 case QRhiVertexInputAttribute::SShort:
6227 return DXGI_FORMAT_R16_SINT;
6229 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6232QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6233 : QRhiGraphicsPipeline(rhi)
6237QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6242void QD3D12GraphicsPipeline::destroy()
6244 if (handle.isNull())
6247 QRHI_RES_RHI(QRhiD3D12);
6249 rhiD->releaseQueue.deferredReleasePipeline(handle);
6250 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6257 rhiD->unregisterResource(
this);
6260bool QD3D12GraphicsPipeline::create()
6262 if (!handle.isNull())
6265 QRHI_RES_RHI(QRhiD3D12);
6266 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6269 rhiD->pipelineCreationStart();
6271 QByteArray shaderBytecode[5];
6272 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6273 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6274 stageData[d3dStage].valid =
true;
6275 stageData[d3dStage].stage = d3dStage;
6276 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6277 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6278 shaderBytecode[d3dStage] = cacheIt->bytecode;
6279 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6282 QShaderKey shaderKey;
6283 int compileFlags = 0;
6284 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6285 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6286 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6287 shaderStage.shaderVariant(),
6291 if (bytecode.isEmpty()) {
6292 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6296 shaderBytecode[d3dStage] = bytecode;
6297 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6298 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6299 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6303 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6305 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6306 if (rootSigHandle.isNull()) {
6307 qWarning(
"Failed to create root signature");
6311 ID3D12RootSignature *rootSig =
nullptr;
6312 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6313 rootSig = rs->rootSig;
6315 qWarning(
"Cannot create graphics pipeline state without root signature");
6319 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6320 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6321 if (rpD->colorAttachmentCount > 0) {
6322 format = DXGI_FORMAT(rpD->colorFormat[0]);
6323 }
else if (rpD->hasDepthStencil) {
6324 format = DXGI_FORMAT(rpD->dsFormat);
6326 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6329 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6332 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6333 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6334 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6335 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6336 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6337 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6338 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6339 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6340 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6341 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6342 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6343 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6344 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6345 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6346 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6347 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6348 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6351 stream.rootSig.object = rootSig;
6353 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6354 QByteArrayList matrixSliceSemantics;
6355 if (!shaderBytecode[VS].isEmpty()) {
6356 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6359 D3D12_INPUT_ELEMENT_DESC desc = {};
6364 const int matrixSlice = it->matrixSlice();
6365 if (matrixSlice < 0) {
6366 desc.SemanticName =
"TEXCOORD";
6367 desc.SemanticIndex = UINT(it->location());
6371 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6372 matrixSliceSemantics.append(sem);
6373 desc.SemanticName = matrixSliceSemantics.last().constData();
6374 desc.SemanticIndex = UINT(matrixSlice);
6376 desc.Format = toD3DAttributeFormat(it->format());
6377 desc.InputSlot = UINT(it->binding());
6378 desc.AlignedByteOffset = it->offset();
6379 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6380 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6381 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6382 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6384 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6386 inputDescs.append(desc);
6390 stream.inputLayout.object.NumElements = inputDescs.count();
6391 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6393 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
6395 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
6396 topology = toD3DTopology(m_topology, m_patchControlPointCount);
6398 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6399 const int d3dStage = qd3d12_stage(shaderStage.type());
6402 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6403 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6406 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6407 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6410 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6411 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6414 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6415 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6418 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6419 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6427 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6428 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6429 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6430 stream.rasterizerState.object.DepthBias = m_depthBias;
6431 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6432 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
6433 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6435 stream.depthStencilState.object.DepthEnable = m_depthTest;
6436 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6437 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6438 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6439 if (m_stencilTest) {
6440 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6441 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6442 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6443 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6444 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6445 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6446 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6447 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6448 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6449 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6452 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6453 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6454 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6455 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6456 blend.BlendEnable = b.enable;
6457 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6458 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6459 blend.BlendOp = toD3DBlendOp(b.opColor);
6460 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6461 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6462 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6463 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6464 stream.blendState.object.RenderTarget[i] = blend;
6466 if (m_targetBlends.isEmpty()) {
6467 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6468 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6469 stream.blendState.object.RenderTarget[0] = blend;
6472 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6473 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6474 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6476 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6478 stream.sampleDesc.object = sampleDesc;
6480 stream.sampleMask.object = 0xFFFFFFFF;
6482 viewInstanceMask = 0;
6483 const bool isMultiView = m_multiViewCount >= 2;
6484 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6485 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6487 for (
int i = 0; i < m_multiViewCount; ++i) {
6488 viewInstanceMask |= (1 << i);
6489 viewInstanceLocations.append({ 0, UINT(i) });
6491 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6494 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6496 ID3D12PipelineState *pso =
nullptr;
6497 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6499 qWarning(
"Failed to create graphics pipeline state: %s",
6500 qPrintable(QSystemError::windowsComString(hr)));
6501 rhiD->rootSignaturePool.remove(rootSigHandle);
6506 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6508 rhiD->pipelineCreationEnd();
6510 rhiD->registerResource(
this);
6514QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6515 : QRhiComputePipeline(rhi)
6519QD3D12ComputePipeline::~QD3D12ComputePipeline()
6524void QD3D12ComputePipeline::destroy()
6526 if (handle.isNull())
6529 QRHI_RES_RHI(QRhiD3D12);
6531 rhiD->releaseQueue.deferredReleasePipeline(handle);
6532 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6539 rhiD->unregisterResource(
this);
6542bool QD3D12ComputePipeline::create()
6544 if (!handle.isNull())
6547 QRHI_RES_RHI(QRhiD3D12);
6548 rhiD->pipelineCreationStart();
6550 stageData.valid =
true;
6551 stageData.stage = CS;
6553 QByteArray shaderBytecode;
6554 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6555 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6556 shaderBytecode = cacheIt->bytecode;
6557 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6560 QShaderKey shaderKey;
6561 int compileFlags = 0;
6562 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6563 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6564 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6565 m_shaderStage.shaderVariant(),
6569 if (bytecode.isEmpty()) {
6570 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6574 shaderBytecode = bytecode;
6575 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6576 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6577 stageData.nativeResourceBindingMap });
6580 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6582 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6583 if (rootSigHandle.isNull()) {
6584 qWarning(
"Failed to create root signature");
6588 ID3D12RootSignature *rootSig =
nullptr;
6589 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6590 rootSig = rs->rootSig;
6592 qWarning(
"Cannot create compute pipeline state without root signature");
6597 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6598 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6600 stream.rootSig.object = rootSig;
6601 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6602 stream.CS.object.BytecodeLength = shaderBytecode.size();
6603 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6604 ID3D12PipelineState *pso =
nullptr;
6605 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6607 qWarning(
"Failed to create compute pipeline state: %s",
6608 qPrintable(QSystemError::windowsComString(hr)));
6609 rhiD->rootSignaturePool.remove(rootSigHandle);
6614 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6616 rhiD->pipelineCreationEnd();
6618 rhiD->registerResource(
this);
6625QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6626 : QRhiRenderPassDescriptor(rhi)
6628 serializedFormatData.reserve(16);
6631QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6636void QD3D12RenderPassDescriptor::destroy()
6638 QRHI_RES_RHI(QRhiD3D12);
6640 rhiD->unregisterResource(
this);
6643bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6648 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6650 if (colorAttachmentCount != o->colorAttachmentCount)
6653 if (hasDepthStencil != o->hasDepthStencil)
6656 for (
int i = 0; i < colorAttachmentCount; ++i) {
6657 if (colorFormat[i] != o->colorFormat[i])
6661 if (hasDepthStencil) {
6662 if (dsFormat != o->dsFormat)
6666 if (hasShadingRateMap != o->hasShadingRateMap)
6672void QD3D12RenderPassDescriptor::updateSerializedFormat()
6674 serializedFormatData.clear();
6675 auto p = std::back_inserter(serializedFormatData);
6677 *p++ = colorAttachmentCount;
6678 *p++ = hasDepthStencil;
6679 for (
int i = 0; i < colorAttachmentCount; ++i)
6680 *p++ = colorFormat[i];
6681 *p++ = hasDepthStencil ? dsFormat : 0;
6684QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6686 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6687 rpD->colorAttachmentCount = colorAttachmentCount;
6688 rpD->hasDepthStencil = hasDepthStencil;
6689 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6690 rpD->dsFormat = dsFormat;
6691 rpD->hasShadingRateMap = hasShadingRateMap;
6693 rpD->updateSerializedFormat();
6695 QRHI_RES_RHI(QRhiD3D12);
6696 rhiD->registerResource(rpD);
6700QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6702 return serializedFormatData;
6705QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6706 : QRhiCommandBuffer(rhi)
6711QD3D12CommandBuffer::~QD3D12CommandBuffer()
6716void QD3D12CommandBuffer::destroy()
6721const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6723 nativeHandlesStruct.commandList = cmdList;
6724 return &nativeHandlesStruct;
6727QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6728 : QRhiSwapChainRenderTarget(rhi, swapchain),
6733QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6738void QD3D12SwapChainRenderTarget::destroy()
6743QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6748float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6753int QD3D12SwapChainRenderTarget::sampleCount()
const
6755 return d.sampleCount;
6758QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6759 : QRhiSwapChain(rhi),
6760 rtWrapper(rhi,
this),
6761 rtWrapperRight(rhi,
this),
6766QD3D12SwapChain::~QD3D12SwapChain()
6771void QD3D12SwapChain::destroy()
6778 swapChain->Release();
6779 swapChain =
nullptr;
6780 sourceSwapChain1->Release();
6781 sourceSwapChain1 =
nullptr;
6783 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6784 FrameResources &fr(frameRes[i]);
6786 fr.fence->Release();
6788 CloseHandle(fr.fenceEvent);
6790 fr.cmdList->Release();
6795 dcompVisual->Release();
6796 dcompVisual =
nullptr;
6800 dcompTarget->Release();
6801 dcompTarget =
nullptr;
6804 if (frameLatencyWaitableObject) {
6805 CloseHandle(frameLatencyWaitableObject);
6806 frameLatencyWaitableObject =
nullptr;
6809 QDxgiVSyncService::instance()->unregisterWindow(window);
6811 QRHI_RES_RHI(QRhiD3D12);
6813 rhiD->swapchains.remove(
this);
6814 rhiD->unregisterResource(
this);
6818void QD3D12SwapChain::releaseBuffers()
6820 QRHI_RES_RHI(QRhiD3D12);
6822 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6823 rhiD->resourcePool.remove(colorBuffers[i]);
6824 rhiD->rtvPool.release(rtvs[i], 1);
6826 rhiD->rtvPool.release(rtvsRight[i], 1);
6827 if (!msaaBuffers[i].isNull())
6828 rhiD->resourcePool.remove(msaaBuffers[i]);
6829 if (msaaRtvs[i].isValid())
6830 rhiD->rtvPool.release(msaaRtvs[i], 1);
6834void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6836 FrameResources &fr(frameRes[frameSlot]);
6837 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6838 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6839 WaitForSingleObject(fr.fenceEvent, INFINITE);
6843void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6845 QRHI_RES_RHI(QRhiD3D12);
6846 FrameResources &fr(frameRes[currentFrameSlot]);
6847 fr.fenceCounter += 1u;
6848 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6851QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6856QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6861QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6863 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6866QSize QD3D12SwapChain::surfacePixelSize()
6869 return m_window->size() * m_window->devicePixelRatio();
6872bool QD3D12SwapChain::isFormatSupported(Format f)
6878 qWarning(
"Attempted to call isFormatSupported() without a window set");
6882 QRHI_RES_RHI(QRhiD3D12);
6883 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6884 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6889QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6891 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6894 QRHI_RES_RHI(QRhiD3D12);
6895 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6900QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6905 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6906 rpD->colorAttachmentCount = 1;
6907 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6908 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6909 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6911 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6913 rpD->updateSerializedFormat();
6915 QRHI_RES_RHI(QRhiD3D12);
6916 rhiD->registerResource(rpD);
6920bool QRhiD3D12::ensureDirectCompositionDevice()
6925 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6926 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6927 return dcompDevice ?
true :
false;
6930static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6931static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6933void QD3D12SwapChain::chooseFormats()
6935 colorFormat = DEFAULT_FORMAT;
6936 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6937 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6938 QRHI_RES_RHI(QRhiD3D12);
6939 if (m_format != SDR) {
6940 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6943 case HDRExtendedSrgbLinear:
6944 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6945 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6946 srgbAdjustedColorFormat = colorFormat;
6949 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6950 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6951 srgbAdjustedColorFormat = colorFormat;
6960 qWarning(
"The output associated with the window is not HDR capable "
6961 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6964 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6967bool QD3D12SwapChain::createOrResize()
6973 const bool needsRegistration = !window || window != m_window;
6976 if (window && window != m_window)
6980 m_currentPixelSize = surfacePixelSize();
6981 pixelSize = m_currentPixelSize;
6983 if (pixelSize.isEmpty())
6986 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6988 QRHI_RES_RHI(QRhiD3D12);
6989 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6991 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6992 if (rhiD->ensureDirectCompositionDevice()) {
6994 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6996 qWarning(
"Failed to create Direct Composition target for the window: %s",
6997 qPrintable(QSystemError::windowsComString(hr)));
7000 if (dcompTarget && !dcompVisual) {
7001 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
7003 qWarning(
"Failed to create DirectComposition visual: %s",
7004 qPrintable(QSystemError::windowsComString(hr)));
7009 if (window->requestedFormat().alphaBufferSize() <= 0)
7010 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
7011 "This may lead to problems.");
7014 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
7016 if (swapInterval == 0 && rhiD->supportsAllowTearing)
7017 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
7021 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
7022 && swapInterval != 0
7023 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
7024 if (useFrameLatencyWaitableObject)
7025 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
7030 DXGI_SWAP_CHAIN_DESC1 desc = {};
7031 desc.Width = UINT(pixelSize.width());
7032 desc.Height = UINT(pixelSize.height());
7033 desc.Format = colorFormat;
7034 desc.SampleDesc.Count = 1;
7035 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7036 desc.BufferCount = BUFFER_COUNT;
7037 desc.Flags = swapChainFlags;
7038 desc.Scaling = DXGI_SCALING_NONE;
7039 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7040 desc.Stereo = stereo;
7046 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
7051 desc.Scaling = DXGI_SCALING_STRETCH;
7055 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7057 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7062 if (FAILED(hr) && m_format != SDR) {
7063 colorFormat = DEFAULT_FORMAT;
7064 desc.Format = DEFAULT_FORMAT;
7066 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7068 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7071 if (SUCCEEDED(hr)) {
7072 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
7073 qWarning(
"IDXGISwapChain3 not available");
7076 if (m_format != SDR) {
7077 hr = swapChain->SetColorSpace1(hdrColorSpace);
7079 qWarning(
"Failed to set color space on swapchain: %s",
7080 qPrintable(QSystemError::windowsComString(hr)));
7083 if (useFrameLatencyWaitableObject) {
7084 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
7085 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
7088 hr = dcompVisual->SetContent(swapChain);
7089 if (SUCCEEDED(hr)) {
7090 hr = dcompTarget->SetRoot(dcompVisual);
7092 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
7093 qPrintable(QSystemError::windowsComString(hr)));
7096 qWarning(
"Failed to set content for Direct Composition visual: %s",
7097 qPrintable(QSystemError::windowsComString(hr)));
7101 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
7104 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7105 qWarning(
"Device loss detected during swapchain creation");
7106 rhiD->deviceLost =
true;
7108 }
else if (FAILED(hr)) {
7109 qWarning(
"Failed to create D3D12 swapchain: %s"
7110 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
7111 qPrintable(QSystemError::windowsComString(hr)),
7112 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
7113 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
7117 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7118 hr = rhiD->dev->CreateFence(0,
7119 D3D12_FENCE_FLAG_NONE,
7120 __uuidof(ID3D12Fence),
7121 reinterpret_cast<
void **>(&frameRes[i].fence));
7123 qWarning(
"Failed to create fence for swapchain: %s",
7124 qPrintable(QSystemError::windowsComString(hr)));
7127 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
7129 frameRes[i].fenceCounter = 0;
7133 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
7134 UINT(pixelSize.width()),
7135 UINT(pixelSize.height()),
7138 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7139 qWarning(
"Device loss detected in ResizeBuffers()");
7140 rhiD->deviceLost =
true;
7142 }
else if (FAILED(hr)) {
7143 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
7148 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7149 ID3D12Resource *colorBuffer;
7150 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
7152 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
7153 i, qPrintable(QSystemError::windowsComString(hr)));
7156 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
7157 rtvs[i] = rhiD->rtvPool.allocate(1);
7158 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7159 rtvDesc.Format = srgbAdjustedColorFormat;
7160 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
7161 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
7164 rtvsRight[i] = rhiD->rtvPool.allocate(1);
7165 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7166 rtvDesc.Format = srgbAdjustedColorFormat;
7167 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
7168 rtvDesc.Texture2DArray.ArraySize = 1;
7169 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7170 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7174 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7175 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7176 m_depthStencil->sampleCount(), m_sampleCount);
7178 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7179 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7180 m_depthStencil->setPixelSize(pixelSize);
7181 if (!m_depthStencil->create())
7182 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7183 pixelSize.width(), pixelSize.height());
7185 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7186 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7187 pixelSize.width(), pixelSize.height());
7191 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7193 if (sampleDesc.Count > 1) {
7194 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7195 D3D12_RESOURCE_DESC resourceDesc = {};
7196 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7197 resourceDesc.Width = UINT64(pixelSize.width());
7198 resourceDesc.Height = UINT(pixelSize.height());
7199 resourceDesc.DepthOrArraySize = 1;
7200 resourceDesc.MipLevels = 1;
7201 resourceDesc.Format = srgbAdjustedColorFormat;
7202 resourceDesc.SampleDesc = sampleDesc;
7203 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7204 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7205 D3D12_CLEAR_VALUE clearValue = {};
7206 clearValue.Format = colorFormat;
7207 ID3D12Resource *resource =
nullptr;
7208 D3D12MA::Allocation *allocation =
nullptr;
7209 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7211 D3D12_RESOURCE_STATE_RENDER_TARGET,
7214 __uuidof(ID3D12Resource),
7215 reinterpret_cast<
void **>(&resource));
7217 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7220 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7221 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7222 if (!msaaRtvs[i].isValid())
7224 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7225 rtvDesc.Format = srgbAdjustedColorFormat;
7226 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7227 : D3D12_RTV_DIMENSION_TEXTURE2D;
7228 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7232 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7233 currentFrameSlot = 0;
7234 lastFrameLatencyWaitSlot = -1;
7236 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7237 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7238 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7239 rtD->d.pixelSize = pixelSize;
7240 rtD->d.dpr =
float(window->devicePixelRatio());
7241 rtD->d.sampleCount =
int(sampleDesc.Count);
7242 rtD->d.colorAttCount = 1;
7243 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7245 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7246 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7247 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7248 rtDr->d.pixelSize = pixelSize;
7249 rtDr->d.dpr =
float(window->devicePixelRatio());
7250 rtDr->d.sampleCount =
int(sampleDesc.Count);
7251 rtDr->d.colorAttCount = 1;
7252 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7254 QDxgiVSyncService::instance()->registerWindow(window);
7256 if (needsRegistration || !rhiD->swapchains.contains(
this))
7257 rhiD->swapchains.insert(
this);
7259 rhiD->registerResource(
this);