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;
925int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
928 case QRhi::TextureSizeMin:
930 case QRhi::TextureSizeMax:
932 case QRhi::MaxColorAttachments:
934 case QRhi::FramesInFlight:
935 return QD3D12_FRAMES_IN_FLIGHT;
936 case QRhi::MaxAsyncReadbackFrames:
937 return QD3D12_FRAMES_IN_FLIGHT;
938 case QRhi::MaxThreadGroupsPerDimension:
940 case QRhi::MaxThreadsPerThreadGroup:
942 case QRhi::MaxThreadGroupX:
944 case QRhi::MaxThreadGroupY:
946 case QRhi::MaxThreadGroupZ:
948 case QRhi::TextureArraySizeMax:
950 case QRhi::MaxUniformBufferRange:
952 case QRhi::MaxVertexInputs:
954 case QRhi::MaxVertexOutputs:
956 case QRhi::ShadingRateImageTileSize:
957 return shadingRateImageTileSize;
962const QRhiNativeHandles *QRhiD3D12::nativeHandles()
964 return &nativeHandlesStruct;
967QRhiDriverInfo QRhiD3D12::driverInfo()
const
969 return driverInfoStruct;
972QRhiStats QRhiD3D12::statistics()
975 result.totalPipelineCreationTime = totalPipelineCreationTime();
977 D3D12MA::Budget budgets[2];
978 vma.getBudget(&budgets[0], &budgets[1]);
979 for (
int i = 0; i < 2; ++i) {
980 const D3D12MA::Statistics &stats(budgets[i].Stats);
981 result.blockCount += stats.BlockCount;
982 result.allocCount += stats.AllocationCount;
983 result.usedBytes += stats.AllocationBytes;
984 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
985 result.totalUsageBytes += budgets[i].UsageBytes;
991bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
997void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1002void QRhiD3D12::releaseCachedResources()
1004 shaderBytecodeCache.data.clear();
1007bool QRhiD3D12::isDeviceLost()
const
1012QByteArray QRhiD3D12::pipelineCacheData()
1017void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1022QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1023 int sampleCount, QRhiRenderBuffer::Flags flags,
1024 QRhiTexture::Format backingFormatHint)
1026 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1029QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1030 const QSize &pixelSize,
int depth,
int arraySize,
1031 int sampleCount, QRhiTexture::Flags flags)
1033 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1036QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1037 QRhiSampler::Filter mipmapMode,
1038 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1040 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1043QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1044 QRhiTextureRenderTarget::Flags flags)
1046 return new QD3D12TextureRenderTarget(
this, desc, flags);
1049QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1051 return new QD3D12ShadingRateMap(
this);
1054QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1056 return new QD3D12GraphicsPipeline(
this);
1059QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1061 return new QD3D12ComputePipeline(
this);
1064QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1066 return new QD3D12ShaderResourceBindings(
this);
1069void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1071 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1072 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1073 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1074 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1076 if (pipelineChanged) {
1077 cbD->currentGraphicsPipeline = psD;
1078 cbD->currentComputePipeline =
nullptr;
1079 cbD->currentPipelineGeneration = psD->generation;
1081 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1082 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1083 cbD->cmdList->SetPipelineState(pipeline->pso);
1084 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1085 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1088 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1090 if (psD->viewInstanceMask)
1091 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1093 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1094 setDefaultScissor(cbD);
1098void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
1099 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1102 int dynamicOffsetCount,
1103 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1105 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1106 quint32 offset = d.offset;
1107 if (d.hasDynamicOffset) {
1108 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1109 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1110 if (dynOfs.first == binding) {
1111 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1112 offset += dynOfs.second;
1116 QRHI_RES_RHI(QRhiD3D12);
1117 visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
1120void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
1121 const QRhiShaderResourceBinding::TextureAndSampler &d,
1124 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1125 visitorData.srvs[s].append(texD->srv);
1128void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
1129 const QRhiShaderResourceBinding::TextureAndSampler &d,
1132 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
1133 visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
1136void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
1137 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1138 QD3D12ShaderResourceVisitor::StorageOp,
1141 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1143 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1144 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1145 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1146 uavDesc.Buffer.FirstElement = d.offset / 4;
1147 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1148 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1149 visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
1152void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
1153 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1154 QD3D12ShaderResourceVisitor::StorageOp,
1157 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1158 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1159 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1160 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1161 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1162 uavDesc.Format = texD->rtFormat;
1164 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1165 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1166 uavDesc.Texture2DArray.FirstArraySlice = 0;
1167 uavDesc.Texture2DArray.ArraySize = 6;
1168 }
else if (isArray) {
1169 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1170 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1171 uavDesc.Texture2DArray.FirstArraySlice = 0;
1172 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1174 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1175 uavDesc.Texture3D.MipSlice = UINT(d.level);
1176 uavDesc.Texture3D.WSize = UINT(-1);
1178 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1179 uavDesc.Texture2D.MipSlice = UINT(d.level);
1181 visitorData.uavs[s].append({ texD->handle, uavDesc });
1184void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1185 int dynamicOffsetCount,
1186 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1188 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1189 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1190 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1191 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1195 srb = gfxPsD->m_shaderResourceBindings;
1197 srb = compPsD->m_shaderResourceBindings;
1200 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1202 bool pipelineChanged =
false;
1204 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD;
1205 srbD->lastUsedGraphicsPipeline = gfxPsD;
1207 pipelineChanged = srbD->lastUsedComputePipeline != compPsD;
1208 srbD->lastUsedComputePipeline = compPsD;
1211 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1212 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1214 case QRhiShaderResourceBinding::UniformBuffer:
1216 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1217 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1218 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1219 sanityCheckResourceOwnership(bufD);
1220 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1223 case QRhiShaderResourceBinding::SampledTexture:
1224 case QRhiShaderResourceBinding::Texture:
1225 case QRhiShaderResourceBinding::Sampler:
1227 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1228 for (
int elem = 0; elem < data->count; ++elem) {
1229 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1230 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1234 Q_ASSERT(texD || samplerD);
1235 sanityCheckResourceOwnership(texD);
1236 sanityCheckResourceOwnership(samplerD);
1239 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1240 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1241 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1242 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1244 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1246 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1247 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1252 case QRhiShaderResourceBinding::ImageLoad:
1253 case QRhiShaderResourceBinding::ImageStore:
1254 case QRhiShaderResourceBinding::ImageLoadStore:
1256 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1257 sanityCheckResourceOwnership(texD);
1258 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1259 if (res->uavUsage) {
1260 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1262 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1264 if (b->type == QRhiShaderResourceBinding::ImageStore
1265 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1268 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1273 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1274 res->uavUsage |= QD3D12Resource::UavUsageRead;
1275 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1276 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1277 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1278 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1282 case QRhiShaderResourceBinding::BufferLoad:
1283 case QRhiShaderResourceBinding::BufferStore:
1284 case QRhiShaderResourceBinding::BufferLoadStore:
1286 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1287 sanityCheckResourceOwnership(bufD);
1288 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1289 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1290 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1291 if (res->uavUsage) {
1292 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1294 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1296 if (b->type == QRhiShaderResourceBinding::BufferStore
1297 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1300 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1305 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1306 res->uavUsage |= QD3D12Resource::UavUsageRead;
1307 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1308 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1309 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1310 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1317 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1318 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1320 if (pipelineChanged || srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1321 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1327 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1329 QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
1332 using namespace std::placeholders;
1333 visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1334 visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
1335 visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
1336 visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
1337 visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
1341 quint32 cbvSrvUavCount = 0;
1342 for (
int s = 0; s < 6; ++s) {
1344 cbvSrvUavCount += visitorData.srvs[s].count();
1345 cbvSrvUavCount += visitorData.uavs[s].count();
1348 bool gotNewHeap =
false;
1349 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1350 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1358 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1359 " per-frame slice size is now %u,"
1360 " if this happens frequently then that's not great.",
1361 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1362 bindShaderVisibleHeaps(cbD);
1365 int rootParamIndex = 0;
1366 for (
int s = 0; s < 6; ++s) {
1367 if (!visitorData.cbufs[s].isEmpty()) {
1368 for (
int i = 0, count = visitorData.cbufs[s].count(); i < count; ++i) {
1369 const auto &cbuf(visitorData.cbufs[s][i]);
1370 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.first)) {
1371 quint32 offset = cbuf.second;
1372 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1373 if (cbD->currentGraphicsPipeline)
1374 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1376 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1378 rootParamIndex += 1;
1382 for (
int s = 0; s < 6; ++s) {
1383 if (!visitorData.srvs[s].isEmpty()) {
1384 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1385 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[s].count());
1386 for (
int i = 0, count = visitorData.srvs[s].count(); i < count; ++i) {
1387 const auto &srv(visitorData.srvs[s][i]);
1388 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc, i).cpuHandle, srv.cpuHandle,
1389 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1392 if (cbD->currentGraphicsPipeline)
1393 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1394 else if (cbD->currentComputePipeline)
1395 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1397 rootParamIndex += 1;
1400 for (
int s = 0; s < 6; ++s) {
1403 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.samplers[s]) {
1404 if (cbD->currentGraphicsPipeline)
1405 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1406 else if (cbD->currentComputePipeline)
1407 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1409 rootParamIndex += 1;
1412 for (
int s = 0; s < 6; ++s) {
1413 if (!visitorData.uavs[s].isEmpty()) {
1414 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1415 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[s].count());
1416 for (
int i = 0, count = visitorData.uavs[s].count(); i < count; ++i) {
1417 const auto &uav(visitorData.uavs[s][i]);
1418 if (QD3D12Resource *res = resourcePool.lookupRef(uav.first)) {
1419 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.second,
1420 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1422 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1423 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1427 if (cbD->currentGraphicsPipeline)
1428 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1429 else if (cbD->currentComputePipeline)
1430 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1432 rootParamIndex += 1;
1437 cbD->currentGraphicsSrb = srb;
1438 cbD->currentComputeSrb =
nullptr;
1440 cbD->currentGraphicsSrb =
nullptr;
1441 cbD->currentComputeSrb = srb;
1443 cbD->currentSrbGeneration = srbD->generation;
1447void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1448 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1449 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1451 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1452 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1454 bool needsBindVBuf =
false;
1455 for (
int i = 0; i < bindingCount; ++i) {
1456 const int inputSlot = startBinding + i;
1457 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1458 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1459 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1461 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1463 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1464 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1466 needsBindVBuf =
true;
1467 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1468 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1472 if (needsBindVBuf) {
1473 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1474 vbv.reserve(bindingCount);
1476 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1477 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1478 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1480 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1481 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1482 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1483 const quint32 offset = bindings[i].second;
1484 const quint32 stride = inputLayout.bindingAt(i)->stride();
1486 if (bufD->m_type != QRhiBuffer::Dynamic) {
1487 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1488 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1491 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1493 res->resource->GetGPUVirtualAddress() + offset,
1494 UINT(res->desc.Width - offset),
1500 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1504 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1505 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1506 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1508 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1510 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1511 : DXGI_FORMAT_R32_UINT;
1512 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1513 || cbD->currentIndexOffset != indexOffset
1514 || cbD->currentIndexFormat != dxgiFormat)
1516 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1517 cbD->currentIndexOffset = indexOffset;
1518 cbD->currentIndexFormat = dxgiFormat;
1520 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1521 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1522 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1525 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1526 const D3D12_INDEX_BUFFER_VIEW ibv = {
1527 res->resource->GetGPUVirtualAddress() + indexOffset,
1528 UINT(res->desc.Width - indexOffset),
1531 cbD->cmdList->IASetIndexBuffer(&ibv);
1537void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1539 cbD->hasCustomScissorSet =
false;
1541 const QSize outputSize = cbD->currentTarget->pixelSize();
1542 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1543 float x = 0, y = 0, w = 0, h = 0;
1545 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1548 w = outputSize.width();
1549 h = outputSize.height();
1552 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1561 cbD->cmdList->RSSetScissorRects(1, &r);
1564void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1566 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1567 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1568 Q_ASSERT(cbD->currentTarget);
1569 const QSize outputSize = cbD->currentTarget->pixelSize();
1573 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1581 v.MinDepth = viewport.minDepth();
1582 v.MaxDepth = viewport.maxDepth();
1583 cbD->cmdList->RSSetViewports(1, &v);
1585 cbD->currentViewport = viewport;
1586 if (cbD->currentGraphicsPipeline
1587 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1589 setDefaultScissor(cbD);
1593void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1595 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1596 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1597 Q_ASSERT(cbD->currentTarget);
1598 const QSize outputSize = cbD->currentTarget->pixelSize();
1602 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1611 cbD->cmdList->RSSetScissorRects(1, &r);
1613 cbD->hasCustomScissorSet =
true;
1616void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1618 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1619 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1620 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1621 cbD->cmdList->OMSetBlendFactor(v);
1624void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1626 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1627 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1628 cbD->cmdList->OMSetStencilRef(refValue);
1631static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1633 if (coarsePixelSize == QSize(1, 2))
1634 return D3D12_SHADING_RATE_1X2;
1635 if (coarsePixelSize == QSize(2, 1))
1636 return D3D12_SHADING_RATE_2X1;
1637 if (coarsePixelSize == QSize(2, 2))
1638 return D3D12_SHADING_RATE_2X2;
1639 if (coarsePixelSize == QSize(2, 4))
1640 return D3D12_SHADING_RATE_2X4;
1641 if (coarsePixelSize == QSize(4, 2))
1642 return D3D12_SHADING_RATE_4X2;
1643 if (coarsePixelSize == QSize(4, 4))
1644 return D3D12_SHADING_RATE_4X4;
1645 return D3D12_SHADING_RATE_1X1;
1648void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
1650 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1651 cbD->hasShadingRateSet =
false;
1653#ifdef QRHI_D3D12_CL5_AVAILABLE
1657 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1658 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
1659 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
1660 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
1661 cbD->hasShadingRateSet =
true;
1664 Q_UNUSED(coarsePixelSize);
1665 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
1669void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1670 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1672 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1673 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1674 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
1677void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1678 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1680 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1681 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1682 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
1683 firstIndex, vertexOffset,
1687void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
1688 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
1690 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1691 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1693 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
1694 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
1695 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
1697 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
1699 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
1700 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1702 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
1705 ID3D12Resource *indirectBufferRes = indirectRes->resource;
1707 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
1709 if (canUseMulti && drawCount > 1) {
1710 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
1711 indirectBufferRes, indirectBufferOffset,
1714 UINT offset = indirectBufferOffset;
1715 for (quint32 i = 0; i < drawCount; ++i) {
1716 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
1717 indirectBufferRes, offset,
1724void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
1725 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
1727 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1728 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1730 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
1731 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
1732 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
1734 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
1736 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
1737 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1739 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
1742 ID3D12Resource *indirectBufferRes = indirectRes->resource;
1744 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
1746 if (canUseMulti && drawCount > 1) {
1747 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
1748 indirectBufferRes, indirectBufferOffset,
1751 UINT offset = indirectBufferOffset;
1752 for (quint32 i = 0; i < drawCount; ++i) {
1753 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
1754 indirectBufferRes, offset,
1761void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
1766 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1767#ifdef QRHI_D3D12_HAS_OLD_PIX
1768 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
1775void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
1780 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1781#ifdef QRHI_D3D12_HAS_OLD_PIX
1782 PIXEndEvent(cbD->cmdList);
1788void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
1793 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1794#ifdef QRHI_D3D12_HAS_OLD_PIX
1795 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
1802const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
1804 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
1807void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
1812void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
1814 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1815 cbD->resetPerPassState();
1816 bindShaderVisibleHeaps(cbD);
1817 if (cbD->currentTarget) {
1818 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
1819 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1822 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1826double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
1828 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1829 return cbD->lastGpuTime;
1832static void calculateGpuTime(QD3D12CommandBuffer *cbD,
1833 int timestampPairStartIndex,
1834 const quint8 *readbackBufPtr,
1835 quint64 timestampTicksPerSecond)
1837 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
1838 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
1839 const quint64 startTime = *p++;
1840 const quint64 endTime = *p;
1841 if (startTime < endTime) {
1842 const quint64 ticks = endTime - startTime;
1843 const double timeSec = ticks /
double(timestampTicksPerSecond);
1844 cbD->lastGpuTime = timeSec;
1848QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
1852 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1853 currentSwapChain = swapChainD;
1854 currentFrameSlot = swapChainD->currentFrameSlot;
1855 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1868 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1869 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1871 if (swapChainD->frameLatencyWaitableObject) {
1873 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
1874 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
1875 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
1879 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1881 qWarning(
"Failed to reset command allocator: %s",
1882 qPrintable(QSystemError::windowsComString(hr)));
1883 return QRhi::FrameOpError;
1886 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1887 return QRhi::FrameOpError;
1889 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1890 cbD->cmdList = fr.cmdList;
1892 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1893 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1894 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1896 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1897 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1899 if (swapChainD->stereo) {
1900 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1901 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1902 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
1904 swapChainD->rtWrapperRight.d.dsv =
1905 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
1912 releaseQueue.executeDeferredReleases(currentFrameSlot);
1918 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1920 smallStagingAreas[currentFrameSlot].head = 0;
1922 bindShaderVisibleHeaps(cbD);
1924 finishActiveReadbacks();
1926 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1929 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1930 calculateGpuTime(cbD,
1931 timestampPairStartIndex,
1932 timestampReadbackArea.mem.p,
1933 timestampTicksPerSecond);
1935 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1936 D3D12_QUERY_TYPE_TIMESTAMP,
1937 timestampPairStartIndex);
1940 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
1942 return QRhi::FrameOpSuccess;
1945QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
1947 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1948 Q_ASSERT(currentSwapChain == swapChainD);
1949 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1951 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1952 if (swapChainD->sampleDesc.Count > 1) {
1953 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1954 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1955 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1956 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1957 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1958 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
1960 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
1963 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1964 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1966 if (timestampQueryHeap.isValid()) {
1967 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1968 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1969 D3D12_QUERY_TYPE_TIMESTAMP,
1970 timestampPairStartIndex + 1);
1971 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1972 D3D12_QUERY_TYPE_TIMESTAMP,
1973 timestampPairStartIndex,
1975 timestampReadbackArea.mem.buffer,
1976 timestampPairStartIndex *
sizeof(quint64));
1979 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1980 HRESULT hr = cmdList->Close();
1982 qWarning(
"Failed to close command list: %s",
1983 qPrintable(QSystemError::windowsComString(hr)));
1984 return QRhi::FrameOpError;
1987 ID3D12CommandList *execList[] = { cmdList };
1988 cmdQueue->ExecuteCommandLists(1, execList);
1990 if (!flags.testFlag(QRhi::SkipPresent)) {
1991 UINT presentFlags = 0;
1992 if (swapChainD->swapInterval == 0
1993 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1995 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1997 if (!swapChainD->swapChain) {
1998 qWarning(
"Failed to present, no swapchain");
1999 return QRhi::FrameOpError;
2001 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2002 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2003 qWarning(
"Device loss detected in Present()");
2005 return QRhi::FrameOpDeviceLost;
2006 }
else if (FAILED(hr)) {
2007 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2008 return QRhi::FrameOpError;
2011 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2012 dcompDevice->Commit();
2015 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2022 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2024 if (!flags.testFlag(QRhi::SkipPresent)) {
2028 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2029 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2032 currentSwapChain =
nullptr;
2033 return QRhi::FrameOpSuccess;
2036QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2049 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2051 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2052 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2054 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2056 qWarning(
"Failed to reset command allocator: %s",
2057 qPrintable(QSystemError::windowsComString(hr)));
2058 return QRhi::FrameOpError;
2061 if (!offscreenCb[currentFrameSlot])
2062 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2063 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2064 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2065 return QRhi::FrameOpError;
2067 releaseQueue.executeDeferredReleases(currentFrameSlot);
2069 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2070 smallStagingAreas[currentFrameSlot].head = 0;
2072 bindShaderVisibleHeaps(cbD);
2074 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2075 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2076 D3D12_QUERY_TYPE_TIMESTAMP,
2077 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2080 offscreenActive =
true;
2083 return QRhi::FrameOpSuccess;
2086QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2089 Q_ASSERT(offscreenActive);
2090 offscreenActive =
false;
2092 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2093 if (timestampQueryHeap.isValid()) {
2094 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2095 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2096 D3D12_QUERY_TYPE_TIMESTAMP,
2097 timestampPairStartIndex + 1);
2098 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2099 D3D12_QUERY_TYPE_TIMESTAMP,
2100 timestampPairStartIndex,
2102 timestampReadbackArea.mem.buffer,
2103 timestampPairStartIndex *
sizeof(quint64));
2106 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2107 HRESULT hr = cmdList->Close();
2109 qWarning(
"Failed to close command list: %s",
2110 qPrintable(QSystemError::windowsComString(hr)));
2111 return QRhi::FrameOpError;
2114 ID3D12CommandList *execList[] = { cmdList };
2115 cmdQueue->ExecuteCommandLists(1, execList);
2117 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2124 finishActiveReadbacks(
true);
2127 if (timestampQueryHeap.isValid()) {
2128 calculateGpuTime(cbD,
2129 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2130 timestampReadbackArea.mem.p,
2131 timestampTicksPerSecond);
2134 return QRhi::FrameOpSuccess;
2137QRhi::FrameOpResult QRhiD3D12::finish()
2139 QD3D12CommandBuffer *cbD =
nullptr;
2141 if (offscreenActive) {
2142 Q_ASSERT(!currentSwapChain);
2143 cbD = offscreenCb[currentFrameSlot];
2145 Q_ASSERT(currentSwapChain);
2146 cbD = ¤tSwapChain->cbWrapper;
2149 return QRhi::FrameOpError;
2151 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2153 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2154 HRESULT hr = cmdList->Close();
2156 qWarning(
"Failed to close command list: %s",
2157 qPrintable(QSystemError::windowsComString(hr)));
2158 return QRhi::FrameOpError;
2161 ID3D12CommandList *execList[] = { cmdList };
2162 cmdQueue->ExecuteCommandLists(1, execList);
2164 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2171 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2173 qWarning(
"Failed to reset command allocator: %s",
2174 qPrintable(QSystemError::windowsComString(hr)));
2175 return QRhi::FrameOpError;
2178 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2179 return QRhi::FrameOpError;
2183 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2184 smallStagingAreas[currentFrameSlot].head = 0;
2186 bindShaderVisibleHeaps(cbD);
2189 releaseQueue.releaseAll();
2190 finishActiveReadbacks(
true);
2192 return QRhi::FrameOpSuccess;
2195void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2197 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2198 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2199 enqueueResourceUpdates(cbD, resourceUpdates);
2202void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2203 QRhiRenderTarget *rt,
2204 const QColor &colorClearValue,
2205 const QRhiDepthStencilClearValue &depthStencilClearValue,
2206 QRhiResourceUpdateBatch *resourceUpdates,
2207 QRhiCommandBuffer::BeginPassFlags)
2209 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2210 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2212 if (resourceUpdates)
2213 enqueueResourceUpdates(cbD, resourceUpdates);
2215 QD3D12RenderTargetData *rtD = rtData(rt);
2216 bool wantsColorClear =
true;
2217 bool wantsDsClear =
true;
2218 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2219 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2220 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2221 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2222 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2225 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2226 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2227 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2228 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2230 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2232 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2234 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2236 if (rtTex->m_desc.depthStencilBuffer()) {
2237 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2238 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2239 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2240 }
else if (rtTex->m_desc.depthTexture()) {
2241 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2242 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2244 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2246 Q_ASSERT(currentSwapChain);
2247 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2248 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
2249 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2250 D3D12_RESOURCE_STATE_RENDER_TARGET);
2251 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2254 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2257 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2259 if (rtD->colorAttCount && wantsColorClear) {
2260 float clearColor[4] = {
2261 colorClearValue.redF(),
2262 colorClearValue.greenF(),
2263 colorClearValue.blueF(),
2264 colorClearValue.alphaF()
2266 for (
int i = 0; i < rtD->colorAttCount; ++i)
2267 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2269 if (rtD->dsAttCount && wantsDsClear) {
2270 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2271 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2272 depthStencilClearValue.depthClearValue(),
2273 UINT8(depthStencilClearValue.stencilClearValue()),
2278 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2279 cbD->currentTarget = rt;
2281 bool hasShadingRateMapSet =
false;
2282#ifdef QRHI_D3D12_CL5_AVAILABLE
2283 if (rtD->rp->hasShadingRateMap) {
2284 cbD->setShadingRate(QSize(1, 1));
2285 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2286 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2287 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2288 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2289 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2290 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2291 cbD->cmdList->RSSetShadingRateImage(res->resource);
2292 hasShadingRateMapSet =
true;
2294 }
else if (cbD->hasShadingRateMapSet) {
2295 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2296 cbD->setShadingRate(QSize(1, 1));
2297 }
else if (cbD->hasShadingRateSet) {
2298 cbD->setShadingRate(QSize(1, 1));
2302 cbD->resetPerPassState();
2305 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2308void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2310 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2311 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2313 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2314 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2315 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2318 const QRhiColorAttachment &colorAtt(*it);
2319 if (!colorAtt.resolveTexture())
2322 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2323 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2327 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2328 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2329 Q_ASSERT(srcTexD || srcRbD);
2330 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2335 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2336 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2337 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2340 if (srcTexD->sampleDesc.Count <= 1) {
2341 qWarning(
"Cannot resolve a non-multisample texture");
2344 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2345 qWarning(
"Resolve source and destination sizes do not match");
2349 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2350 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2351 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2354 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2355 qWarning(
"Resolve source and destination sizes do not match");
2360 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2361 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2362 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2364 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2365 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2366 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2367 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2368 UINT(colorAtt.resolveLayer()) + resolveIdx,
2369 dstTexD->mipLevelCount);
2370 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
2371 srcRes->resource, srcSubresource,
2372 dstTexD->dxgiFormat);
2375 if (rtTex->m_desc.depthResolveTexture())
2376 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2379 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2380 cbD->currentTarget =
nullptr;
2382 if (resourceUpdates)
2383 enqueueResourceUpdates(cbD, resourceUpdates);
2386void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2387 QRhiResourceUpdateBatch *resourceUpdates,
2388 QRhiCommandBuffer::BeginPassFlags)
2390 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2391 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2393 if (resourceUpdates)
2394 enqueueResourceUpdates(cbD, resourceUpdates);
2396 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2398 cbD->resetPerPassState();
2401void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2403 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2404 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2406 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2408 if (resourceUpdates)
2409 enqueueResourceUpdates(cbD, resourceUpdates);
2412void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2414 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2415 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2416 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2417 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2419 if (pipelineChanged) {
2420 cbD->currentGraphicsPipeline =
nullptr;
2421 cbD->currentComputePipeline = psD;
2422 cbD->currentPipelineGeneration = psD->generation;
2424 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2425 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2426 cbD->cmdList->SetPipelineState(pipeline->pso);
2427 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2428 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2433void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2435 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2436 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2437 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2440bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2441 quint32 descriptorCount,
2442 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2443 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2446 capacity = descriptorCount;
2447 this->heapType = heapType;
2448 this->heapFlags = heapFlags;
2450 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2451 heapDesc.Type = heapType;
2452 heapDesc.NumDescriptors = capacity;
2453 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2455 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2457 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2459 capacity = descriptorByteSize = 0;
2463 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2464 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2465 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2466 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2471void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2472 quint32 offsetInDescriptors,
2473 quint32 descriptorCount)
2477 capacity = descriptorCount;
2478 heapType = other.heapType;
2479 heapFlags = other.heapFlags;
2480 descriptorByteSize = other.descriptorByteSize;
2481 heapStart = incremented(other.heapStart, offsetInDescriptors);
2484void QD3D12DescriptorHeap::destroy()
2493void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2496 releaseQueue->deferredReleaseDescriptorHeap(heap);
2502QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2504 Q_ASSERT(count > 0);
2505 if (head + count > capacity) {
2506 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2510 return at(head - count);
2513QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2515 const quint32 startOffset = index * descriptorByteSize;
2516 QD3D12Descriptor result;
2517 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2518 if (heapStart.gpuHandle.ptr != 0)
2519 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2523bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2525 QD3D12DescriptorHeap firstHeap;
2526 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2528 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2529 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2530 this->device = device;
2531 this->debugName = debugName;
2535void QD3D12CpuDescriptorPool::destroy()
2539 static bool leakCheck =
true;
2542 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2545 for (HeapWithMap &heap : heaps) {
2546 const int leakedDescriptorCount = heap.map.count(
true);
2547 if (leakedDescriptorCount > 0) {
2548 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2549 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2550 &heap.heap,
this, debugName, leakedDescriptorCount);
2554 for (HeapWithMap &heap : heaps)
2555 heap.heap.destroy();
2559QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2561 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2563 HeapWithMap &last(heaps.last());
2564 if (last.heap.head + count <= last.heap.capacity) {
2565 quint32 firstIndex = last.heap.head;
2566 for (quint32 i = 0; i < count; ++i)
2567 last.map.setBit(firstIndex + i);
2568 return last.heap.get(count);
2571 for (HeapWithMap &heap : heaps) {
2572 quint32 freeCount = 0;
2573 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2574 if (heap.map.testBit(i)) {
2578 if (freeCount == count) {
2579 quint32 firstIndex = i - (freeCount - 1);
2580 for (quint32 j = 0; j < count; ++j) {
2581 heap.map.setBit(firstIndex + j);
2582 return heap.heap.at(firstIndex);
2589 QD3D12DescriptorHeap newHeap;
2590 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2593 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2595 for (quint32 i = 0; i < count; ++i)
2596 heaps.last().map.setBit(i);
2598 return heaps.last().heap.get(count);
2601void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
2603 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2604 if (!descriptor.isValid())
2607 const SIZE_T addr = descriptor.cpuHandle.ptr;
2608 for (HeapWithMap &heap : heaps) {
2609 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
2610 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2611 if (addr >= begin && addr < end) {
2612 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
2613 for (quint32 i = 0; i < count; ++i)
2614 heap.map.setBit(firstIndex + i,
false);
2619 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2620 quint64(descriptor.cpuHandle.ptr));
2623bool QD3D12QueryHeap::create(ID3D12Device *device,
2625 D3D12_QUERY_HEAP_TYPE heapType)
2627 capacity = queryCount;
2629 D3D12_QUERY_HEAP_DESC heapDesc = {};
2630 heapDesc.Type = heapType;
2631 heapDesc.Count = capacity;
2633 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
2635 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2644void QD3D12QueryHeap::destroy()
2653bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
2655 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2656 D3D12_RESOURCE_DESC resourceDesc = {};
2657 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2658 resourceDesc.Width = capacity;
2659 resourceDesc.Height = 1;
2660 resourceDesc.DepthOrArraySize = 1;
2661 resourceDesc.MipLevels = 1;
2662 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2663 resourceDesc.SampleDesc = { 1, 0 };
2664 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2665 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2666 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2667 HRESULT hr = rhi->vma.createResource(heapType,
2669 D3D12_RESOURCE_STATES(state),
2672 __uuidof(ID3D12Resource),
2673 reinterpret_cast<
void **>(&resource));
2675 qWarning(
"Failed to create buffer for staging area: %s",
2676 qPrintable(QSystemError::windowsComString(hr)));
2680 hr = resource->Map(0,
nullptr, &p);
2682 qWarning(
"Failed to map buffer for staging area: %s",
2683 qPrintable(QSystemError::windowsComString(hr)));
2688 mem.p =
static_cast<quint8 *>(p);
2689 mem.gpuAddr = resource->GetGPUVirtualAddress();
2690 mem.buffer = resource;
2691 mem.bufferOffset = 0;
2693 this->capacity = capacity;
2699void QD3D12StagingArea::destroy()
2702 resource->Release();
2706 allocation->Release();
2707 allocation =
nullptr;
2712void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2715 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
2719QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
2721 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
2722 if (head + allocSize > capacity) {
2723 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2724 allocSize, byteSize, capacity, remainingCapacity());
2727 const quint32 offset = head;
2731 mem.gpuAddr + offset,
2740void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
2742 DeferredReleaseEntry e;
2747void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
2748 QD3D12CpuDescriptorPool *pool,
2749 const QD3D12Descriptor &viewsStart,
2752 DeferredReleaseEntry e;
2753 e.type = DeferredReleaseEntry::Resource;
2755 e.poolForViews = pool;
2756 e.viewsStart = viewsStart;
2757 e.viewCount = viewCount;
2761void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
2763 DeferredReleaseEntry e;
2764 e.type = DeferredReleaseEntry::Pipeline;
2769void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
2771 DeferredReleaseEntry e;
2772 e.type = DeferredReleaseEntry::RootSignature;
2777void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2779 DeferredReleaseEntry e;
2780 e.type = DeferredReleaseEntry::Callback;
2781 e.callback = callback;
2782 e.callbackUserData = userData;
2786void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2787 D3D12MA::Allocation *allocation)
2789 DeferredReleaseEntry e;
2790 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2791 e.resourceAndAllocation = { resource, allocation };
2795void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2797 DeferredReleaseEntry e;
2798 e.type = DeferredReleaseEntry::DescriptorHeap;
2799 e.descriptorHeap = heap;
2803void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
2804 const QD3D12Descriptor &viewsStart,
2807 DeferredReleaseEntry e;
2808 e.type = DeferredReleaseEntry::Views;
2809 e.poolForViews = pool;
2810 e.viewsStart = viewsStart;
2811 e.viewCount = viewCount;
2815void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2817 for (DeferredReleaseEntry &e : queue) {
2818 if (!e.frameSlotToBeReleasedIn.has_value())
2819 e.frameSlotToBeReleasedIn = frameSlot;
2823void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2825 for (
int i = queue.count() - 1; i >= 0; --i) {
2826 const DeferredReleaseEntry &e(queue[i]);
2827 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2829 case DeferredReleaseEntry::Resource:
2830 resourcePool->remove(e.handle);
2831 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
2832 e.poolForViews->release(e.viewsStart, e.viewCount);
2834 case DeferredReleaseEntry::Pipeline:
2835 pipelinePool->remove(e.handle);
2837 case DeferredReleaseEntry::RootSignature:
2838 rootSignaturePool->remove(e.handle);
2840 case DeferredReleaseEntry::Callback:
2841 e.callback(e.callbackUserData);
2843 case DeferredReleaseEntry::ResourceAndAllocation:
2846 e.resourceAndAllocation.first->Release();
2847 if (e.resourceAndAllocation.second)
2848 e.resourceAndAllocation.second->Release();
2850 case DeferredReleaseEntry::DescriptorHeap:
2851 e.descriptorHeap->Release();
2853 case DeferredReleaseEntry::Views:
2854 e.poolForViews->release(e.viewsStart, e.viewCount);
2862void QD3D12ReleaseQueue::releaseAll()
2864 executeDeferredReleases(0,
true);
2867void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2868 D3D12_RESOURCE_STATES stateAfter)
2870 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2871 if (stateAfter != res->state) {
2872 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
2873 res->state = stateAfter;
2878void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2880 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
2881 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2882 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
2883 D3D12_RESOURCE_BARRIER barrier = {};
2884 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2885 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2886 barrier.Transition.pResource = res->resource;
2887 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2888 barrier.Transition.StateBefore = trb.stateBefore;
2889 barrier.Transition.StateAfter = trb.stateAfter;
2890 barriers.append(barrier);
2893 transitionResourceBarriers.clear();
2894 if (!barriers.isEmpty())
2895 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
2898void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2899 const QD3D12ObjectHandle &resourceHandle,
2901 D3D12_RESOURCE_STATES stateBefore,
2902 D3D12_RESOURCE_STATES stateAfter)
2904 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2905 D3D12_RESOURCE_BARRIER barrier = {};
2906 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2907 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2908 barrier.Transition.pResource = res->resource;
2909 barrier.Transition.Subresource = subresource;
2910 barrier.Transition.StateBefore = stateBefore;
2911 barrier.Transition.StateAfter = stateAfter;
2912 cbD->cmdList->ResourceBarrier(1, &barrier);
2916void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2917 const QD3D12ObjectHandle &resourceHandle)
2919 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2920 D3D12_RESOURCE_BARRIER barrier = {};
2921 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2922 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2923 barrier.UAV.pResource = res->resource;
2924 cbD->cmdList->ResourceBarrier(1, &barrier);
2928void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
2930 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2932 data.insert(key, s);
2935bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
2936 D3D12_DESCRIPTOR_HEAP_TYPE type,
2937 quint32 perFrameDescriptorCount)
2939 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2941 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2944 const quint32 CBV_SRV_UAV_MAX = 1000000;
2945 const quint32 SAMPLER_MAX = 2048;
2946 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2947 size = qMin(size, CBV_SRV_UAV_MAX);
2948 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2949 size = qMin(size, SAMPLER_MAX);
2951 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2952 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
2956 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
2957 quint32 currentOffsetInDescriptors = 0;
2958 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
2959 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2960 currentOffsetInDescriptors += perFrameDescriptorCount;
2966void QD3D12ShaderVisibleDescriptorHeap::destroy()
2971void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2973 heap.destroyWithDeferredRelease(releaseQueue);
2976static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
2979 return { binding, binding };
2981 auto it = map.constFind(binding);
2982 if (it != map.cend())
2991void QD3D12ShaderResourceVisitor::visit()
2993 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2994 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
2995 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
2997 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
2998 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3002 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3006 case QRhiShaderResourceBinding::UniformBuffer:
3008 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3009 if (shaderRegister >= 0 && uniformBuffer)
3010 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3013 case QRhiShaderResourceBinding::SampledTexture:
3015 Q_ASSERT(bd->u.stex.count > 0);
3016 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3017 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
3018 for (
int i = 0; i < bd->u.stex.count; ++i) {
3019 if (textureBaseShaderRegister >= 0 && texture)
3020 texture(sd->stage, bd->u.stex.texSamplers[i], textureBaseShaderRegister + i);
3021 if (samplerBaseShaderRegister >= 0 && sampler)
3022 sampler(sd->stage, bd->u.stex.texSamplers[i], samplerBaseShaderRegister + i);
3026 case QRhiShaderResourceBinding::Texture:
3028 Q_ASSERT(bd->u.stex.count > 0);
3029 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3030 if (baseShaderRegister >= 0 && texture) {
3031 for (
int i = 0; i < bd->u.stex.count; ++i)
3032 texture(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
3036 case QRhiShaderResourceBinding::Sampler:
3038 Q_ASSERT(bd->u.stex.count > 0);
3039 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3040 if (baseShaderRegister >= 0 && sampler) {
3041 for (
int i = 0; i < bd->u.stex.count; ++i)
3042 sampler(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
3046 case QRhiShaderResourceBinding::ImageLoad:
3048 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3049 if (shaderRegister >= 0 && storageImage)
3050 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3053 case QRhiShaderResourceBinding::ImageStore:
3055 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3056 if (shaderRegister >= 0 && storageImage)
3057 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3060 case QRhiShaderResourceBinding::ImageLoadStore:
3062 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3063 if (shaderRegister >= 0 && storageImage)
3064 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3067 case QRhiShaderResourceBinding::BufferLoad:
3069 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3070 if (shaderRegister >= 0 && storageBuffer)
3071 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3074 case QRhiShaderResourceBinding::BufferStore:
3076 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3077 if (shaderRegister >= 0 && storageBuffer)
3078 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3081 case QRhiShaderResourceBinding::BufferLoadStore:
3083 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3084 if (shaderRegister >= 0 && storageBuffer)
3085 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3093bool QD3D12SamplerManager::create(ID3D12Device *device)
3096 if (!shaderVisibleSamplerHeap.create(device,
3097 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3098 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3100 qWarning(
"Could not create shader-visible SAMPLER heap");
3104 this->device = device;
3108void QD3D12SamplerManager::destroy()
3111 shaderVisibleSamplerHeap.destroy();
3116QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3118 auto it = gpuMap.constFind({desc});
3119 if (it != gpuMap.cend())
3122 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3123 if (descriptor.isValid()) {
3124 device->CreateSampler(&desc, descriptor.cpuHandle);
3125 gpuMap.insert({desc}, descriptor);
3127 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3128 " this should not happen, maximum number of unique samplers is %u",
3129 shaderVisibleSamplerHeap.heap.capacity);
3135bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3139 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3140 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3143 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3144 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3145 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3148 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3149 descriptorRanges[0].NumDescriptors = 1;
3150 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3151 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3152 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3153 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3154 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3157 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3158 descriptorRanges[1].NumDescriptors = 4;
3159 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3160 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3161 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3162 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3165 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3166 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3167 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3168 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3169 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3170 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3172 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3173 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3174 rsDesc.Desc_1_1.NumParameters = 3;
3175 rsDesc.Desc_1_1.pParameters = rootParams;
3176 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3177 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3179 ID3DBlob *signature =
nullptr;
3180 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3182 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3185 ID3D12RootSignature *rootSig =
nullptr;
3186 hr = rhiD->dev->CreateRootSignature(0,
3187 signature->GetBufferPointer(),
3188 signature->GetBufferSize(),
3189 __uuidof(ID3D12RootSignature),
3190 reinterpret_cast<
void **>(&rootSig));
3191 signature->Release();
3193 qWarning(
"Failed to create root signature: %s",
3194 qPrintable(QSystemError::windowsComString(hr)));
3198 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3200 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3201 psoDesc.pRootSignature = rootSig;
3202 psoDesc.CS.pShaderBytecode = g_csMipmap;
3203 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3204 ID3D12PipelineState *pso =
nullptr;
3205 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3206 __uuidof(ID3D12PipelineState),
3207 reinterpret_cast<
void **>(&pso));
3209 qWarning(
"Failed to create compute pipeline state: %s",
3210 qPrintable(QSystemError::windowsComString(hr)));
3211 rhiD->rootSignaturePool.remove(rootSigHandle);
3216 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3221void QD3D12MipmapGenerator::destroy()
3223 rhiD->pipelinePool.remove(pipelineHandle);
3224 pipelineHandle = {};
3225 rhiD->rootSignaturePool.remove(rootSigHandle);
3229void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3231 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3234 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3237 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3241 const quint32 mipLevelCount = res->desc.MipLevels;
3242 if (mipLevelCount < 2)
3245 if (res->desc.SampleDesc.Count > 1) {
3246 qWarning(
"Cannot generate mipmaps for MSAA texture");
3250 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3252 qWarning(
"Cannot generate mipmaps for 1D texture");
3256 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3257 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3258 && res->desc.DepthOrArraySize > 1;
3259 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3262 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3266 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3267 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3269 cbD->cmdList->SetPipelineState(pipeline->pso);
3270 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3272 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3275 quint32 srcMipLevel;
3276 quint32 numMipLevels;
3281 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3282 std::optional<QD3D12StagingArea> ownStagingArea;
3283 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3284 ownStagingArea = QD3D12StagingArea();
3285 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3286 qWarning(
"Could not create staging area for mipmap generation");
3290 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3291 ? &ownStagingArea.value()
3292 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3294 bool gotNewHeap =
false;
3295 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3296 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3297 rhiD->currentFrameSlot,
3298 (1 + 4) * mipLevelCount * layerCount,
3301 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3305 rhiD->bindShaderVisibleHeaps(cbD);
3307 for (quint32 layer = 0; layer < layerCount; ++layer) {
3308 for (quint32 level = 0; level < mipLevelCount ;) {
3309 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3310 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3311 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3312 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3314 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3315 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3316 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3317 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3319 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3320 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3321 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3322 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3324 CBufData cbufData = {
3327 1.0f /
float(levelPlusOneMipWidth),
3328 1.0f /
float(levelPlusOneMipHeight)
3331 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3332 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3333 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3335 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3336 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3337 srvDesc.Format = res->desc.Format;
3338 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3339 if (isCubeOrArray) {
3340 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3341 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3342 srvDesc.Texture2DArray.FirstArraySlice = layer;
3343 srvDesc.Texture2DArray.ArraySize = 1;
3345 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3346 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3348 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3349 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3351 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3352 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3354 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3355 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3356 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3357 uavDesc.Format = res->desc.Format;
3358 if (isCubeOrArray) {
3359 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3360 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3361 uavDesc.Texture2DArray.FirstArraySlice = layer;
3362 uavDesc.Texture2DArray.ArraySize = 1;
3364 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3365 uavDesc.Texture2D.MipSlice = uavMipLevel;
3367 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3368 uavCpuHandle.ptr += descriptorByteSize;
3370 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3372 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3374 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3375 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3376 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3377 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3379 level += numGenMips;
3383 if (ownStagingArea.has_value())
3384 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3387bool QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
3391 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3392 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3395 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3396 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3397 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3400 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3401 descriptorRanges[0].NumDescriptors = 1;
3402 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3403 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3404 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3405 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3406 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3409 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3410 descriptorRanges[1].NumDescriptors = 1;
3411 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3412 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3413 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3414 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3417 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3418 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3419 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3420 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3421 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3422 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3424 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3425 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3426 rsDesc.Desc_1_1.NumParameters = 3;
3427 rsDesc.Desc_1_1.pParameters = rootParams;
3428 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3429 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3431 ID3DBlob *signature =
nullptr;
3432 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3434 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3437 ID3D12RootSignature *rootSig =
nullptr;
3438 hr = rhiD->dev->CreateRootSignature(0,
3439 signature->GetBufferPointer(),
3440 signature->GetBufferSize(),
3441 __uuidof(ID3D12RootSignature),
3442 reinterpret_cast<
void **>(&rootSig));
3443 signature->Release();
3445 qWarning(
"Failed to create root signature: %s",
3446 qPrintable(QSystemError::windowsComString(hr)));
3450 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3452 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3453 psoDesc.pRootSignature = rootSig;
3454 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
3455 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
3456 ID3D12PipelineState *pso =
nullptr;
3457 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3458 __uuidof(ID3D12PipelineState),
3459 reinterpret_cast<
void **>(&pso));
3461 qWarning(
"Failed to create compute pipeline state: %s",
3462 qPrintable(QSystemError::windowsComString(hr)));
3463 rhiD->rootSignaturePool.remove(rootSigHandle);
3468 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3473void QD3D12MipmapGenerator3D::destroy()
3475 rhiD->pipelinePool.remove(pipelineHandle);
3476 pipelineHandle = {};
3477 rhiD->rootSignaturePool.remove(rootSigHandle);
3481void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3483 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3486 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3489 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3493 const quint32 mipLevelCount = res->desc.MipLevels;
3494 if (mipLevelCount < 2)
3497 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3499 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
3503 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3504 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3506 cbD->cmdList->SetPipelineState(pipeline->pso);
3507 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3509 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3515 quint32 srcMipLevel;
3518 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
3519 std::optional<QD3D12StagingArea> ownStagingArea;
3520 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3521 ownStagingArea = QD3D12StagingArea();
3522 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3523 qWarning(
"Could not create staging area for mipmap generation");
3527 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3528 ? &ownStagingArea.value()
3529 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3531 bool gotNewHeap =
false;
3532 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3533 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3534 rhiD->currentFrameSlot,
3535 (1 + 1) * mipLevelCount,
3538 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3542 rhiD->bindShaderVisibleHeaps(cbD);
3544 for (quint32 level = 0; level < mipLevelCount; ++level) {
3545 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
3546 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3547 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3548 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3550 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
3551 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
3552 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
3554 CBufData cbufData = {
3555 1.0f /
float(levelPlusOneMipWidth),
3556 1.0f /
float(levelPlusOneMipHeight),
3557 1.0f /
float(levelPlusOneMipDepth),
3561 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3562 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3563 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3565 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3566 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3567 srvDesc.Format = res->desc.Format;
3568 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3569 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
3570 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
3572 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3573 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3575 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3576 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3577 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
3578 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3579 uavDesc.Format = res->desc.Format;
3580 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
3581 uavDesc.Texture3D.MipSlice = uavMipLevel;
3582 uavDesc.Texture3D.WSize = UINT(-1);
3583 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3584 uavCpuHandle.ptr += descriptorByteSize;
3585 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3587 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
3589 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3590 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3591 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3592 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3595 if (ownStagingArea.has_value())
3596 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3599bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
3601 this->device = device;
3608 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
3612 DXGI_ADAPTER_DESC1 desc;
3613 adapter->GetDesc1(&desc);
3614 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
3617 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3618 allocatorDesc.pDevice = device;
3619 allocatorDesc.pAdapter = adapter;
3622 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
3623 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3625 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
3626 qPrintable(QSystemError::windowsComString(hr)));
3632void QD3D12MemoryAllocator::destroy()
3635 allocator->Release();
3636 allocator =
nullptr;
3640HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
3641 const D3D12_RESOURCE_DESC *resourceDesc,
3642 D3D12_RESOURCE_STATES initialState,
3643 const D3D12_CLEAR_VALUE *optimizedClearValue,
3644 D3D12MA::Allocation **maybeAllocation,
3645 REFIID riidResource,
3649 D3D12MA::ALLOCATION_DESC allocDesc = {};
3650 allocDesc.HeapType = heapType;
3651 return allocator->CreateResource(&allocDesc,
3654 optimizedClearValue,
3659 *maybeAllocation =
nullptr;
3660 D3D12_HEAP_PROPERTIES heapProps = {};
3661 heapProps.Type = heapType;
3662 return device->CreateCommittedResource(&heapProps,
3663 D3D12_HEAP_FLAG_NONE,
3666 optimizedClearValue,
3672void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
3675 allocator->GetBudget(localBudget, nonLocalBudget);
3678 *nonLocalBudget = {};
3682void QRhiD3D12::waitGpu()
3684 fullFenceCounter += 1u;
3685 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
3686 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
3687 WaitForSingleObject(fullFenceEvent, INFINITE);
3691DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
3693 DXGI_SAMPLE_DESC desc;
3697 const int s = effectiveSampleCount(sampleCount);
3700 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
3701 msaaInfo.Format = format;
3702 msaaInfo.SampleCount = UINT(s);
3703 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
3704 if (msaaInfo.NumQualityLevels > 0) {
3705 desc.Count = UINT(s);
3706 desc.Quality = msaaInfo.NumQualityLevels - 1;
3708 qWarning(
"No quality levels for multisampling with sample count %d", s);
3716bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
3718 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
3720 HRESULT hr = dev->CreateCommandList(0,
3721 D3D12_COMMAND_LIST_TYPE_DIRECT,
3724 __uuidof(D3D12GraphicsCommandList),
3725 reinterpret_cast<
void **>(cmdList));
3727 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3731 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
3733 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3740static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
3743 case DXGI_FORMAT_R8G8B8A8_UNORM:
3744 return QRhiTexture::RGBA8;
3745 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
3747 (*flags) |= QRhiTexture::sRGB;
3748 return QRhiTexture::RGBA8;
3749 case DXGI_FORMAT_B8G8R8A8_UNORM:
3750 return QRhiTexture::BGRA8;
3751 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
3753 (*flags) |= QRhiTexture::sRGB;
3754 return QRhiTexture::BGRA8;
3755 case DXGI_FORMAT_R16G16B16A16_FLOAT:
3756 return QRhiTexture::RGBA16F;
3757 case DXGI_FORMAT_R32G32B32A32_FLOAT:
3758 return QRhiTexture::RGBA32F;
3759 case DXGI_FORMAT_R10G10B10A2_UNORM:
3760 return QRhiTexture::RGB10A2;
3762 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
3765 return QRhiTexture::UnknownFormat;
3768void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
3770 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
3772 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
3773 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
3774 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
3775 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3776 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
3777 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3778 if (u.offset == 0 && u.data.size() == bufD->m_size)
3779 bufD->pendingHostWrites[i].clear();
3780 bufD->pendingHostWrites[i].append({ u.offset, u.data });
3782 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
3783 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3784 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
3785 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3793 QD3D12StagingArea::Allocation stagingAlloc;
3794 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3795 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3796 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3798 std::optional<QD3D12StagingArea> ownStagingArea;
3799 if (!stagingAlloc.isValid()) {
3800 ownStagingArea = QD3D12StagingArea();
3801 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3803 stagingAlloc = ownStagingArea->get(allocSize);
3804 if (!stagingAlloc.isValid()) {
3805 ownStagingArea->destroy();
3810 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3812 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3813 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3815 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3816 cbD->cmdList->CopyBufferRegion(res->resource,
3818 stagingAlloc.buffer,
3819 stagingAlloc.bufferOffset + u.offset,
3823 if (ownStagingArea.has_value())
3824 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3825 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
3826 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3827 if (bufD->m_type == QRhiBuffer::Dynamic) {
3828 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3829 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3830 Q_ASSERT(res->cpuMapPtr);
3831 u.result->data.resize(u.readSize);
3832 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
3834 if (u.result->completed)
3835 u.result->completed();
3837 QD3D12Readback readback;
3838 readback.frameSlot = currentFrameSlot;
3839 readback.result = u.result;
3840 readback.byteSize = u.readSize;
3841 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3842 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3843 if (u.result->completed)
3844 u.result->completed();
3847 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3848 if (!stagingAlloc.isValid()) {
3849 readback.staging.destroy();
3850 if (u.result->completed)
3851 u.result->completed();
3854 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3855 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3856 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3857 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3858 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
3859 activeReadbacks.append(readback);
3861 readback.staging.destroy();
3862 if (u.result->completed)
3863 u.result->completed();
3869 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
3870 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
3871 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
3872 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3873 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3874 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
3877 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3878 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3879 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
3880 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
3881 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
3882 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
3883 footprint.Format = res->desc.Format;
3884 footprint.Depth = 1;
3885 quint32 totalBytes = 0;
3887 const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
3888 : subresDesc.sourceSize();
3889 const QPoint srcPos = subresDesc.sourceTopLeft();
3890 QPoint dstPos = subresDesc.destinationTopLeft();
3892 if (!subresDesc.image().isNull()) {
3893 const QImage img = subresDesc.image();
3894 const int bpl = img.bytesPerLine();
3895 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3896 totalBytes = footprint.RowPitch * img.height();
3897 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3900 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3901 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3902 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3903 totalBytes = footprint.RowPitch * rowCount;
3904 }
else if (!subresDesc.data().isEmpty()) {
3906 if (subresDesc.dataStride())
3907 bpl = subresDesc.dataStride();
3909 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3910 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3911 totalBytes = footprint.RowPitch * subresSize.height();
3913 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
3917 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
3918 QD3D12StagingArea::Allocation stagingAlloc;
3919 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3920 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3922 std::optional<QD3D12StagingArea> ownStagingArea;
3923 if (!stagingAlloc.isValid()) {
3924 ownStagingArea = QD3D12StagingArea();
3925 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3927 stagingAlloc = ownStagingArea->get(allocSize);
3928 if (!stagingAlloc.isValid()) {
3929 ownStagingArea->destroy();
3934 D3D12_TEXTURE_COPY_LOCATION dst;
3935 dst.pResource = res->resource;
3936 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3937 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
3938 D3D12_TEXTURE_COPY_LOCATION src;
3939 src.pResource = stagingAlloc.buffer;
3940 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3941 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3945 if (!subresDesc.image().isNull()) {
3946 const QImage img = subresDesc.image();
3947 const int bpc = qMax(1, img.depth() / 8);
3948 const int bpl = img.bytesPerLine();
3950 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
3951 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
3952 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
3953 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
3955 footprint.Width = size.width();
3956 footprint.Height = size.height();
3960 srcBox.right = UINT(size.width());
3961 srcBox.bottom = UINT(size.height());
3965 const uchar *imgPtr = img.constBits();
3966 const quint32 lineBytes = size.width() * bpc;
3967 for (
int y = 0, h = size.height(); y < h; ++y) {
3968 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3969 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3972 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3975 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3977 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3978 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3983 srcBox.right = aligned(subresSize.width(), blockDim.width());
3984 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3989 footprint.Width = aligned(subresSize.width(), blockDim.width());
3990 footprint.Height = aligned(subresSize.height(), blockDim.height());
3992 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3993 const QByteArray imgData = subresDesc.data();
3994 const char *imgPtr = imgData.constData();
3995 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3996 for (
int y = 0; y < rowCount; ++y)
3997 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3998 }
else if (!subresDesc.data().isEmpty()) {
4001 srcBox.right = subresSize.width();
4002 srcBox.bottom = subresSize.height();
4006 footprint.Width = subresSize.width();
4007 footprint.Height = subresSize.height();
4010 if (subresDesc.dataStride())
4011 bpl = subresDesc.dataStride();
4013 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4015 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4016 const QByteArray data = subresDesc.data();
4017 const char *imgPtr = data.constData();
4018 for (
int y = 0, h = subresSize.height(); y < h; ++y)
4019 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
4022 src.PlacedFootprint.Footprint = footprint;
4024 cbD->cmdList->CopyTextureRegion(&dst,
4027 is3D ? UINT(layer) : 0u,
4031 if (ownStagingArea.has_value())
4032 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4036 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4037 Q_ASSERT(u.src && u.dst);
4038 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4039 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4040 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4041 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4042 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4043 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4044 if (!srcRes || !dstRes)
4047 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4048 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4049 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4051 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4052 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4053 srcD->mipLevelCount);
4054 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4055 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4056 dstD->mipLevelCount);
4057 const QPoint dp = u.desc.destinationTopLeft();
4058 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4059 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4060 const QPoint sp = u.desc.sourceTopLeft();
4063 srcBox.left = UINT(sp.x());
4064 srcBox.top = UINT(sp.y());
4065 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4067 srcBox.right = srcBox.left + UINT(copySize.width());
4068 srcBox.bottom = srcBox.top + UINT(copySize.height());
4069 srcBox.back = srcBox.front + 1;
4071 D3D12_TEXTURE_COPY_LOCATION src;
4072 src.pResource = srcRes->resource;
4073 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4074 src.SubresourceIndex = srcSubresource;
4075 D3D12_TEXTURE_COPY_LOCATION dst;
4076 dst.pResource = dstRes->resource;
4077 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4078 dst.SubresourceIndex = dstSubresource;
4080 cbD->cmdList->CopyTextureRegion(&dst,
4083 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4086 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4087 QD3D12Readback readback;
4088 readback.frameSlot = currentFrameSlot;
4089 readback.result = u.result;
4091 QD3D12ObjectHandle srcHandle;
4094 if (u.rb.texture()) {
4095 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4096 if (texD->sampleDesc.Count > 1) {
4097 qWarning(
"Multisample texture cannot be read back");
4100 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4101 if (u.rb.rect().isValid())
4104 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4105 readback.format = texD->m_format;
4106 srcHandle = texD->handle;
4108 Q_ASSERT(currentSwapChain);
4109 if (u.rb.rect().isValid())
4112 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4113 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4114 if (readback.format == QRhiTexture::UnknownFormat)
4116 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4118 readback.pixelSize = rect.size();
4120 textureFormatInfo(readback.format,
4122 &readback.bytesPerLine,
4126 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4130 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4131 is3D ? 0u : UINT(u.rb.layer()),
4132 srcRes->desc.MipLevels);
4133 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4136 UINT64 totalBytes = 0;
4137 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4138 &layout,
nullptr,
nullptr, &totalBytes);
4139 readback.stagingRowPitch = layout.Footprint.RowPitch;
4141 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
4142 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4143 if (u.result->completed)
4144 u.result->completed();
4147 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
4148 if (!stagingAlloc.isValid()) {
4149 readback.staging.destroy();
4150 if (u.result->completed)
4151 u.result->completed();
4154 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4156 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4157 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4159 D3D12_TEXTURE_COPY_LOCATION dst;
4160 dst.pResource = stagingAlloc.buffer;
4161 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4162 dst.PlacedFootprint.Offset = 0;
4163 dst.PlacedFootprint.Footprint = layout.Footprint;
4165 D3D12_TEXTURE_COPY_LOCATION src;
4166 src.pResource = srcRes->resource;
4167 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4168 src.SubresourceIndex = subresource;
4170 D3D12_BOX srcBox = {};
4171 srcBox.left = UINT(rect.left());
4172 srcBox.top = UINT(rect.top());
4173 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4175 srcBox.right = srcBox.left + UINT(rect.width());
4176 srcBox.bottom = srcBox.top + UINT(rect.height());
4177 srcBox.back = srcBox.front + 1;
4179 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4180 activeReadbacks.append(readback);
4181 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4182 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4183 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4184 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4185 mipmapGen3D.generate(cbD, texD->handle);
4187 mipmapGen.generate(cbD, texD->handle);
4194void QRhiD3D12::finishActiveReadbacks(
bool forced)
4196 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4198 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4199 QD3D12Readback &readback(activeReadbacks[i]);
4200 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4201 readback.result->format = readback.format;
4202 readback.result->pixelSize = readback.pixelSize;
4203 readback.result->data.resize(
int(readback.byteSize));
4205 if (readback.format != QRhiTexture::UnknownFormat) {
4206 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4207 const quint8 *srcPtr = readback.staging.mem.p;
4208 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4209 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4210 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4212 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4215 readback.staging.destroy();
4217 if (readback.result->completed)
4218 completedCallbacks.append(readback.result->completed);
4220 activeReadbacks.remove(i);
4224 for (
auto f : completedCallbacks)
4228bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4229 D3D12_DESCRIPTOR_HEAP_TYPE type,
4231 quint32 neededDescriptorCount,
4239 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4240 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4241 neededDescriptorCount);
4242 QD3D12ShaderVisibleDescriptorHeap newHeap;
4243 if (!newHeap.create(dev, type, newPerFrameSize)) {
4244 qWarning(
"Could not create new shader-visible descriptor heap");
4247 h->destroyWithDeferredRelease(&releaseQueue);
4254void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4256 ID3D12DescriptorHeap *heaps[] = {
4257 shaderVisibleCbvSrvUavHeap.heap.heap,
4258 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4260 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4263QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4264 : QRhiBuffer(rhi, type, usage, size)
4268QD3D12Buffer::~QD3D12Buffer()
4273void QD3D12Buffer::destroy()
4275 if (handles[0].isNull())
4278 QRHI_RES_RHI(QRhiD3D12);
4287 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4289 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4291 pendingHostWrites[i].clear();
4295 rhiD->unregisterResource(
this);
4298bool QD3D12Buffer::create()
4300 if (!handles[0].isNull())
4303 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4304 qWarning(
"UniformBuffer must always be Dynamic");
4308 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4309 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4313 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4314 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4316 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4317 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4318 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4320 QRHI_RES_RHI(QRhiD3D12);
4322 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4323 if (i == 0 || m_type == Dynamic) {
4324 D3D12_RESOURCE_DESC resourceDesc = {};
4325 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4326 resourceDesc.Width = roundedSize;
4327 resourceDesc.Height = 1;
4328 resourceDesc.DepthOrArraySize = 1;
4329 resourceDesc.MipLevels = 1;
4330 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4331 resourceDesc.SampleDesc = { 1, 0 };
4332 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4333 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4334 ID3D12Resource *resource =
nullptr;
4335 D3D12MA::Allocation *allocation =
nullptr;
4337 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4338 ? D3D12_HEAP_TYPE_UPLOAD
4339 : D3D12_HEAP_TYPE_DEFAULT;
4340 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4341 ? D3D12_RESOURCE_STATE_GENERIC_READ
4342 : D3D12_RESOURCE_STATE_COMMON;
4343 hr = rhiD->vma.createResource(heapType,
4349 reinterpret_cast<
void **>(&resource));
4352 if (!m_objectName.isEmpty()) {
4353 QString decoratedName = QString::fromUtf8(m_objectName);
4354 if (m_type == Dynamic) {
4355 decoratedName += QLatin1Char(
'/');
4356 decoratedName += QString::number(i);
4358 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4360 void *cpuMemPtr =
nullptr;
4361 if (m_type == Dynamic) {
4363 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4365 qWarning(
"Map() failed to dynamic buffer");
4366 resource->Release();
4368 allocation->Release();
4372 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4380 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4381 qPrintable(QSystemError::windowsComString(hr)),
4384 int(rhiD->vma.isUsingD3D12MA()));
4388 rhiD->registerResource(
this);
4392QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4395 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4396 QRHI_RES_RHI(QRhiD3D12);
4397 if (m_type == Dynamic) {
4398 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4399 executeHostWritesForFrameSlot(i);
4400 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4401 b.objects[i] = res->resource;
4403 b.objects[i] =
nullptr;
4405 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4408 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4409 b.objects[0] = res->resource;
4411 b.objects[0] =
nullptr;
4416char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4424 Q_ASSERT(m_type == Dynamic);
4425 QRHI_RES_RHI(QRhiD3D12);
4426 Q_ASSERT(rhiD->inFrame);
4427 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4428 return static_cast<
char *>(res->cpuMapPtr);
4433void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4438void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4440 if (pendingHostWrites[frameSlot].isEmpty())
4443 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4444 QRHI_RES_RHI(QRhiD3D12);
4445 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4446 Q_ASSERT(res->cpuMapPtr);
4447 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4448 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4450 pendingHostWrites[frameSlot].clear();
4453static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4455 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4457 case QRhiTexture::RGBA8:
4458 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4459 case QRhiTexture::BGRA8:
4460 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4461 case QRhiTexture::R8:
4462 return DXGI_FORMAT_R8_UNORM;
4463 case QRhiTexture::R8SI:
4464 return DXGI_FORMAT_R8_SINT;
4465 case QRhiTexture::R8UI:
4466 return DXGI_FORMAT_R8_UINT;
4467 case QRhiTexture::RG8:
4468 return DXGI_FORMAT_R8G8_UNORM;
4469 case QRhiTexture::R16:
4470 return DXGI_FORMAT_R16_UNORM;
4471 case QRhiTexture::RG16:
4472 return DXGI_FORMAT_R16G16_UNORM;
4473 case QRhiTexture::RED_OR_ALPHA8:
4474 return DXGI_FORMAT_R8_UNORM;
4476 case QRhiTexture::RGBA16F:
4477 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4478 case QRhiTexture::RGBA32F:
4479 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4480 case QRhiTexture::R16F:
4481 return DXGI_FORMAT_R16_FLOAT;
4482 case QRhiTexture::R32F:
4483 return DXGI_FORMAT_R32_FLOAT;
4485 case QRhiTexture::RGB10A2:
4486 return DXGI_FORMAT_R10G10B10A2_UNORM;
4488 case QRhiTexture::R32SI:
4489 return DXGI_FORMAT_R32_SINT;
4490 case QRhiTexture::R32UI:
4491 return DXGI_FORMAT_R32_UINT;
4492 case QRhiTexture::RG32SI:
4493 return DXGI_FORMAT_R32G32_SINT;
4494 case QRhiTexture::RG32UI:
4495 return DXGI_FORMAT_R32G32_UINT;
4496 case QRhiTexture::RGBA32SI:
4497 return DXGI_FORMAT_R32G32B32A32_SINT;
4498 case QRhiTexture::RGBA32UI:
4499 return DXGI_FORMAT_R32G32B32A32_UINT;
4501 case QRhiTexture::D16:
4502 return DXGI_FORMAT_R16_TYPELESS;
4503 case QRhiTexture::D24:
4504 return DXGI_FORMAT_R24G8_TYPELESS;
4505 case QRhiTexture::D24S8:
4506 return DXGI_FORMAT_R24G8_TYPELESS;
4507 case QRhiTexture::D32F:
4508 return DXGI_FORMAT_R32_TYPELESS;
4509 case QRhiTexture::Format::D32FS8:
4510 return DXGI_FORMAT_R32G8X24_TYPELESS;
4512 case QRhiTexture::BC1:
4513 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4514 case QRhiTexture::BC2:
4515 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4516 case QRhiTexture::BC3:
4517 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4518 case QRhiTexture::BC4:
4519 return DXGI_FORMAT_BC4_UNORM;
4520 case QRhiTexture::BC5:
4521 return DXGI_FORMAT_BC5_UNORM;
4522 case QRhiTexture::BC6H:
4523 return DXGI_FORMAT_BC6H_UF16;
4524 case QRhiTexture::BC7:
4525 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4527 case QRhiTexture::ETC2_RGB8:
4528 case QRhiTexture::ETC2_RGB8A1:
4529 case QRhiTexture::ETC2_RGBA8:
4530 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4531 return DXGI_FORMAT_R8G8B8A8_UNORM;
4533 case QRhiTexture::ASTC_4x4:
4534 case QRhiTexture::ASTC_5x4:
4535 case QRhiTexture::ASTC_5x5:
4536 case QRhiTexture::ASTC_6x5:
4537 case QRhiTexture::ASTC_6x6:
4538 case QRhiTexture::ASTC_8x5:
4539 case QRhiTexture::ASTC_8x6:
4540 case QRhiTexture::ASTC_8x8:
4541 case QRhiTexture::ASTC_10x5:
4542 case QRhiTexture::ASTC_10x6:
4543 case QRhiTexture::ASTC_10x8:
4544 case QRhiTexture::ASTC_10x10:
4545 case QRhiTexture::ASTC_12x10:
4546 case QRhiTexture::ASTC_12x12:
4547 qWarning(
"QRhiD3D12 does not support ASTC textures");
4548 return DXGI_FORMAT_R8G8B8A8_UNORM;
4553 return DXGI_FORMAT_R8G8B8A8_UNORM;
4556QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4558 const QSize &pixelSize,
4561 QRhiTexture::Format backingFormatHint)
4562 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4566QD3D12RenderBuffer::~QD3D12RenderBuffer()
4571void QD3D12RenderBuffer::destroy()
4573 if (handle.isNull())
4576 QRHI_RES_RHI(QRhiD3D12);
4579 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4580 else if (dsv.isValid())
4581 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4589 rhiD->unregisterResource(
this);
4592bool QD3D12RenderBuffer::create()
4594 if (!handle.isNull())
4597 if (m_pixelSize.isEmpty())
4600 QRHI_RES_RHI(QRhiD3D12);
4603 case QRhiRenderBuffer::Color:
4605 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4606 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4607 D3D12_RESOURCE_DESC resourceDesc = {};
4608 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4609 resourceDesc.Width = UINT64(m_pixelSize.width());
4610 resourceDesc.Height = UINT(m_pixelSize.height());
4611 resourceDesc.DepthOrArraySize = 1;
4612 resourceDesc.MipLevels = 1;
4613 resourceDesc.Format = dxgiFormat;
4614 resourceDesc.SampleDesc = sampleDesc;
4615 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4616 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4617 D3D12_CLEAR_VALUE clearValue = {};
4618 clearValue.Format = dxgiFormat;
4620 ID3D12Resource *resource =
nullptr;
4621 D3D12MA::Allocation *allocation =
nullptr;
4622 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4624 D3D12_RESOURCE_STATE_RENDER_TARGET,
4627 __uuidof(ID3D12Resource),
4628 reinterpret_cast<
void **>(&resource));
4630 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4633 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4634 rtv = rhiD->rtvPool.allocate(1);
4637 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4638 rtvDesc.Format = dxgiFormat;
4639 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4640 : D3D12_RTV_DIMENSION_TEXTURE2D;
4641 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4644 case QRhiRenderBuffer::DepthStencil:
4646 dxgiFormat = DS_FORMAT;
4647 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4648 D3D12_RESOURCE_DESC resourceDesc = {};
4649 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4650 resourceDesc.Width = UINT64(m_pixelSize.width());
4651 resourceDesc.Height = UINT(m_pixelSize.height());
4652 resourceDesc.DepthOrArraySize = 1;
4653 resourceDesc.MipLevels = 1;
4654 resourceDesc.Format = dxgiFormat;
4655 resourceDesc.SampleDesc = sampleDesc;
4656 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4657 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4658 if (m_flags.testFlag(UsedWithSwapChainOnly))
4659 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4660 D3D12_CLEAR_VALUE clearValue = {};
4661 clearValue.Format = dxgiFormat;
4662 clearValue.DepthStencil.Depth = 1.0f;
4663 clearValue.DepthStencil.Stencil = 0;
4664 ID3D12Resource *resource =
nullptr;
4665 D3D12MA::Allocation *allocation =
nullptr;
4666 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4668 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4671 __uuidof(ID3D12Resource),
4672 reinterpret_cast<
void **>(&resource));
4674 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4677 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4678 dsv = rhiD->dsvPool.allocate(1);
4681 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4682 dsvDesc.Format = dxgiFormat;
4683 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4684 : D3D12_DSV_DIMENSION_TEXTURE2D;
4685 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4690 if (!m_objectName.isEmpty()) {
4691 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4692 const QString name = QString::fromUtf8(m_objectName);
4693 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4698 rhiD->registerResource(
this);
4702QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4704 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4705 return m_backingFormatHint;
4707 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4710QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4711 int arraySize,
int sampleCount, Flags flags)
4712 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4716QD3D12Texture::~QD3D12Texture()
4721void QD3D12Texture::destroy()
4723 if (handle.isNull())
4726 QRHI_RES_RHI(QRhiD3D12);
4728 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4734 rhiD->unregisterResource(
this);
4737static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4740 case QRhiTexture::Format::D16:
4741 return DXGI_FORMAT_R16_FLOAT;
4742 case QRhiTexture::Format::D24:
4743 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4744 case QRhiTexture::Format::D24S8:
4745 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4746 case QRhiTexture::Format::D32F:
4747 return DXGI_FORMAT_R32_FLOAT;
4748 case QRhiTexture::Format::D32FS8:
4749 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4753 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4756static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4760 case QRhiTexture::Format::D16:
4761 return DXGI_FORMAT_D16_UNORM;
4762 case QRhiTexture::Format::D24:
4763 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4764 case QRhiTexture::Format::D24S8:
4765 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4766 case QRhiTexture::Format::D32F:
4767 return DXGI_FORMAT_D32_FLOAT;
4768 case QRhiTexture::Format::D32FS8:
4769 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4773 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4776static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4779 case QRhiTexture::Format::D16:
4780 case QRhiTexture::Format::D24:
4781 case QRhiTexture::Format::D24S8:
4782 case QRhiTexture::Format::D32F:
4783 case QRhiTexture::Format::D32FS8:
4790bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4792 if (!handle.isNull())
4795 QRHI_RES_RHI(QRhiD3D12);
4796 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4799 const bool isDepth = isDepthTextureFormat(m_format);
4800 const bool isCube = m_flags.testFlag(CubeMap);
4801 const bool is3D = m_flags.testFlag(ThreeDimensional);
4802 const bool isArray = m_flags.testFlag(TextureArray);
4803 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4804 const bool is1D = m_flags.testFlag(OneDimensional);
4806 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4807 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4809 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4811 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4812 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4814 srvFormat = dxgiFormat;
4815 rtFormat = dxgiFormat;
4817 if (m_writeViewFormat.format != UnknownFormat) {
4819 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4821 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4823 if (m_readViewFormat.format != UnknownFormat) {
4825 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4827 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4830 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4831 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4832 if (sampleDesc.Count > 1) {
4834 qWarning(
"Cubemap texture cannot be multisample");
4838 qWarning(
"3D texture cannot be multisample");
4842 qWarning(
"Multisample texture cannot have mipmaps");
4846 if (isDepth && hasMipMaps) {
4847 qWarning(
"Depth texture cannot have mipmaps");
4850 if (isCube && is3D) {
4851 qWarning(
"Texture cannot be both cube and 3D");
4854 if (isArray && is3D) {
4855 qWarning(
"Texture cannot be both array and 3D");
4858 if (isCube && is1D) {
4859 qWarning(
"Texture cannot be both cube and 1D");
4863 qWarning(
"Texture cannot be both 1D and 3D");
4866 if (m_depth > 1 && !is3D) {
4867 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4870 if (m_arraySize > 0 && !isArray) {
4871 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4874 if (m_arraySize < 1 && isArray) {
4875 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4880 *adjustedSize = size;
4885bool QD3D12Texture::finishCreate()
4887 QRHI_RES_RHI(QRhiD3D12);
4888 const bool isCube = m_flags.testFlag(CubeMap);
4889 const bool is3D = m_flags.testFlag(ThreeDimensional);
4890 const bool isArray = m_flags.testFlag(TextureArray);
4891 const bool is1D = m_flags.testFlag(OneDimensional);
4893 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4894 srvDesc.Format = srvFormat;
4895 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4898 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4899 srvDesc.TextureCube.MipLevels = mipLevelCount;
4903 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4904 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4905 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4906 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4907 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4909 srvDesc.Texture1DArray.FirstArraySlice = 0;
4910 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4913 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4914 srvDesc.Texture1D.MipLevels = mipLevelCount;
4916 }
else if (isArray) {
4917 if (sampleDesc.Count > 1) {
4918 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4919 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4920 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4921 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4923 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4924 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4927 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4928 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4929 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4930 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4931 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4933 srvDesc.Texture2DArray.FirstArraySlice = 0;
4934 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4938 if (sampleDesc.Count > 1) {
4939 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4941 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4942 srvDesc.Texture3D.MipLevels = mipLevelCount;
4944 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4945 srvDesc.Texture2D.MipLevels = mipLevelCount;
4950 srv = rhiD->cbvSrvUavPool.allocate(1);
4954 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4955 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4956 if (!m_objectName.isEmpty()) {
4957 const QString name = QString::fromUtf8(m_objectName);
4958 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4968bool QD3D12Texture::create()
4971 if (!prepareCreate(&size))
4974 const bool isDepth = isDepthTextureFormat(m_format);
4975 const bool isCube = m_flags.testFlag(CubeMap);
4976 const bool is3D = m_flags.testFlag(ThreeDimensional);
4977 const bool isArray = m_flags.testFlag(TextureArray);
4978 const bool is1D = m_flags.testFlag(OneDimensional);
4980 QRHI_RES_RHI(QRhiD3D12);
4982 bool needsOptimizedClearValueSpecified =
false;
4983 UINT resourceFlags = 0;
4984 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4986 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4988 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4989 needsOptimizedClearValueSpecified =
true;
4991 if (m_flags.testFlag(UsedWithGenerateMips)) {
4993 qWarning(
"Depth texture cannot have mipmaps generated");
4996 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4998 if (m_flags.testFlag(UsedWithLoadStore))
4999 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5001 D3D12_RESOURCE_DESC resourceDesc = {};
5002 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
5003 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
5004 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
5005 resourceDesc.Width = UINT64(size.width());
5006 resourceDesc.Height = UINT(size.height());
5007 resourceDesc.DepthOrArraySize = isCube ? 6
5008 : (isArray ? UINT(qMax(0, m_arraySize))
5009 : (is3D ? qMax(1, m_depth)
5011 resourceDesc.MipLevels = mipLevelCount;
5012 resourceDesc.Format = dxgiFormat;
5013 resourceDesc.SampleDesc = sampleDesc;
5014 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5015 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5016 D3D12_CLEAR_VALUE clearValue = {};
5017 clearValue.Format = dxgiFormat;
5019 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
5020 clearValue.DepthStencil.Depth = 1.0f;
5021 clearValue.DepthStencil.Stencil = 0;
5023 ID3D12Resource *resource =
nullptr;
5024 D3D12MA::Allocation *allocation =
nullptr;
5025 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5027 D3D12_RESOURCE_STATE_COMMON,
5028 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
5030 __uuidof(ID3D12Resource),
5031 reinterpret_cast<
void **>(&resource));
5033 qWarning(
"Failed to create texture: '%s'"
5034 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
5035 qPrintable(QSystemError::windowsComString(hr)),
5036 int(resourceDesc.Dimension),
5037 uint(resourceDesc.Width),
5038 uint(resourceDesc.Height),
5039 uint(resourceDesc.DepthOrArraySize),
5040 uint(resourceDesc.MipLevels),
5041 int(resourceDesc.Format),
5042 int(resourceDesc.SampleDesc.Count));
5046 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
5048 if (!finishCreate())
5051 rhiD->registerResource(
this);
5055bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
5060 if (!prepareCreate())
5063 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
5064 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
5066 QRHI_RES_RHI(QRhiD3D12);
5067 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
5069 if (!finishCreate())
5072 rhiD->registerResource(
this);
5076QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
5078 QRHI_RES_RHI(QRhiD3D12);
5079 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5080 return { quint64(res->resource),
int(res->state) };
5085void QD3D12Texture::setNativeLayout(
int layout)
5087 QRHI_RES_RHI(QRhiD3D12);
5088 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5089 res->state = D3D12_RESOURCE_STATES(layout);
5092QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
5093 AddressMode u, AddressMode v, AddressMode w)
5094 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5098QD3D12Sampler::~QD3D12Sampler()
5103void QD3D12Sampler::destroy()
5105 shaderVisibleDescriptor = {};
5107 QRHI_RES_RHI(QRhiD3D12);
5109 rhiD->unregisterResource(
this);
5112static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
5114 if (minFilter == QRhiSampler::Nearest) {
5115 if (magFilter == QRhiSampler::Nearest) {
5116 if (mipFilter == QRhiSampler::Linear)
5117 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
5119 return D3D12_FILTER_MIN_MAG_MIP_POINT;
5121 if (mipFilter == QRhiSampler::Linear)
5122 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
5124 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
5127 if (magFilter == QRhiSampler::Nearest) {
5128 if (mipFilter == QRhiSampler::Linear)
5129 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
5131 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
5133 if (mipFilter == QRhiSampler::Linear)
5134 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
5136 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
5139 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
5142static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
5145 case QRhiSampler::Repeat:
5146 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
5147 case QRhiSampler::ClampToEdge:
5148 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
5149 case QRhiSampler::Mirror:
5150 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
5152 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5155static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5158 case QRhiSampler::Never:
5159 return D3D12_COMPARISON_FUNC_NEVER;
5160 case QRhiSampler::Less:
5161 return D3D12_COMPARISON_FUNC_LESS;
5162 case QRhiSampler::Equal:
5163 return D3D12_COMPARISON_FUNC_EQUAL;
5164 case QRhiSampler::LessOrEqual:
5165 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5166 case QRhiSampler::Greater:
5167 return D3D12_COMPARISON_FUNC_GREATER;
5168 case QRhiSampler::NotEqual:
5169 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5170 case QRhiSampler::GreaterOrEqual:
5171 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5172 case QRhiSampler::Always:
5173 return D3D12_COMPARISON_FUNC_ALWAYS;
5175 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5178bool QD3D12Sampler::create()
5181 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5182 if (m_compareOp != Never)
5183 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5184 desc.AddressU = toD3DAddressMode(m_addressU);
5185 desc.AddressV = toD3DAddressMode(m_addressV);
5186 desc.AddressW = toD3DAddressMode(m_addressW);
5187 desc.MaxAnisotropy = 1.0f;
5188 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5189 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5191 QRHI_RES_RHI(QRhiD3D12);
5192 rhiD->registerResource(
this,
false);
5196QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5198 if (!shaderVisibleDescriptor.isValid()) {
5199 QRHI_RES_RHI(QRhiD3D12);
5200 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5202 return shaderVisibleDescriptor;
5205QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5206 : QRhiShadingRateMap(rhi)
5210QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5215void QD3D12ShadingRateMap::destroy()
5217 if (handle.isNull())
5223bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5225 if (!handle.isNull())
5228 handle = QRHI_RES(QD3D12Texture, src)->handle;
5233QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5234 const QRhiTextureRenderTargetDescription &desc,
5236 : QRhiTextureRenderTarget(rhi, desc, flags),
5241QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5246void QD3D12TextureRenderTarget::destroy()
5248 if (!rtv[0].isValid() && !dsv.isValid())
5251 QRHI_RES_RHI(QRhiD3D12);
5252 if (dsv.isValid()) {
5253 if (ownsDsv && rhiD)
5254 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5258 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5259 if (rtv[i].isValid()) {
5260 if (ownsRtv[i] && rhiD)
5261 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5267 rhiD->unregisterResource(
this);
5270QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5274 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5276 rpD->colorAttachmentCount = 0;
5277 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5278 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5279 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5281 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5283 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5284 rpD->colorAttachmentCount += 1;
5287 rpD->hasDepthStencil =
false;
5288 if (m_desc.depthStencilBuffer()) {
5289 rpD->hasDepthStencil =
true;
5290 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5291 }
else if (m_desc.depthTexture()) {
5292 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5293 rpD->hasDepthStencil =
true;
5294 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5297 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5299 rpD->updateSerializedFormat();
5301 QRHI_RES_RHI(QRhiD3D12);
5302 rhiD->registerResource(rpD);
5306bool QD3D12TextureRenderTarget::create()
5308 if (rtv[0].isValid() || dsv.isValid())
5311 QRHI_RES_RHI(QRhiD3D12);
5312 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5313 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5314 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5315 d.colorAttCount = 0;
5318 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5319 d.colorAttCount += 1;
5320 const QRhiColorAttachment &colorAtt(*it);
5321 QRhiTexture *texture = colorAtt.texture();
5322 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5323 Q_ASSERT(texture || rb);
5325 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5326 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5328 qWarning(
"Could not look up texture handle for render target");
5331 const bool isMultiView = it->multiViewCount() >= 2;
5332 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5333 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5334 rtvDesc.Format = texD->rtFormat;
5335 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5336 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5337 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5338 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5339 rtvDesc.Texture2DArray.ArraySize = layerCount;
5340 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5341 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5342 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5343 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5344 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5345 rtvDesc.Texture1DArray.ArraySize = layerCount;
5347 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5348 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5350 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5351 if (texD->sampleDesc.Count > 1) {
5352 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5353 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5354 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5356 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5357 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5358 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5359 rtvDesc.Texture2DArray.ArraySize = layerCount;
5361 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5362 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5363 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5364 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5365 rtvDesc.Texture3D.WSize = layerCount;
5367 if (texD->sampleDesc.Count > 1) {
5368 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5370 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5371 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5374 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5375 if (!rtv[attIndex].isValid()) {
5376 qWarning(
"Failed to allocate RTV for texture render target");
5379 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5380 ownsRtv[attIndex] =
true;
5381 if (attIndex == 0) {
5382 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5383 d.sampleCount =
int(texD->sampleDesc.Count);
5386 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5387 ownsRtv[attIndex] =
false;
5388 rtv[attIndex] = rbD->rtv;
5389 if (attIndex == 0) {
5390 d.pixelSize = rbD->pixelSize();
5391 d.sampleCount =
int(rbD->sampleDesc.Count);
5398 if (hasDepthStencil) {
5399 if (m_desc.depthTexture()) {
5401 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5402 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5404 qWarning(
"Could not look up depth texture handle");
5407 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5408 dsvDesc.Format = depthTexD->rtFormat;
5409 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5410 : D3D12_DSV_DIMENSION_TEXTURE2D;
5411 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5412 if (depthTexD->sampleDesc.Count > 1) {
5413 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5414 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5415 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5416 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5418 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5419 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5422 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5423 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5424 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5425 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5427 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5428 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5432 dsv = rhiD->dsvPool.allocate(1);
5433 if (!dsv.isValid()) {
5434 qWarning(
"Failed to allocate DSV for texture render target");
5437 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5438 if (d.colorAttCount == 0) {
5439 d.pixelSize = depthTexD->pixelSize();
5440 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5444 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5445 dsv = depthRbD->dsv;
5446 if (d.colorAttCount == 0) {
5447 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5448 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5456 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5457 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5458 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5459 d.dsv = dsv.cpuHandle;
5460 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5462 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5464 rhiD->registerResource(
this);
5468QSize QD3D12TextureRenderTarget::pixelSize()
const
5470 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5471 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5476float QD3D12TextureRenderTarget::devicePixelRatio()
const
5481int QD3D12TextureRenderTarget::sampleCount()
const
5483 return d.sampleCount;
5486QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5487 : QRhiShaderResourceBindings(rhi)
5491QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5496void QD3D12ShaderResourceBindings::destroy()
5498 QRHI_RES_RHI(QRhiD3D12);
5500 rhiD->unregisterResource(
this);
5503bool QD3D12ShaderResourceBindings::create()
5505 QRHI_RES_RHI(QRhiD3D12);
5506 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5509 rhiD->updateLayoutDesc(
this);
5511 hasDynamicOffset =
false;
5512 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5513 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5514 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5515 hasDynamicOffset =
true;
5529 rhiD->registerResource(
this,
false);
5533void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5544void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5545 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5549 D3D12_ROOT_PARAMETER1 rootParam = {};
5550 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5551 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5552 rootParam.Descriptor.ShaderRegister = shaderRegister;
5553 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5554 visitorData.cbParams[s].append(rootParam);
5557void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5558 const QRhiShaderResourceBinding::TextureAndSampler &,
5561 D3D12_DESCRIPTOR_RANGE1 range = {};
5562 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5563 range.NumDescriptors = 1;
5564 range.BaseShaderRegister = shaderRegister;
5565 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5566 visitorData.currentSrvRangeOffset[s] += 1;
5567 visitorData.srvRanges[s].append(range);
5568 if (visitorData.srvRanges[s].count() == 1) {
5569 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5570 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5574void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5575 const QRhiShaderResourceBinding::TextureAndSampler &,
5581 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5582 if (rangeStoreIdx == 16) {
5583 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5586 D3D12_DESCRIPTOR_RANGE1 range = {};
5587 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5588 range.NumDescriptors = 1;
5589 range.BaseShaderRegister = shaderRegister;
5590 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5591 D3D12_ROOT_PARAMETER1 param = {};
5592 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5593 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5594 param.DescriptorTable.NumDescriptorRanges = 1;
5595 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5597 visitorData.samplerTables[s].append(param);
5600void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5601 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5602 QD3D12ShaderResourceVisitor::StorageOp,
5605 D3D12_DESCRIPTOR_RANGE1 range = {};
5606 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5607 range.NumDescriptors = 1;
5608 range.BaseShaderRegister = shaderRegister;
5609 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5610 visitorData.currentUavRangeOffset[s] += 1;
5611 visitorData.uavRanges[s].append(range);
5612 if (visitorData.uavRanges[s].count() == 1) {
5613 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5614 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5618void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5619 const QRhiShaderResourceBinding::Data::StorageImageData &,
5620 QD3D12ShaderResourceVisitor::StorageOp,
5623 D3D12_DESCRIPTOR_RANGE1 range = {};
5624 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5625 range.NumDescriptors = 1;
5626 range.BaseShaderRegister = shaderRegister;
5627 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5628 visitorData.currentUavRangeOffset[s] += 1;
5629 visitorData.uavRanges[s].append(range);
5630 if (visitorData.uavRanges[s].count() == 1) {
5631 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5632 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5636QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5639 QRHI_RES_RHI(QRhiD3D12);
5653 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5657 using namespace std::placeholders;
5658 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5659 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5660 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5661 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5662 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5686 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5687 for (
int s = 0; s < 6; ++s) {
5688 if (!visitorData.cbParams[s].isEmpty())
5689 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5691 for (
int s = 0; s < 6; ++s) {
5692 if (!visitorData.srvRanges[s].isEmpty()) {
5693 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5694 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5695 rootParams.append(visitorData.srvTables[s]);
5698 for (
int s = 0; s < 6; ++s) {
5699 if (!visitorData.samplerTables[s].isEmpty())
5700 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5702 for (
int s = 0; s < 6; ++s) {
5703 if (!visitorData.uavRanges[s].isEmpty()) {
5704 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5705 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5706 rootParams.append(visitorData.uavTables[s]);
5710 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5711 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5712 if (!rootParams.isEmpty()) {
5713 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5714 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5718 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5719 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5720 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5722 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5724 ID3DBlob *signature =
nullptr;
5725 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5727 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5730 ID3D12RootSignature *rootSig =
nullptr;
5731 hr = rhiD->dev->CreateRootSignature(0,
5732 signature->GetBufferPointer(),
5733 signature->GetBufferSize(),
5734 __uuidof(ID3D12RootSignature),
5735 reinterpret_cast<
void **>(&rootSig));
5736 signature->Release();
5738 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5742 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5754static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5756 const int smMajor = version / 10;
5757 const int smMinor = version % 10;
5758 target[0] = stage[0];
5759 target[1] = stage[1];
5761 target[3] =
'0' + smMajor;
5763 target[5] =
'0' + smMinor;
5767enum class HlslCompileFlag
5769 WithDebugInfo = 0x01
5772static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5774 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5776 qWarning(
"Unable to resolve function D3DCompile()");
5777 return QByteArray();
5780 ID3DBlob *bytecode =
nullptr;
5781 ID3DBlob *errors =
nullptr;
5782 UINT d3dCompileFlags = 0;
5783 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5784 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5786 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5787 nullptr,
nullptr,
nullptr,
5788 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5789 if (FAILED(hr) || !bytecode) {
5790 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5792 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5793 int(errors->GetBufferSize()));
5796 return QByteArray();
5800 result.resize(
int(bytecode->GetBufferSize()));
5801 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5802 bytecode->Release();
5806#ifdef QRHI_D3D12_HAS_DXC
5809#define DXC_CP_UTF8 65001
5812#ifndef DXC_ARG_DEBUG
5813#define DXC_ARG_DEBUG L"-Zi"
5816static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5818 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5819 IDxcCompiler *compiler = dxc.first;
5821 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5822 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5823 return QByteArray();
5825 IDxcLibrary *library = dxc.second;
5827 return QByteArray();
5829 IDxcBlobEncoding *sourceBlob =
nullptr;
5830 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5831 UINT32(hlslSource.shader().size()),
5835 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5837 qPrintable(QSystemError::windowsComString(hr)));
5838 return QByteArray();
5841 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5842 const QString targetStr = QString::fromLatin1(target);
5844 QVarLengthArray<LPCWSTR, 4> argPtrs;
5846 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5847 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5848 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5851 IDxcOperationResult *result =
nullptr;
5852 hr = compiler->Compile(sourceBlob,
5854 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5855 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5856 argPtrs.data(), argPtrs.count(),
5860 sourceBlob->Release();
5862 result->GetStatus(&hr);
5864 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5866 qPrintable(QSystemError::windowsComString(hr)));
5868 IDxcBlobEncoding *errorsBlob =
nullptr;
5869 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5871 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5872 int(errorsBlob->GetBufferSize()));
5873 errorsBlob->Release();
5877 return QByteArray();
5880 IDxcBlob *bytecode =
nullptr;
5881 if FAILED(result->GetResult(&bytecode)) {
5882 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5884 qPrintable(QSystemError::windowsComString(hr)));
5885 return QByteArray();
5889 ba.resize(
int(bytecode->GetBufferSize()));
5890 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5891 bytecode->Release();
5897static QByteArray compileHlslShaderSource(
const QShader &shader,
5898 QShader::Variant shaderVariant,
5901 QShaderKey *usedShaderKey)
5904 const int shaderModelMax = 67;
5905 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5906 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5907 QShaderKey key = { type, sm, shaderVariant };
5908 QShaderCode intermediateBytecodeShader = shader.shader(key);
5909 if (!intermediateBytecodeShader.shader().isEmpty()) {
5911 *usedShaderKey = key;
5912 return intermediateBytecodeShader.shader();
5917 QShaderCode hlslSource;
5919 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5920 key = { QShader::HlslShader, sm, shaderVariant };
5921 hlslSource = shader.shader(key);
5922 if (!hlslSource.shader().isEmpty())
5926 if (hlslSource.shader().isEmpty()) {
5927 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5928 return QByteArray();
5932 *usedShaderKey = key;
5935 switch (shader.stage()) {
5936 case QShader::VertexStage:
5937 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5939 case QShader::TessellationControlStage:
5940 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5942 case QShader::TessellationEvaluationStage:
5943 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5945 case QShader::GeometryStage:
5946 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5948 case QShader::FragmentStage:
5949 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5951 case QShader::ComputeStage:
5952 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5956 if (key.sourceVersion().version() >= 60) {
5957#ifdef QRHI_D3D12_HAS_DXC
5958 return dxcCompile(hlslSource, target, flags, error);
5960 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5961 "but the Qt build has no support for DXC. "
5962 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5966 return legacyCompile(hlslSource, target, flags, error);
5969static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5972 if (c.testFlag(QRhiGraphicsPipeline::R))
5973 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5974 if (c.testFlag(QRhiGraphicsPipeline::G))
5975 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5976 if (c.testFlag(QRhiGraphicsPipeline::B))
5977 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5978 if (c.testFlag(QRhiGraphicsPipeline::A))
5979 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5983static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
5992 case QRhiGraphicsPipeline::Zero:
5993 return D3D12_BLEND_ZERO;
5994 case QRhiGraphicsPipeline::One:
5995 return D3D12_BLEND_ONE;
5996 case QRhiGraphicsPipeline::SrcColor:
5997 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
5998 case QRhiGraphicsPipeline::OneMinusSrcColor:
5999 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
6000 case QRhiGraphicsPipeline::DstColor:
6001 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
6002 case QRhiGraphicsPipeline::OneMinusDstColor:
6003 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
6004 case QRhiGraphicsPipeline::SrcAlpha:
6005 return D3D12_BLEND_SRC_ALPHA;
6006 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6007 return D3D12_BLEND_INV_SRC_ALPHA;
6008 case QRhiGraphicsPipeline::DstAlpha:
6009 return D3D12_BLEND_DEST_ALPHA;
6010 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6011 return D3D12_BLEND_INV_DEST_ALPHA;
6012 case QRhiGraphicsPipeline::ConstantColor:
6013 case QRhiGraphicsPipeline::ConstantAlpha:
6014 return D3D12_BLEND_BLEND_FACTOR;
6015 case QRhiGraphicsPipeline::OneMinusConstantColor:
6016 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6017 return D3D12_BLEND_INV_BLEND_FACTOR;
6018 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6019 return D3D12_BLEND_SRC_ALPHA_SAT;
6020 case QRhiGraphicsPipeline::Src1Color:
6021 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
6022 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6023 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
6024 case QRhiGraphicsPipeline::Src1Alpha:
6025 return D3D12_BLEND_SRC1_ALPHA;
6026 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6027 return D3D12_BLEND_INV_SRC1_ALPHA;
6029 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
6032static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
6035 case QRhiGraphicsPipeline::Add:
6036 return D3D12_BLEND_OP_ADD;
6037 case QRhiGraphicsPipeline::Subtract:
6038 return D3D12_BLEND_OP_SUBTRACT;
6039 case QRhiGraphicsPipeline::ReverseSubtract:
6040 return D3D12_BLEND_OP_REV_SUBTRACT;
6041 case QRhiGraphicsPipeline::Min:
6042 return D3D12_BLEND_OP_MIN;
6043 case QRhiGraphicsPipeline::Max:
6044 return D3D12_BLEND_OP_MAX;
6046 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
6049static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
6052 case QRhiGraphicsPipeline::None:
6053 return D3D12_CULL_MODE_NONE;
6054 case QRhiGraphicsPipeline::Front:
6055 return D3D12_CULL_MODE_FRONT;
6056 case QRhiGraphicsPipeline::Back:
6057 return D3D12_CULL_MODE_BACK;
6059 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
6062static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
6065 case QRhiGraphicsPipeline::Fill:
6066 return D3D12_FILL_MODE_SOLID;
6067 case QRhiGraphicsPipeline::Line:
6068 return D3D12_FILL_MODE_WIREFRAME;
6070 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
6073static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
6076 case QRhiGraphicsPipeline::Never:
6077 return D3D12_COMPARISON_FUNC_NEVER;
6078 case QRhiGraphicsPipeline::Less:
6079 return D3D12_COMPARISON_FUNC_LESS;
6080 case QRhiGraphicsPipeline::Equal:
6081 return D3D12_COMPARISON_FUNC_EQUAL;
6082 case QRhiGraphicsPipeline::LessOrEqual:
6083 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6084 case QRhiGraphicsPipeline::Greater:
6085 return D3D12_COMPARISON_FUNC_GREATER;
6086 case QRhiGraphicsPipeline::NotEqual:
6087 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6088 case QRhiGraphicsPipeline::GreaterOrEqual:
6089 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6090 case QRhiGraphicsPipeline::Always:
6091 return D3D12_COMPARISON_FUNC_ALWAYS;
6093 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
6096static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
6099 case QRhiGraphicsPipeline::StencilZero:
6100 return D3D12_STENCIL_OP_ZERO;
6101 case QRhiGraphicsPipeline::Keep:
6102 return D3D12_STENCIL_OP_KEEP;
6103 case QRhiGraphicsPipeline::Replace:
6104 return D3D12_STENCIL_OP_REPLACE;
6105 case QRhiGraphicsPipeline::IncrementAndClamp:
6106 return D3D12_STENCIL_OP_INCR_SAT;
6107 case QRhiGraphicsPipeline::DecrementAndClamp:
6108 return D3D12_STENCIL_OP_DECR_SAT;
6109 case QRhiGraphicsPipeline::Invert:
6110 return D3D12_STENCIL_OP_INVERT;
6111 case QRhiGraphicsPipeline::IncrementAndWrap:
6112 return D3D12_STENCIL_OP_INCR;
6113 case QRhiGraphicsPipeline::DecrementAndWrap:
6114 return D3D12_STENCIL_OP_DECR;
6116 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
6119static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
6122 case QRhiGraphicsPipeline::Triangles:
6123 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
6124 case QRhiGraphicsPipeline::TriangleStrip:
6125 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6126 case QRhiGraphicsPipeline::TriangleFan:
6127 qWarning(
"Triangle fans are not supported with D3D");
6128 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6129 case QRhiGraphicsPipeline::Lines:
6130 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
6131 case QRhiGraphicsPipeline::LineStrip:
6132 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
6133 case QRhiGraphicsPipeline::Points:
6134 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
6135 case QRhiGraphicsPipeline::Patches:
6136 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
6137 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
6139 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
6142static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
6145 case QRhiGraphicsPipeline::Triangles:
6146 case QRhiGraphicsPipeline::TriangleStrip:
6147 case QRhiGraphicsPipeline::TriangleFan:
6148 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
6149 case QRhiGraphicsPipeline::Lines:
6150 case QRhiGraphicsPipeline::LineStrip:
6151 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
6152 case QRhiGraphicsPipeline::Points:
6153 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6154 case QRhiGraphicsPipeline::Patches:
6155 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6157 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6160static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6163 case QRhiVertexInputAttribute::Float4:
6164 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6165 case QRhiVertexInputAttribute::Float3:
6166 return DXGI_FORMAT_R32G32B32_FLOAT;
6167 case QRhiVertexInputAttribute::Float2:
6168 return DXGI_FORMAT_R32G32_FLOAT;
6169 case QRhiVertexInputAttribute::Float:
6170 return DXGI_FORMAT_R32_FLOAT;
6171 case QRhiVertexInputAttribute::UNormByte4:
6172 return DXGI_FORMAT_R8G8B8A8_UNORM;
6173 case QRhiVertexInputAttribute::UNormByte2:
6174 return DXGI_FORMAT_R8G8_UNORM;
6175 case QRhiVertexInputAttribute::UNormByte:
6176 return DXGI_FORMAT_R8_UNORM;
6177 case QRhiVertexInputAttribute::UInt4:
6178 return DXGI_FORMAT_R32G32B32A32_UINT;
6179 case QRhiVertexInputAttribute::UInt3:
6180 return DXGI_FORMAT_R32G32B32_UINT;
6181 case QRhiVertexInputAttribute::UInt2:
6182 return DXGI_FORMAT_R32G32_UINT;
6183 case QRhiVertexInputAttribute::UInt:
6184 return DXGI_FORMAT_R32_UINT;
6185 case QRhiVertexInputAttribute::SInt4:
6186 return DXGI_FORMAT_R32G32B32A32_SINT;
6187 case QRhiVertexInputAttribute::SInt3:
6188 return DXGI_FORMAT_R32G32B32_SINT;
6189 case QRhiVertexInputAttribute::SInt2:
6190 return DXGI_FORMAT_R32G32_SINT;
6191 case QRhiVertexInputAttribute::SInt:
6192 return DXGI_FORMAT_R32_SINT;
6193 case QRhiVertexInputAttribute::Half4:
6195 case QRhiVertexInputAttribute::Half3:
6196 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6197 case QRhiVertexInputAttribute::Half2:
6198 return DXGI_FORMAT_R16G16_FLOAT;
6199 case QRhiVertexInputAttribute::Half:
6200 return DXGI_FORMAT_R16_FLOAT;
6201 case QRhiVertexInputAttribute::UShort4:
6203 case QRhiVertexInputAttribute::UShort3:
6204 return DXGI_FORMAT_R16G16B16A16_UINT;
6205 case QRhiVertexInputAttribute::UShort2:
6206 return DXGI_FORMAT_R16G16_UINT;
6207 case QRhiVertexInputAttribute::UShort:
6208 return DXGI_FORMAT_R16_UINT;
6209 case QRhiVertexInputAttribute::SShort4:
6211 case QRhiVertexInputAttribute::SShort3:
6212 return DXGI_FORMAT_R16G16B16A16_SINT;
6213 case QRhiVertexInputAttribute::SShort2:
6214 return DXGI_FORMAT_R16G16_SINT;
6215 case QRhiVertexInputAttribute::SShort:
6216 return DXGI_FORMAT_R16_SINT;
6218 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6221QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6222 : QRhiGraphicsPipeline(rhi)
6226QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6231void QD3D12GraphicsPipeline::destroy()
6233 if (handle.isNull())
6236 QRHI_RES_RHI(QRhiD3D12);
6238 rhiD->releaseQueue.deferredReleasePipeline(handle);
6239 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6246 rhiD->unregisterResource(
this);
6249bool QD3D12GraphicsPipeline::create()
6251 if (!handle.isNull())
6254 QRHI_RES_RHI(QRhiD3D12);
6255 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6258 rhiD->pipelineCreationStart();
6260 QByteArray shaderBytecode[5];
6261 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6262 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6263 stageData[d3dStage].valid =
true;
6264 stageData[d3dStage].stage = d3dStage;
6265 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6266 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6267 shaderBytecode[d3dStage] = cacheIt->bytecode;
6268 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6271 QShaderKey shaderKey;
6272 int compileFlags = 0;
6273 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6274 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6275 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6276 shaderStage.shaderVariant(),
6280 if (bytecode.isEmpty()) {
6281 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6285 shaderBytecode[d3dStage] = bytecode;
6286 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6287 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6288 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6292 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6294 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6295 if (rootSigHandle.isNull()) {
6296 qWarning(
"Failed to create root signature");
6300 ID3D12RootSignature *rootSig =
nullptr;
6301 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6302 rootSig = rs->rootSig;
6304 qWarning(
"Cannot create graphics pipeline state without root signature");
6308 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6309 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6310 if (rpD->colorAttachmentCount > 0) {
6311 format = DXGI_FORMAT(rpD->colorFormat[0]);
6312 }
else if (rpD->hasDepthStencil) {
6313 format = DXGI_FORMAT(rpD->dsFormat);
6315 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6318 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6321 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6322 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6323 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6324 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6325 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6326 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6327 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6328 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6329 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6330 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6331 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6332 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6333 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6334 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6335 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6336 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6337 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6340 stream.rootSig.object = rootSig;
6342 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6343 QByteArrayList matrixSliceSemantics;
6344 if (!shaderBytecode[VS].isEmpty()) {
6345 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6348 D3D12_INPUT_ELEMENT_DESC desc = {};
6353 const int matrixSlice = it->matrixSlice();
6354 if (matrixSlice < 0) {
6355 desc.SemanticName =
"TEXCOORD";
6356 desc.SemanticIndex = UINT(it->location());
6360 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6361 matrixSliceSemantics.append(sem);
6362 desc.SemanticName = matrixSliceSemantics.last().constData();
6363 desc.SemanticIndex = UINT(matrixSlice);
6365 desc.Format = toD3DAttributeFormat(it->format());
6366 desc.InputSlot = UINT(it->binding());
6367 desc.AlignedByteOffset = it->offset();
6368 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6369 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6370 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6371 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6373 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6375 inputDescs.append(desc);
6379 stream.inputLayout.object.NumElements = inputDescs.count();
6380 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6382 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
6384 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
6385 topology = toD3DTopology(m_topology, m_patchControlPointCount);
6387 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6388 const int d3dStage = qd3d12_stage(shaderStage.type());
6391 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6392 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6395 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6396 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6399 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6400 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6403 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6404 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6407 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6408 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6416 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6417 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6418 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6419 stream.rasterizerState.object.DepthBias = m_depthBias;
6420 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6421 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
6422 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6424 stream.depthStencilState.object.DepthEnable = m_depthTest;
6425 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6426 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6427 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6428 if (m_stencilTest) {
6429 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6430 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6431 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6432 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6433 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6434 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6435 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6436 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6437 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6438 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6441 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6442 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6443 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6444 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6445 blend.BlendEnable = b.enable;
6446 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6447 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6448 blend.BlendOp = toD3DBlendOp(b.opColor);
6449 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6450 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6451 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6452 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6453 stream.blendState.object.RenderTarget[i] = blend;
6455 if (m_targetBlends.isEmpty()) {
6456 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6457 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6458 stream.blendState.object.RenderTarget[0] = blend;
6461 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6462 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6463 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6465 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6467 stream.sampleDesc.object = sampleDesc;
6469 stream.sampleMask.object = 0xFFFFFFFF;
6471 viewInstanceMask = 0;
6472 const bool isMultiView = m_multiViewCount >= 2;
6473 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6474 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6476 for (
int i = 0; i < m_multiViewCount; ++i) {
6477 viewInstanceMask |= (1 << i);
6478 viewInstanceLocations.append({ 0, UINT(i) });
6480 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6483 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6485 ID3D12PipelineState *pso =
nullptr;
6486 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6488 qWarning(
"Failed to create graphics pipeline state: %s",
6489 qPrintable(QSystemError::windowsComString(hr)));
6490 rhiD->rootSignaturePool.remove(rootSigHandle);
6495 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6497 rhiD->pipelineCreationEnd();
6499 rhiD->registerResource(
this);
6503QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6504 : QRhiComputePipeline(rhi)
6508QD3D12ComputePipeline::~QD3D12ComputePipeline()
6513void QD3D12ComputePipeline::destroy()
6515 if (handle.isNull())
6518 QRHI_RES_RHI(QRhiD3D12);
6520 rhiD->releaseQueue.deferredReleasePipeline(handle);
6521 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6528 rhiD->unregisterResource(
this);
6531bool QD3D12ComputePipeline::create()
6533 if (!handle.isNull())
6536 QRHI_RES_RHI(QRhiD3D12);
6537 rhiD->pipelineCreationStart();
6539 stageData.valid =
true;
6540 stageData.stage = CS;
6542 QByteArray shaderBytecode;
6543 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6544 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6545 shaderBytecode = cacheIt->bytecode;
6546 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6549 QShaderKey shaderKey;
6550 int compileFlags = 0;
6551 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6552 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6553 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6554 m_shaderStage.shaderVariant(),
6558 if (bytecode.isEmpty()) {
6559 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6563 shaderBytecode = bytecode;
6564 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6565 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6566 stageData.nativeResourceBindingMap });
6569 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6571 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6572 if (rootSigHandle.isNull()) {
6573 qWarning(
"Failed to create root signature");
6577 ID3D12RootSignature *rootSig =
nullptr;
6578 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6579 rootSig = rs->rootSig;
6581 qWarning(
"Cannot create compute pipeline state without root signature");
6586 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6587 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6589 stream.rootSig.object = rootSig;
6590 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6591 stream.CS.object.BytecodeLength = shaderBytecode.size();
6592 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6593 ID3D12PipelineState *pso =
nullptr;
6594 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6596 qWarning(
"Failed to create compute pipeline state: %s",
6597 qPrintable(QSystemError::windowsComString(hr)));
6598 rhiD->rootSignaturePool.remove(rootSigHandle);
6603 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6605 rhiD->pipelineCreationEnd();
6607 rhiD->registerResource(
this);
6614QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6615 : QRhiRenderPassDescriptor(rhi)
6617 serializedFormatData.reserve(16);
6620QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6625void QD3D12RenderPassDescriptor::destroy()
6627 QRHI_RES_RHI(QRhiD3D12);
6629 rhiD->unregisterResource(
this);
6632bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6637 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6639 if (colorAttachmentCount != o->colorAttachmentCount)
6642 if (hasDepthStencil != o->hasDepthStencil)
6645 for (
int i = 0; i < colorAttachmentCount; ++i) {
6646 if (colorFormat[i] != o->colorFormat[i])
6650 if (hasDepthStencil) {
6651 if (dsFormat != o->dsFormat)
6655 if (hasShadingRateMap != o->hasShadingRateMap)
6661void QD3D12RenderPassDescriptor::updateSerializedFormat()
6663 serializedFormatData.clear();
6664 auto p = std::back_inserter(serializedFormatData);
6666 *p++ = colorAttachmentCount;
6667 *p++ = hasDepthStencil;
6668 for (
int i = 0; i < colorAttachmentCount; ++i)
6669 *p++ = colorFormat[i];
6670 *p++ = hasDepthStencil ? dsFormat : 0;
6673QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6675 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6676 rpD->colorAttachmentCount = colorAttachmentCount;
6677 rpD->hasDepthStencil = hasDepthStencil;
6678 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6679 rpD->dsFormat = dsFormat;
6680 rpD->hasShadingRateMap = hasShadingRateMap;
6682 rpD->updateSerializedFormat();
6684 QRHI_RES_RHI(QRhiD3D12);
6685 rhiD->registerResource(rpD);
6689QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6691 return serializedFormatData;
6694QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6695 : QRhiCommandBuffer(rhi)
6700QD3D12CommandBuffer::~QD3D12CommandBuffer()
6705void QD3D12CommandBuffer::destroy()
6710const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6712 nativeHandlesStruct.commandList = cmdList;
6713 return &nativeHandlesStruct;
6716QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6717 : QRhiSwapChainRenderTarget(rhi, swapchain),
6722QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6727void QD3D12SwapChainRenderTarget::destroy()
6732QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6737float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6742int QD3D12SwapChainRenderTarget::sampleCount()
const
6744 return d.sampleCount;
6747QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6748 : QRhiSwapChain(rhi),
6749 rtWrapper(rhi,
this),
6750 rtWrapperRight(rhi,
this),
6755QD3D12SwapChain::~QD3D12SwapChain()
6760void QD3D12SwapChain::destroy()
6767 swapChain->Release();
6768 swapChain =
nullptr;
6769 sourceSwapChain1->Release();
6770 sourceSwapChain1 =
nullptr;
6772 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6773 FrameResources &fr(frameRes[i]);
6775 fr.fence->Release();
6777 CloseHandle(fr.fenceEvent);
6779 fr.cmdList->Release();
6784 dcompVisual->Release();
6785 dcompVisual =
nullptr;
6789 dcompTarget->Release();
6790 dcompTarget =
nullptr;
6793 if (frameLatencyWaitableObject) {
6794 CloseHandle(frameLatencyWaitableObject);
6795 frameLatencyWaitableObject =
nullptr;
6798 QDxgiVSyncService::instance()->unregisterWindow(window);
6800 QRHI_RES_RHI(QRhiD3D12);
6802 rhiD->swapchains.remove(
this);
6803 rhiD->unregisterResource(
this);
6807void QD3D12SwapChain::releaseBuffers()
6809 QRHI_RES_RHI(QRhiD3D12);
6811 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6812 rhiD->resourcePool.remove(colorBuffers[i]);
6813 rhiD->rtvPool.release(rtvs[i], 1);
6815 rhiD->rtvPool.release(rtvsRight[i], 1);
6816 if (!msaaBuffers[i].isNull())
6817 rhiD->resourcePool.remove(msaaBuffers[i]);
6818 if (msaaRtvs[i].isValid())
6819 rhiD->rtvPool.release(msaaRtvs[i], 1);
6823void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6825 FrameResources &fr(frameRes[frameSlot]);
6826 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6827 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6828 WaitForSingleObject(fr.fenceEvent, INFINITE);
6832void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6834 QRHI_RES_RHI(QRhiD3D12);
6835 FrameResources &fr(frameRes[currentFrameSlot]);
6836 fr.fenceCounter += 1u;
6837 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6840QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6845QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6850QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6852 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6855QSize QD3D12SwapChain::surfacePixelSize()
6858 return m_window->size() * m_window->devicePixelRatio();
6861bool QD3D12SwapChain::isFormatSupported(Format f)
6867 qWarning(
"Attempted to call isFormatSupported() without a window set");
6871 QRHI_RES_RHI(QRhiD3D12);
6872 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6873 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6878QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6880 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6883 QRHI_RES_RHI(QRhiD3D12);
6884 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6889QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6894 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6895 rpD->colorAttachmentCount = 1;
6896 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6897 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6898 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6900 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6902 rpD->updateSerializedFormat();
6904 QRHI_RES_RHI(QRhiD3D12);
6905 rhiD->registerResource(rpD);
6909bool QRhiD3D12::ensureDirectCompositionDevice()
6914 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6915 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6916 return dcompDevice ?
true :
false;
6919static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6920static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6922void QD3D12SwapChain::chooseFormats()
6924 colorFormat = DEFAULT_FORMAT;
6925 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6926 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6927 QRHI_RES_RHI(QRhiD3D12);
6928 if (m_format != SDR) {
6929 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6932 case HDRExtendedSrgbLinear:
6933 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6934 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6935 srgbAdjustedColorFormat = colorFormat;
6938 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6939 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6940 srgbAdjustedColorFormat = colorFormat;
6949 qWarning(
"The output associated with the window is not HDR capable "
6950 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6953 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6956bool QD3D12SwapChain::createOrResize()
6962 const bool needsRegistration = !window || window != m_window;
6965 if (window && window != m_window)
6969 m_currentPixelSize = surfacePixelSize();
6970 pixelSize = m_currentPixelSize;
6972 if (pixelSize.isEmpty())
6975 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6977 QRHI_RES_RHI(QRhiD3D12);
6978 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6980 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6981 if (rhiD->ensureDirectCompositionDevice()) {
6983 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6985 qWarning(
"Failed to create Direct Composition target for the window: %s",
6986 qPrintable(QSystemError::windowsComString(hr)));
6989 if (dcompTarget && !dcompVisual) {
6990 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
6992 qWarning(
"Failed to create DirectComposition visual: %s",
6993 qPrintable(QSystemError::windowsComString(hr)));
6998 if (window->requestedFormat().alphaBufferSize() <= 0)
6999 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
7000 "This may lead to problems.");
7003 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
7005 if (swapInterval == 0 && rhiD->supportsAllowTearing)
7006 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
7010 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
7011 && swapInterval != 0
7012 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
7013 if (useFrameLatencyWaitableObject)
7014 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
7019 DXGI_SWAP_CHAIN_DESC1 desc = {};
7020 desc.Width = UINT(pixelSize.width());
7021 desc.Height = UINT(pixelSize.height());
7022 desc.Format = colorFormat;
7023 desc.SampleDesc.Count = 1;
7024 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7025 desc.BufferCount = BUFFER_COUNT;
7026 desc.Flags = swapChainFlags;
7027 desc.Scaling = DXGI_SCALING_NONE;
7028 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7029 desc.Stereo = stereo;
7035 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
7040 desc.Scaling = DXGI_SCALING_STRETCH;
7044 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7046 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7051 if (FAILED(hr) && m_format != SDR) {
7052 colorFormat = DEFAULT_FORMAT;
7053 desc.Format = DEFAULT_FORMAT;
7055 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7057 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7060 if (SUCCEEDED(hr)) {
7061 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
7062 qWarning(
"IDXGISwapChain3 not available");
7065 if (m_format != SDR) {
7066 hr = swapChain->SetColorSpace1(hdrColorSpace);
7068 qWarning(
"Failed to set color space on swapchain: %s",
7069 qPrintable(QSystemError::windowsComString(hr)));
7072 if (useFrameLatencyWaitableObject) {
7073 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
7074 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
7077 hr = dcompVisual->SetContent(swapChain);
7078 if (SUCCEEDED(hr)) {
7079 hr = dcompTarget->SetRoot(dcompVisual);
7081 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
7082 qPrintable(QSystemError::windowsComString(hr)));
7085 qWarning(
"Failed to set content for Direct Composition visual: %s",
7086 qPrintable(QSystemError::windowsComString(hr)));
7090 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
7093 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7094 qWarning(
"Device loss detected during swapchain creation");
7095 rhiD->deviceLost =
true;
7097 }
else if (FAILED(hr)) {
7098 qWarning(
"Failed to create D3D12 swapchain: %s"
7099 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
7100 qPrintable(QSystemError::windowsComString(hr)),
7101 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
7102 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
7106 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7107 hr = rhiD->dev->CreateFence(0,
7108 D3D12_FENCE_FLAG_NONE,
7109 __uuidof(ID3D12Fence),
7110 reinterpret_cast<
void **>(&frameRes[i].fence));
7112 qWarning(
"Failed to create fence for swapchain: %s",
7113 qPrintable(QSystemError::windowsComString(hr)));
7116 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
7118 frameRes[i].fenceCounter = 0;
7122 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
7123 UINT(pixelSize.width()),
7124 UINT(pixelSize.height()),
7127 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7128 qWarning(
"Device loss detected in ResizeBuffers()");
7129 rhiD->deviceLost =
true;
7131 }
else if (FAILED(hr)) {
7132 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
7137 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7138 ID3D12Resource *colorBuffer;
7139 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
7141 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
7142 i, qPrintable(QSystemError::windowsComString(hr)));
7145 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
7146 rtvs[i] = rhiD->rtvPool.allocate(1);
7147 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7148 rtvDesc.Format = srgbAdjustedColorFormat;
7149 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
7150 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
7153 rtvsRight[i] = rhiD->rtvPool.allocate(1);
7154 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7155 rtvDesc.Format = srgbAdjustedColorFormat;
7156 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
7157 rtvDesc.Texture2DArray.ArraySize = 1;
7158 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7159 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7163 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7164 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7165 m_depthStencil->sampleCount(), m_sampleCount);
7167 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7168 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7169 m_depthStencil->setPixelSize(pixelSize);
7170 if (!m_depthStencil->create())
7171 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7172 pixelSize.width(), pixelSize.height());
7174 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7175 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7176 pixelSize.width(), pixelSize.height());
7180 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7182 if (sampleDesc.Count > 1) {
7183 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7184 D3D12_RESOURCE_DESC resourceDesc = {};
7185 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7186 resourceDesc.Width = UINT64(pixelSize.width());
7187 resourceDesc.Height = UINT(pixelSize.height());
7188 resourceDesc.DepthOrArraySize = 1;
7189 resourceDesc.MipLevels = 1;
7190 resourceDesc.Format = srgbAdjustedColorFormat;
7191 resourceDesc.SampleDesc = sampleDesc;
7192 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7193 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7194 D3D12_CLEAR_VALUE clearValue = {};
7195 clearValue.Format = colorFormat;
7196 ID3D12Resource *resource =
nullptr;
7197 D3D12MA::Allocation *allocation =
nullptr;
7198 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7200 D3D12_RESOURCE_STATE_RENDER_TARGET,
7203 __uuidof(ID3D12Resource),
7204 reinterpret_cast<
void **>(&resource));
7206 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7209 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7210 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7211 if (!msaaRtvs[i].isValid())
7213 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7214 rtvDesc.Format = srgbAdjustedColorFormat;
7215 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7216 : D3D12_RTV_DIMENSION_TEXTURE2D;
7217 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7221 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7222 currentFrameSlot = 0;
7223 lastFrameLatencyWaitSlot = -1;
7225 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7226 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7227 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7228 rtD->d.pixelSize = pixelSize;
7229 rtD->d.dpr =
float(window->devicePixelRatio());
7230 rtD->d.sampleCount =
int(sampleDesc.Count);
7231 rtD->d.colorAttCount = 1;
7232 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7234 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7235 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7236 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7237 rtDr->d.pixelSize = pixelSize;
7238 rtDr->d.dpr =
float(window->devicePixelRatio());
7239 rtDr->d.sampleCount =
int(sampleDesc.Count);
7240 rtDr->d.colorAttCount = 1;
7241 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7243 QDxgiVSyncService::instance()->registerWindow(window);
7245 if (needsRegistration || !rhiD->swapchains.contains(
this))
7246 rhiD->swapchains.insert(
this);
7248 rhiD->registerResource(
this);